1*333d2b36SAndroid Build Coastguard Worker// Copyright 2018 Google Inc. All Rights Reserved. 2*333d2b36SAndroid Build Coastguard Worker// 3*333d2b36SAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*333d2b36SAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*333d2b36SAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*333d2b36SAndroid Build Coastguard Worker// 7*333d2b36SAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*333d2b36SAndroid Build Coastguard Worker// 9*333d2b36SAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*333d2b36SAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*333d2b36SAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*333d2b36SAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*333d2b36SAndroid Build Coastguard Worker// limitations under the License. 14*333d2b36SAndroid Build Coastguard Worker 15*333d2b36SAndroid Build Coastguard Workerpackage metrics 16*333d2b36SAndroid Build Coastguard Worker 17*333d2b36SAndroid Build Coastguard Worker// This file contains the functionality to represent a build event in respect 18*333d2b36SAndroid Build Coastguard Worker// to the metric system. A build event corresponds to a block of scoped code 19*333d2b36SAndroid Build Coastguard Worker// that contains a "Begin()" and immediately followed by "defer End()" trace. 20*333d2b36SAndroid Build Coastguard Worker// When defined, the duration of the scoped code is measure along with other 21*333d2b36SAndroid Build Coastguard Worker// performance measurements such as memory. 22*333d2b36SAndroid Build Coastguard Worker// 23*333d2b36SAndroid Build Coastguard Worker// As explained in the metrics package, the metrics system is a stacked based 24*333d2b36SAndroid Build Coastguard Worker// system since the collected metrics is considered to be topline metrics. 25*333d2b36SAndroid Build Coastguard Worker// The steps of the build system in the UI layer is sequential. Hence, the 26*333d2b36SAndroid Build Coastguard Worker// functionality defined below follows the stack data structure operations. 27*333d2b36SAndroid Build Coastguard Worker 28*333d2b36SAndroid Build Coastguard Workerimport ( 29*333d2b36SAndroid Build Coastguard Worker "os" 30*333d2b36SAndroid Build Coastguard Worker "syscall" 31*333d2b36SAndroid Build Coastguard Worker "time" 32*333d2b36SAndroid Build Coastguard Worker 33*333d2b36SAndroid Build Coastguard Worker soong_metrics_proto "android/soong/ui/metrics/metrics_proto" 34*333d2b36SAndroid Build Coastguard Worker 35*333d2b36SAndroid Build Coastguard Worker "google.golang.org/protobuf/proto" 36*333d2b36SAndroid Build Coastguard Worker) 37*333d2b36SAndroid Build Coastguard Worker 38*333d2b36SAndroid Build Coastguard Worker// _now wraps the time.Now() function. _now is declared for unit testing purpose. 39*333d2b36SAndroid Build Coastguard Workervar _now = func() time.Time { 40*333d2b36SAndroid Build Coastguard Worker return time.Now() 41*333d2b36SAndroid Build Coastguard Worker} 42*333d2b36SAndroid Build Coastguard Worker 43*333d2b36SAndroid Build Coastguard Worker// event holds the performance metrics data of a single build event. 44*333d2b36SAndroid Build Coastguard Workertype event struct { 45*333d2b36SAndroid Build Coastguard Worker // The event name (mostly used for grouping a set of events) 46*333d2b36SAndroid Build Coastguard Worker name string 47*333d2b36SAndroid Build Coastguard Worker 48*333d2b36SAndroid Build Coastguard Worker // The description of the event (used to uniquely identify an event 49*333d2b36SAndroid Build Coastguard Worker // for metrics analysis). 50*333d2b36SAndroid Build Coastguard Worker desc string 51*333d2b36SAndroid Build Coastguard Worker 52*333d2b36SAndroid Build Coastguard Worker nonZeroExitCode bool 53*333d2b36SAndroid Build Coastguard Worker 54*333d2b36SAndroid Build Coastguard Worker errorMsg *string 55*333d2b36SAndroid Build Coastguard Worker 56*333d2b36SAndroid Build Coastguard Worker // The time that the event started to occur. 57*333d2b36SAndroid Build Coastguard Worker start time.Time 58*333d2b36SAndroid Build Coastguard Worker 59*333d2b36SAndroid Build Coastguard Worker // The list of process resource information that was executed. 60*333d2b36SAndroid Build Coastguard Worker procResInfo []*soong_metrics_proto.ProcessResourceInfo 61*333d2b36SAndroid Build Coastguard Worker} 62*333d2b36SAndroid Build Coastguard Worker 63*333d2b36SAndroid Build Coastguard Worker// newEvent returns an event with start populated with the now time. 64*333d2b36SAndroid Build Coastguard Workerfunc newEvent(name, desc string) *event { 65*333d2b36SAndroid Build Coastguard Worker return &event{ 66*333d2b36SAndroid Build Coastguard Worker name: name, 67*333d2b36SAndroid Build Coastguard Worker desc: desc, 68*333d2b36SAndroid Build Coastguard Worker start: _now(), 69*333d2b36SAndroid Build Coastguard Worker } 70*333d2b36SAndroid Build Coastguard Worker} 71*333d2b36SAndroid Build Coastguard Worker 72*333d2b36SAndroid Build Coastguard Workerfunc (e event) perfInfo() soong_metrics_proto.PerfInfo { 73*333d2b36SAndroid Build Coastguard Worker realTime := uint64(_now().Sub(e.start).Nanoseconds()) 74*333d2b36SAndroid Build Coastguard Worker perfInfo := soong_metrics_proto.PerfInfo{ 75*333d2b36SAndroid Build Coastguard Worker Description: proto.String(e.desc), 76*333d2b36SAndroid Build Coastguard Worker Name: proto.String(e.name), 77*333d2b36SAndroid Build Coastguard Worker StartTime: proto.Uint64(uint64(e.start.UnixNano())), 78*333d2b36SAndroid Build Coastguard Worker RealTime: proto.Uint64(realTime), 79*333d2b36SAndroid Build Coastguard Worker ProcessesResourceInfo: e.procResInfo, 80*333d2b36SAndroid Build Coastguard Worker NonZeroExit: proto.Bool(e.nonZeroExitCode), 81*333d2b36SAndroid Build Coastguard Worker } 82*333d2b36SAndroid Build Coastguard Worker if m := e.errorMsg; m != nil { 83*333d2b36SAndroid Build Coastguard Worker perfInfo.ErrorMessage = proto.String(*m) 84*333d2b36SAndroid Build Coastguard Worker } 85*333d2b36SAndroid Build Coastguard Worker return perfInfo 86*333d2b36SAndroid Build Coastguard Worker} 87*333d2b36SAndroid Build Coastguard Worker 88*333d2b36SAndroid Build Coastguard Worker// EventTracer is an array of events that provides functionality to trace a 89*333d2b36SAndroid Build Coastguard Worker// block of code on time and performance. The End call expects the Begin is 90*333d2b36SAndroid Build Coastguard Worker// invoked, otherwise panic is raised. 91*333d2b36SAndroid Build Coastguard Workertype EventTracer []*event 92*333d2b36SAndroid Build Coastguard Worker 93*333d2b36SAndroid Build Coastguard Worker// empty returns true if there are no pending events. 94*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) empty() bool { 95*333d2b36SAndroid Build Coastguard Worker return len(*t) == 0 96*333d2b36SAndroid Build Coastguard Worker} 97*333d2b36SAndroid Build Coastguard Worker 98*333d2b36SAndroid Build Coastguard Worker// lastIndex returns the index of the last element of events. 99*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) lastIndex() int { 100*333d2b36SAndroid Build Coastguard Worker return len(*t) - 1 101*333d2b36SAndroid Build Coastguard Worker} 102*333d2b36SAndroid Build Coastguard Worker 103*333d2b36SAndroid Build Coastguard Worker// peek returns the active build event. 104*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) peek() *event { 105*333d2b36SAndroid Build Coastguard Worker if t.empty() { 106*333d2b36SAndroid Build Coastguard Worker return nil 107*333d2b36SAndroid Build Coastguard Worker } 108*333d2b36SAndroid Build Coastguard Worker return (*t)[t.lastIndex()] 109*333d2b36SAndroid Build Coastguard Worker} 110*333d2b36SAndroid Build Coastguard Worker 111*333d2b36SAndroid Build Coastguard Worker// push adds the active build event in the stack. 112*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) push(e *event) { 113*333d2b36SAndroid Build Coastguard Worker *t = append(*t, e) 114*333d2b36SAndroid Build Coastguard Worker} 115*333d2b36SAndroid Build Coastguard Worker 116*333d2b36SAndroid Build Coastguard Worker// pop removes the active event from the stack since the event has completed. 117*333d2b36SAndroid Build Coastguard Worker// A panic is raised if there are no pending events. 118*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) pop() *event { 119*333d2b36SAndroid Build Coastguard Worker if t.empty() { 120*333d2b36SAndroid Build Coastguard Worker panic("Internal error: No pending events") 121*333d2b36SAndroid Build Coastguard Worker } 122*333d2b36SAndroid Build Coastguard Worker e := (*t)[t.lastIndex()] 123*333d2b36SAndroid Build Coastguard Worker *t = (*t)[:t.lastIndex()] 124*333d2b36SAndroid Build Coastguard Worker return e 125*333d2b36SAndroid Build Coastguard Worker} 126*333d2b36SAndroid Build Coastguard Worker 127*333d2b36SAndroid Build Coastguard Worker// AddProcResInfo adds information on an executed process such as max resident 128*333d2b36SAndroid Build Coastguard Worker// set memory and the number of voluntary context switches. 129*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) AddProcResInfo(name string, state *os.ProcessState) { 130*333d2b36SAndroid Build Coastguard Worker if t.empty() { 131*333d2b36SAndroid Build Coastguard Worker return 132*333d2b36SAndroid Build Coastguard Worker } 133*333d2b36SAndroid Build Coastguard Worker 134*333d2b36SAndroid Build Coastguard Worker rusage := state.SysUsage().(*syscall.Rusage) 135*333d2b36SAndroid Build Coastguard Worker e := t.peek() 136*333d2b36SAndroid Build Coastguard Worker e.procResInfo = append(e.procResInfo, &soong_metrics_proto.ProcessResourceInfo{ 137*333d2b36SAndroid Build Coastguard Worker Name: proto.String(name), 138*333d2b36SAndroid Build Coastguard Worker UserTimeMicros: proto.Uint64(uint64(state.UserTime().Microseconds())), 139*333d2b36SAndroid Build Coastguard Worker SystemTimeMicros: proto.Uint64(uint64(state.SystemTime().Microseconds())), 140*333d2b36SAndroid Build Coastguard Worker MinorPageFaults: proto.Uint64(uint64(rusage.Minflt)), 141*333d2b36SAndroid Build Coastguard Worker MajorPageFaults: proto.Uint64(uint64(rusage.Majflt)), 142*333d2b36SAndroid Build Coastguard Worker // ru_inblock and ru_oublock are measured in blocks of 512 bytes. 143*333d2b36SAndroid Build Coastguard Worker IoInputKb: proto.Uint64(uint64(rusage.Inblock / 2)), 144*333d2b36SAndroid Build Coastguard Worker IoOutputKb: proto.Uint64(uint64(rusage.Oublock / 2)), 145*333d2b36SAndroid Build Coastguard Worker VoluntaryContextSwitches: proto.Uint64(uint64(rusage.Nvcsw)), 146*333d2b36SAndroid Build Coastguard Worker InvoluntaryContextSwitches: proto.Uint64(uint64(rusage.Nivcsw)), 147*333d2b36SAndroid Build Coastguard Worker }) 148*333d2b36SAndroid Build Coastguard Worker} 149*333d2b36SAndroid Build Coastguard Worker 150*333d2b36SAndroid Build Coastguard Worker// Begin starts tracing the event. 151*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) Begin(name, desc string) { 152*333d2b36SAndroid Build Coastguard Worker t.push(newEvent(name, desc)) 153*333d2b36SAndroid Build Coastguard Worker} 154*333d2b36SAndroid Build Coastguard Worker 155*333d2b36SAndroid Build Coastguard Worker// End performs post calculations such as duration of the event, aggregates 156*333d2b36SAndroid Build Coastguard Worker// the collected performance information into PerfInfo protobuf message. 157*333d2b36SAndroid Build Coastguard Workerfunc (t *EventTracer) End() soong_metrics_proto.PerfInfo { 158*333d2b36SAndroid Build Coastguard Worker return t.pop().perfInfo() 159*333d2b36SAndroid Build Coastguard Worker} 160