1// Copyright 2018 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package metrics 16 17import ( 18 "io/ioutil" 19 "os" 20 "time" 21 22 "github.com/golang/protobuf/proto" 23 24 soong_metrics_proto "android/soong/ui/metrics/metrics_proto" 25) 26 27const ( 28 PrimaryNinja = "ninja" 29 RunKati = "kati" 30 RunSetupTool = "setup" 31 RunShutdownTool = "shutdown" 32 RunSoong = "soong" 33 TestRun = "test" 34 Total = "total" 35) 36 37type Metrics struct { 38 metrics soong_metrics_proto.MetricsBase 39 TimeTracer TimeTracer 40} 41 42func New() (metrics *Metrics) { 43 m := &Metrics{ 44 metrics: soong_metrics_proto.MetricsBase{}, 45 TimeTracer: &timeTracerImpl{}, 46 } 47 return m 48} 49 50func (m *Metrics) SetTimeMetrics(perf soong_metrics_proto.PerfInfo) { 51 switch perf.GetName() { 52 case RunKati: 53 m.metrics.KatiRuns = append(m.metrics.KatiRuns, &perf) 54 break 55 case RunSoong: 56 m.metrics.SoongRuns = append(m.metrics.SoongRuns, &perf) 57 break 58 case PrimaryNinja: 59 m.metrics.NinjaRuns = append(m.metrics.NinjaRuns, &perf) 60 break 61 case Total: 62 m.metrics.Total = &perf 63 default: 64 // ignored 65 } 66} 67 68func (m *Metrics) SetMetadataMetrics(metadata map[string]string) { 69 for k, v := range metadata { 70 switch k { 71 case "BUILD_ID": 72 m.metrics.BuildId = proto.String(v) 73 break 74 case "PLATFORM_VERSION_CODENAME": 75 m.metrics.PlatformVersionCodename = proto.String(v) 76 break 77 case "TARGET_PRODUCT": 78 m.metrics.TargetProduct = proto.String(v) 79 break 80 case "TARGET_BUILD_VARIANT": 81 switch v { 82 case "user": 83 m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_USER.Enum() 84 case "userdebug": 85 m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_USERDEBUG.Enum() 86 case "eng": 87 m.metrics.TargetBuildVariant = soong_metrics_proto.MetricsBase_ENG.Enum() 88 default: 89 // ignored 90 } 91 case "TARGET_ARCH": 92 m.metrics.TargetArch = m.getArch(v) 93 case "TARGET_ARCH_VARIANT": 94 m.metrics.TargetArchVariant = proto.String(v) 95 case "TARGET_CPU_VARIANT": 96 m.metrics.TargetCpuVariant = proto.String(v) 97 case "HOST_ARCH": 98 m.metrics.HostArch = m.getArch(v) 99 case "HOST_2ND_ARCH": 100 m.metrics.Host_2NdArch = m.getArch(v) 101 case "HOST_OS": 102 m.metrics.HostOs = proto.String(v) 103 case "HOST_OS_EXTRA": 104 m.metrics.HostOsExtra = proto.String(v) 105 case "HOST_CROSS_OS": 106 m.metrics.HostCrossOs = proto.String(v) 107 case "HOST_CROSS_ARCH": 108 m.metrics.HostCrossArch = proto.String(v) 109 case "HOST_CROSS_2ND_ARCH": 110 m.metrics.HostCross_2NdArch = proto.String(v) 111 case "OUT_DIR": 112 m.metrics.OutDir = proto.String(v) 113 default: 114 // ignored 115 } 116 } 117} 118 119func (m *Metrics) getArch(arch string) *soong_metrics_proto.MetricsBase_Arch { 120 switch arch { 121 case "arm": 122 return soong_metrics_proto.MetricsBase_ARM.Enum() 123 case "arm64": 124 return soong_metrics_proto.MetricsBase_ARM64.Enum() 125 case "x86": 126 return soong_metrics_proto.MetricsBase_X86.Enum() 127 case "x86_64": 128 return soong_metrics_proto.MetricsBase_X86_64.Enum() 129 default: 130 return soong_metrics_proto.MetricsBase_UNKNOWN.Enum() 131 } 132} 133 134func (m *Metrics) SetBuildDateTime(buildTimestamp time.Time) { 135 m.metrics.BuildDateTimestamp = proto.Int64(buildTimestamp.UnixNano() / int64(time.Second)) 136} 137 138// exports the output to the file at outputPath 139func (m *Metrics) Dump(outputPath string) (err error) { 140 return writeMessageToFile(&m.metrics, outputPath) 141} 142 143func (m *Metrics) SetSoongBuildMetrics(metrics *soong_metrics_proto.SoongBuildMetrics) { 144 m.metrics.SoongBuildMetrics = metrics 145} 146 147type CriticalUserJourneysMetrics struct { 148 cujs soong_metrics_proto.CriticalUserJourneysMetrics 149} 150 151func NewCriticalUserJourneysMetrics() *CriticalUserJourneysMetrics { 152 return &CriticalUserJourneysMetrics{} 153} 154 155func (c *CriticalUserJourneysMetrics) Add(name string, metrics *Metrics) { 156 c.cujs.Cujs = append(c.cujs.Cujs, &soong_metrics_proto.CriticalUserJourneyMetrics{ 157 Name: proto.String(name), 158 Metrics: &metrics.metrics, 159 }) 160} 161 162func (c *CriticalUserJourneysMetrics) Dump(outputPath string) (err error) { 163 return writeMessageToFile(&c.cujs, outputPath) 164} 165 166func writeMessageToFile(pb proto.Message, outputPath string) (err error) { 167 data, err := proto.Marshal(pb) 168 if err != nil { 169 return err 170 } 171 tempPath := outputPath + ".tmp" 172 err = ioutil.WriteFile(tempPath, []byte(data), 0644) 173 if err != nil { 174 return err 175 } 176 err = os.Rename(tempPath, outputPath) 177 if err != nil { 178 return err 179 } 180 181 return nil 182} 183