123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- package bp2build
- import (
- "fmt"
- "os"
- "path/filepath"
- "strings"
- "android/soong/android"
- "android/soong/shared"
- "android/soong/ui/metrics/bp2build_metrics_proto"
- "google.golang.org/protobuf/proto"
- "github.com/google/blueprint"
- )
- // CodegenMetrics represents information about the Blueprint-to-BUILD
- // conversion process.
- // Use CreateCodegenMetrics() to get a properly initialized instance
- type CodegenMetrics struct {
- serialized *bp2build_metrics_proto.Bp2BuildMetrics
- // List of modules with unconverted deps
- // NOTE: NOT in the .proto
- moduleWithUnconvertedDepsMsgs []string
- // List of modules with missing deps
- // NOTE: NOT in the .proto
- moduleWithMissingDepsMsgs []string
- // Map of converted modules and paths to call
- // NOTE: NOT in the .proto
- convertedModulePathMap map[string]string
- }
- func CreateCodegenMetrics() CodegenMetrics {
- return CodegenMetrics{
- serialized: &bp2build_metrics_proto.Bp2BuildMetrics{
- RuleClassCount: make(map[string]uint64),
- ConvertedModuleTypeCount: make(map[string]uint64),
- TotalModuleTypeCount: make(map[string]uint64),
- UnconvertedModules: make(map[string]*bp2build_metrics_proto.UnconvertedReason),
- },
- convertedModulePathMap: make(map[string]string),
- }
- }
- // Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
- func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetrics {
- return metrics.serialized
- }
- // Print the codegen metrics to stdout.
- func (metrics *CodegenMetrics) Print() {
- generatedTargetCount := uint64(0)
- for _, ruleClass := range android.SortedKeys(metrics.serialized.RuleClassCount) {
- count := metrics.serialized.RuleClassCount[ruleClass]
- fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
- generatedTargetCount += count
- }
- fmt.Printf(
- `[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.
- %d converted modules have unconverted deps:
- %s
- %d converted modules have missing deps:
- %s
- `,
- metrics.serialized.GeneratedModuleCount,
- generatedTargetCount,
- metrics.serialized.HandCraftedModuleCount,
- metrics.TotalModuleCount(),
- len(metrics.moduleWithUnconvertedDepsMsgs),
- strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
- len(metrics.moduleWithMissingDepsMsgs),
- strings.Join(metrics.moduleWithMissingDepsMsgs, "\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 {
- if os.IsNotExist(err) {
- fail(err, "MISSING BP2BUILD METRICS OUTPUT: %s", metricsFile)
- } else {
- fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
- }
- }
- }
- // ReadCodegenMetrics loads CodegenMetrics from `dir`
- // returns a nil pointer if the file doesn't exist
- func ReadCodegenMetrics(dir string) *CodegenMetrics {
- metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
- if _, err := os.Stat(metricsFile); err != nil {
- if os.IsNotExist(err) {
- return nil
- } else {
- fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
- panic("unreachable after fail")
- }
- }
- if buf, err := os.ReadFile(metricsFile); err != nil {
- fail(err, "FAILED TO READ BP2BUILD METRICS OUTPUT: %s", metricsFile)
- panic("unreachable after fail")
- } else {
- bp2BuildMetrics := bp2build_metrics_proto.Bp2BuildMetrics{
- RuleClassCount: make(map[string]uint64),
- ConvertedModuleTypeCount: make(map[string]uint64),
- TotalModuleTypeCount: make(map[string]uint64),
- }
- if err := proto.Unmarshal(buf, &bp2BuildMetrics); err != nil {
- fail(err, "FAILED TO PARSE BP2BUILD METRICS OUTPUT: %s", metricsFile)
- }
- return &CodegenMetrics{
- serialized: &bp2BuildMetrics,
- convertedModulePathMap: make(map[string]string),
- }
- }
- }
- func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
- metrics.serialized.RuleClassCount[ruleClass] += 1
- }
- func (metrics *CodegenMetrics) AddEvent(event *bp2build_metrics_proto.Event) {
- metrics.serialized.Events = append(metrics.serialized.Events, event)
- }
- func (metrics *CodegenMetrics) SetSymlinkCount(n uint64) {
- if m := metrics.serialized.WorkspaceSymlinkCount; m != 0 {
- fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceSymlinkCount of %d", m)
- }
- metrics.serialized.WorkspaceSymlinkCount = n
- }
- func (metrics *CodegenMetrics) SetMkDirCount(n uint64) {
- if m := metrics.serialized.WorkspaceMkDirCount; m != 0 {
- fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceDirCount of %d", m)
- }
- metrics.serialized.WorkspaceMkDirCount = n
- }
- func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
- return metrics.serialized.HandCraftedModuleCount +
- metrics.serialized.GeneratedModuleCount +
- metrics.serialized.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
- const (
- Generated ConversionType = iota
- Handcrafted
- )
- func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string) {
- //a package module has empty name
- if moduleType == "package" {
- return
- }
- // Undo prebuilt_ module name prefix modifications
- moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
- metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
- metrics.convertedModulePathMap[moduleName] = "//" + dir
- metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
- metrics.serialized.TotalModuleTypeCount[moduleType] += 1
- metrics.serialized.GeneratedModuleCount += 1
- }
- func (metrics *CodegenMetrics) AddUnconvertedModule(m blueprint.Module, moduleType string, dir string,
- reason android.UnconvertedReason) {
- //a package module has empty name
- if moduleType == "package" {
- return
- }
- // Undo prebuilt_ module name prefix modifications
- moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
- metrics.serialized.UnconvertedModules[moduleName] = &bp2build_metrics_proto.UnconvertedReason{
- Type: bp2build_metrics_proto.UnconvertedReasonType(reason.ReasonType),
- Detail: reason.Detail,
- }
- metrics.serialized.UnconvertedModuleCount += 1
- metrics.serialized.TotalModuleTypeCount[moduleType] += 1
- if reason.ReasonType == int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
- metrics.serialized.HandCraftedModuleCount += 1
- }
- }
|