Add performance counter metrics to build.trace.gz
Start a background goroutine at the beginning of soong_build that
captures the CPU usage, heap size, and total system memory every
second. Propagate the values through soong_build_metrics.pb back
to soong_ui, and then into build.trace.gz.
Test: m nothing, examine build.trace.gz
Change-Id: Iad99f8f1f088f4f7f7d5f76566a38c0c4f4d0daa
diff --git a/ui/tracer/tracer.go b/ui/tracer/tracer.go
index b8fc87b..33b3d89 100644
--- a/ui/tracer/tracer.go
+++ b/ui/tracer/tracer.go
@@ -46,6 +46,8 @@
End(thread Thread)
Complete(name string, thread Thread, begin, end uint64)
+ CountersAtTime(name string, thread Thread, time uint64, counters []Counter)
+
ImportMicrofactoryLog(filename string)
StatusTracer() status.StatusOutput
@@ -247,3 +249,48 @@
Tid: uint64(thread),
})
}
+
+type Counter struct {
+ Name string
+ Value int64
+}
+
+type countersMarshaller []Counter
+
+var _ json.Marshaler = countersMarshaller(nil)
+
+func (counters countersMarshaller) MarshalJSON() ([]byte, error) {
+ // This produces similar output to a map[string]int64, but maintains the order of the slice.
+ buf := bytes.Buffer{}
+ buf.WriteRune('{')
+ for i, counter := range counters {
+ name, err := json.Marshal(counter.Name)
+ if err != nil {
+ return nil, err
+ }
+ buf.Write(name)
+ buf.WriteByte(':')
+ value, err := json.Marshal(counter.Value)
+ if err != nil {
+ return nil, err
+ }
+ buf.Write(value)
+ if i != len(counters)-1 {
+ buf.WriteRune(',')
+ }
+ }
+ buf.WriteRune('}')
+ return buf.Bytes(), nil
+}
+
+// CountersAtTime writes a Counter event at the given timestamp in nanoseconds.
+func (t *tracerImpl) CountersAtTime(name string, thread Thread, time uint64, counters []Counter) {
+ t.writeEvent(&viewerEvent{
+ Name: name,
+ Phase: "C",
+ Time: time / 1000,
+ Pid: 0,
+ Tid: uint64(thread),
+ Arg: countersMarshaller(counters),
+ })
+}