Log bp2build_metrics .pb
Also share `Save(pb proto.Message, filepath string)` Bug: 201539536 Test: bp2build_metrics.pb has expected content & path Test: m nothing Test: {bp2build,mixed_{libc,droid}}.sh Test: CI Change-Id: I7d8ad87fca6a4b0355010090a527f5ae67b27c88
This commit is contained in:
parent
484aa25875
commit
947fdbfdee
10 changed files with 136 additions and 34 deletions
|
@ -19,6 +19,7 @@ bootstrap_go_package {
|
||||||
deps: [
|
deps: [
|
||||||
"soong-android",
|
"soong-android",
|
||||||
"soong-android-soongconfig",
|
"soong-android-soongconfig",
|
||||||
|
"soong-shared",
|
||||||
"soong-apex",
|
"soong-apex",
|
||||||
"soong-bazel",
|
"soong-bazel",
|
||||||
"soong-cc",
|
"soong-cc",
|
||||||
|
@ -27,6 +28,7 @@ bootstrap_go_package {
|
||||||
"soong-genrule",
|
"soong-genrule",
|
||||||
"soong-python",
|
"soong-python",
|
||||||
"soong-sh",
|
"soong-sh",
|
||||||
|
"soong-ui-metrics",
|
||||||
],
|
],
|
||||||
testSrcs: [
|
testSrcs: [
|
||||||
"android_app_certificate_conversion_test.go",
|
"android_app_certificate_conversion_test.go",
|
||||||
|
|
|
@ -259,7 +259,7 @@ func GenerateBazelTargets(ctx *CodegenContext, generateFilegroups bool) (convers
|
||||||
|
|
||||||
// Simple metrics tracking for bp2build
|
// Simple metrics tracking for bp2build
|
||||||
metrics := CodegenMetrics{
|
metrics := CodegenMetrics{
|
||||||
ruleClassCount: make(map[string]int),
|
ruleClassCount: make(map[string]uint64),
|
||||||
}
|
}
|
||||||
|
|
||||||
dirs := make(map[string]bool)
|
dirs := make(map[string]bool)
|
||||||
|
|
|
@ -2,34 +2,52 @@ package bp2build
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"android/soong/android"
|
"android/soong/android"
|
||||||
|
"android/soong/shared"
|
||||||
|
"android/soong/ui/metrics/bp2build_metrics_proto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Simple metrics struct to collect information about a Blueprint to BUILD
|
// Simple metrics struct to collect information about a Blueprint to BUILD
|
||||||
// conversion process.
|
// conversion process.
|
||||||
type CodegenMetrics struct {
|
type CodegenMetrics struct {
|
||||||
// Total number of Soong modules converted to generated targets
|
// Total number of Soong modules converted to generated targets
|
||||||
generatedModuleCount int
|
generatedModuleCount uint64
|
||||||
|
|
||||||
// Total number of Soong modules converted to handcrafted targets
|
// Total number of Soong modules converted to handcrafted targets
|
||||||
handCraftedModuleCount int
|
handCraftedModuleCount uint64
|
||||||
|
|
||||||
// Total number of unconverted Soong modules
|
// Total number of unconverted Soong modules
|
||||||
unconvertedModuleCount int
|
unconvertedModuleCount uint64
|
||||||
|
|
||||||
// Counts of generated Bazel targets per Bazel rule class
|
// Counts of generated Bazel targets per Bazel rule class
|
||||||
ruleClassCount map[string]int
|
ruleClassCount map[string]uint64
|
||||||
|
|
||||||
|
// List of modules with unconverted deps
|
||||||
|
// NOTE: NOT in the .proto
|
||||||
moduleWithUnconvertedDepsMsgs []string
|
moduleWithUnconvertedDepsMsgs []string
|
||||||
|
|
||||||
|
// List of converted modules
|
||||||
convertedModules []string
|
convertedModules []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
|
||||||
|
func (metrics *CodegenMetrics) Serialize() bp2build_metrics_proto.Bp2BuildMetrics {
|
||||||
|
return bp2build_metrics_proto.Bp2BuildMetrics{
|
||||||
|
GeneratedModuleCount: metrics.generatedModuleCount,
|
||||||
|
HandCraftedModuleCount: metrics.handCraftedModuleCount,
|
||||||
|
UnconvertedModuleCount: metrics.unconvertedModuleCount,
|
||||||
|
RuleClassCount: metrics.ruleClassCount,
|
||||||
|
ConvertedModules: metrics.convertedModules,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Print the codegen metrics to stdout.
|
// Print the codegen metrics to stdout.
|
||||||
func (metrics *CodegenMetrics) Print() {
|
func (metrics *CodegenMetrics) Print() {
|
||||||
generatedTargetCount := 0
|
generatedTargetCount := uint64(0)
|
||||||
for _, ruleClass := range android.SortedStringKeys(metrics.ruleClassCount) {
|
for _, ruleClass := range android.SortedStringKeys(metrics.ruleClassCount) {
|
||||||
count := metrics.ruleClassCount[ruleClass]
|
count := metrics.ruleClassCount[ruleClass]
|
||||||
fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
|
fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
|
||||||
|
@ -45,6 +63,40 @@ func (metrics *CodegenMetrics) Print() {
|
||||||
strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"))
|
strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bp2buildMetricsFilename = "bp2build_metrics.pb"
|
||||||
|
|
||||||
|
// fail prints $PWD to stderr, followed by the given printf string and args (vals),
|
||||||
|
// then the given alert, and then exits with 1 for failure
|
||||||
|
func fail(err error, alertFmt string, vals ...interface{}) {
|
||||||
|
cwd, wderr := os.Getwd()
|
||||||
|
if wderr != nil {
|
||||||
|
cwd = "FAILED TO GET $PWD: " + wderr.Error()
|
||||||
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "\nIn "+cwd+":\n"+alertFmt+"\n"+err.Error()+"\n", vals...)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the bp2build-protoized codegen metrics into the given directory
|
||||||
|
func (metrics *CodegenMetrics) Write(dir string) {
|
||||||
|
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||||
|
// The metrics dir doesn't already exist, so create it (and parents)
|
||||||
|
if err := os.MkdirAll(dir, 0755); err != nil { // rx for all; w for user
|
||||||
|
fail(err, "Failed to `mkdir -p` %s", dir)
|
||||||
|
}
|
||||||
|
} else if err != nil {
|
||||||
|
fail(err, "Failed to `stat` %s", dir)
|
||||||
|
}
|
||||||
|
metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
|
||||||
|
if err := metrics.dump(metricsFile); err != nil {
|
||||||
|
fail(err, "Error outputting %s", metricsFile)
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(metricsFile); err != nil {
|
||||||
|
fail(err, "MISSING BP2BUILD METRICS OUTPUT: Failed to `stat` %s", metricsFile)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("\nWrote bp2build metrics to: %s\n", metricsFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
|
func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
|
||||||
metrics.ruleClassCount[ruleClass] += 1
|
metrics.ruleClassCount[ruleClass] += 1
|
||||||
}
|
}
|
||||||
|
@ -53,12 +105,18 @@ func (metrics *CodegenMetrics) IncrementUnconvertedCount() {
|
||||||
metrics.unconvertedModuleCount += 1
|
metrics.unconvertedModuleCount += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
func (metrics *CodegenMetrics) TotalModuleCount() int {
|
func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
|
||||||
return metrics.handCraftedModuleCount +
|
return metrics.handCraftedModuleCount +
|
||||||
metrics.generatedModuleCount +
|
metrics.generatedModuleCount +
|
||||||
metrics.unconvertedModuleCount
|
metrics.unconvertedModuleCount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Dump serializes the metrics to the given filename
|
||||||
|
func (metrics *CodegenMetrics) dump(filename string) (err error) {
|
||||||
|
ser := metrics.Serialize()
|
||||||
|
return shared.Save(&ser, filename)
|
||||||
|
}
|
||||||
|
|
||||||
type ConversionType int
|
type ConversionType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -537,6 +537,7 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
|
||||||
// for queryview, since that's a total repo-wide conversion and there's a
|
// for queryview, since that's a total repo-wide conversion and there's a
|
||||||
// 1:1 mapping for each module.
|
// 1:1 mapping for each module.
|
||||||
metrics.Print()
|
metrics.Print()
|
||||||
|
writeBp2BuildMetrics(&metrics, configuration)
|
||||||
|
|
||||||
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
|
ninjaDeps = append(ninjaDeps, codegenContext.AdditionalNinjaDeps()...)
|
||||||
ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
|
ninjaDeps = append(ninjaDeps, symlinkForestDeps...)
|
||||||
|
@ -546,3 +547,13 @@ func runBp2Build(configuration android.Config, extraNinjaDeps []string) {
|
||||||
// Create an empty bp2build marker file.
|
// Create an empty bp2build marker file.
|
||||||
touch(shared.JoinPath(topDir, bp2buildMarker))
|
touch(shared.JoinPath(topDir, bp2buildMarker))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write Bp2Build metrics into $LOG_DIR
|
||||||
|
func writeBp2BuildMetrics(metrics *bp2build.CodegenMetrics, configuration android.Config) {
|
||||||
|
metricsDir := configuration.Getenv("LOG_DIR")
|
||||||
|
if len(metricsDir) < 1 {
|
||||||
|
fmt.Fprintf(os.Stderr, "\nMissing required env var for generating bp2build metrics: LOG_DIR\n")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
metrics.Write(metricsDir)
|
||||||
|
}
|
||||||
|
|
|
@ -9,11 +9,13 @@ bootstrap_go_package {
|
||||||
"env.go",
|
"env.go",
|
||||||
"paths.go",
|
"paths.go",
|
||||||
"debug.go",
|
"debug.go",
|
||||||
|
"proto.go",
|
||||||
],
|
],
|
||||||
testSrcs: [
|
testSrcs: [
|
||||||
"paths_test.go",
|
"paths_test.go",
|
||||||
],
|
],
|
||||||
deps: [
|
deps: [
|
||||||
"soong-bazel",
|
"soong-bazel",
|
||||||
|
"golang-protobuf-proto",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
41
shared/proto.go
Normal file
41
shared/proto.go
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2021 Google Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package shared
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"google.golang.org/protobuf/proto"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Save takes a protobuf message, marshals to an array of bytes
|
||||||
|
// and is then saved to a file.
|
||||||
|
func Save(pb proto.Message, filepath string) (err error) {
|
||||||
|
data, err := proto.Marshal(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tempFilepath := filepath + ".tmp"
|
||||||
|
if err := ioutil.WriteFile(tempFilepath, []byte(data), 0644 /* rw-r--r-- */); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Rename(tempFilepath, filepath); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -1255,16 +1255,22 @@ func (c *configImpl) MetricsUploaderApp() string {
|
||||||
return c.metricsUploader
|
return c.metricsUploader
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogsDir returns the logs directory where build log and metrics
|
// LogsDir returns the absolute path to the logs directory where build log and
|
||||||
// files are located. By default, the logs directory is the out
|
// metrics files are located. By default, the logs directory is the out
|
||||||
// directory. If the argument dist is specified, the logs directory
|
// directory. If the argument dist is specified, the logs directory
|
||||||
// is <dist_dir>/logs.
|
// is <dist_dir>/logs.
|
||||||
func (c *configImpl) LogsDir() string {
|
func (c *configImpl) LogsDir() string {
|
||||||
|
dir := c.OutDir()
|
||||||
if c.Dist() {
|
if c.Dist() {
|
||||||
// Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
|
// Always write logs to the real dist dir, even if Bazel is using a rigged dist dir for other files
|
||||||
return filepath.Join(c.RealDistDir(), "logs")
|
dir = filepath.Join(c.RealDistDir(), "logs")
|
||||||
}
|
}
|
||||||
return c.OutDir()
|
absDir, err := filepath.Abs(dir)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "\nError making log dir '%s' absolute: %s\n", dir, err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return absDir
|
||||||
}
|
}
|
||||||
|
|
||||||
// BazelMetricsDir returns the <logs dir>/bazel_metrics directory
|
// BazelMetricsDir returns the <logs dir>/bazel_metrics directory
|
||||||
|
|
|
@ -373,6 +373,7 @@ func runSoong(ctx Context, config Config) {
|
||||||
soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
|
soongBuildEnv.Set("BAZEL_OUTPUT_BASE", filepath.Join(config.BazelOutDir(), "output"))
|
||||||
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
|
soongBuildEnv.Set("BAZEL_WORKSPACE", absPath(ctx, "."))
|
||||||
soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
|
soongBuildEnv.Set("BAZEL_METRICS_DIR", config.BazelMetricsDir())
|
||||||
|
soongBuildEnv.Set("LOG_DIR", config.LogsDir())
|
||||||
|
|
||||||
// For Soong bootstrapping tests
|
// For Soong bootstrapping tests
|
||||||
if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
|
if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" {
|
||||||
|
|
|
@ -25,6 +25,7 @@ bootstrap_go_package {
|
||||||
"soong-ui-metrics_proto",
|
"soong-ui-metrics_proto",
|
||||||
"soong-ui-bp2build_metrics_proto",
|
"soong-ui-bp2build_metrics_proto",
|
||||||
"soong-ui-tracer",
|
"soong-ui-tracer",
|
||||||
|
"soong-shared",
|
||||||
],
|
],
|
||||||
srcs: [
|
srcs: [
|
||||||
"metrics.go",
|
"metrics.go",
|
||||||
|
|
|
@ -32,12 +32,12 @@ package metrics
|
||||||
// of what an event is and how the metrics system is a stack based system.
|
// of what an event is and how the metrics system is a stack based system.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
"os"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"android/soong/shared"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
|
|
||||||
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
|
soong_metrics_proto "android/soong/ui/metrics/metrics_proto"
|
||||||
|
@ -196,7 +196,7 @@ func (m *Metrics) Dump(out string) error {
|
||||||
}
|
}
|
||||||
m.metrics.HostOs = proto.String(runtime.GOOS)
|
m.metrics.HostOs = proto.String(runtime.GOOS)
|
||||||
|
|
||||||
return save(&m.metrics, out)
|
return shared.Save(&m.metrics, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSoongBuildMetrics sets the metrics collected from the soong_build
|
// SetSoongBuildMetrics sets the metrics collected from the soong_build
|
||||||
|
@ -228,25 +228,5 @@ func (c *CriticalUserJourneysMetrics) Add(name string, metrics *Metrics) {
|
||||||
|
|
||||||
// Dump saves the collected CUJs metrics to the raw protobuf file.
|
// Dump saves the collected CUJs metrics to the raw protobuf file.
|
||||||
func (c *CriticalUserJourneysMetrics) Dump(filename string) (err error) {
|
func (c *CriticalUserJourneysMetrics) Dump(filename string) (err error) {
|
||||||
return save(&c.cujs, filename)
|
return shared.Save(&c.cujs, filename)
|
||||||
}
|
|
||||||
|
|
||||||
// save takes a protobuf message, marshals to an array of bytes
|
|
||||||
// and is then saved to a file.
|
|
||||||
func save(pb proto.Message, filename string) (err error) {
|
|
||||||
data, err := proto.Marshal(pb)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
tempFilename := filename + ".tmp"
|
|
||||||
if err := ioutil.WriteFile(tempFilename, []byte(data), 0644 /* rw-r--r-- */); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Rename(tempFilename, filename); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue