1// Copyright 2020 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 android 16 17import ( 18 "io/ioutil" 19 "runtime" 20 "sort" 21 22 "github.com/google/blueprint/metrics" 23 "google.golang.org/protobuf/proto" 24 25 soong_metrics_proto "android/soong/ui/metrics/metrics_proto" 26) 27 28var soongMetricsOnceKey = NewOnceKey("soong metrics") 29 30type SoongMetrics struct { 31 Modules int 32 Variants int 33} 34 35func readSoongMetrics(config Config) (SoongMetrics, bool) { 36 soongMetrics, ok := config.Peek(soongMetricsOnceKey) 37 if ok { 38 return soongMetrics.(SoongMetrics), true 39 } else { 40 return SoongMetrics{}, false 41 } 42} 43 44func init() { 45 RegisterSingletonType("soong_metrics", soongMetricsSingletonFactory) 46} 47 48func soongMetricsSingletonFactory() Singleton { return soongMetricsSingleton{} } 49 50type soongMetricsSingleton struct{} 51 52func (soongMetricsSingleton) GenerateBuildActions(ctx SingletonContext) { 53 metrics := SoongMetrics{} 54 ctx.VisitAllModules(func(m Module) { 55 if ctx.PrimaryModule(m) == m { 56 metrics.Modules++ 57 } 58 metrics.Variants++ 59 }) 60 ctx.Config().Once(soongMetricsOnceKey, func() interface{} { 61 return metrics 62 }) 63} 64 65func collectMetrics(config Config, eventHandler *metrics.EventHandler) *soong_metrics_proto.SoongBuildMetrics { 66 metrics := &soong_metrics_proto.SoongBuildMetrics{} 67 68 soongMetrics, ok := readSoongMetrics(config) 69 if ok { 70 metrics.Modules = proto.Uint32(uint32(soongMetrics.Modules)) 71 metrics.Variants = proto.Uint32(uint32(soongMetrics.Variants)) 72 } 73 74 memStats := runtime.MemStats{} 75 runtime.ReadMemStats(&memStats) 76 metrics.MaxHeapSize = proto.Uint64(memStats.HeapSys) 77 metrics.TotalAllocCount = proto.Uint64(memStats.Mallocs) 78 metrics.TotalAllocSize = proto.Uint64(memStats.TotalAlloc) 79 80 for _, event := range eventHandler.CompletedEvents() { 81 perfInfo := soong_metrics_proto.PerfInfo{ 82 Description: proto.String(event.Id), 83 Name: proto.String("soong_build"), 84 StartTime: proto.Uint64(uint64(event.Start.UnixNano())), 85 RealTime: proto.Uint64(event.RuntimeNanoseconds()), 86 } 87 metrics.Events = append(metrics.Events, &perfInfo) 88 } 89 mixedBuildsInfo := soong_metrics_proto.MixedBuildsInfo{} 90 mixedBuildEnabledModules := make([]string, 0, len(config.mixedBuildEnabledModules)) 91 for module, _ := range config.mixedBuildEnabledModules { 92 mixedBuildEnabledModules = append(mixedBuildEnabledModules, module) 93 } 94 95 mixedBuildDisabledModules := make([]string, 0, len(config.mixedBuildDisabledModules)) 96 for module, _ := range config.mixedBuildDisabledModules { 97 mixedBuildDisabledModules = append(mixedBuildDisabledModules, module) 98 } 99 // Sorted for deterministic output. 100 sort.Strings(mixedBuildEnabledModules) 101 sort.Strings(mixedBuildDisabledModules) 102 103 mixedBuildsInfo.MixedBuildEnabledModules = mixedBuildEnabledModules 104 mixedBuildsInfo.MixedBuildDisabledModules = mixedBuildDisabledModules 105 metrics.MixedBuildsInfo = &mixedBuildsInfo 106 107 return metrics 108} 109 110func WriteMetrics(config Config, eventHandler *metrics.EventHandler, metricsFile string) error { 111 metrics := collectMetrics(config, eventHandler) 112 113 buf, err := proto.Marshal(metrics) 114 if err != nil { 115 return err 116 } 117 err = ioutil.WriteFile(absolutePath(metricsFile), buf, 0666) 118 if err != nil { 119 return err 120 } 121 122 return nil 123} 124