blob: 00f21c8a7dd2b95b4879665c951b6526984f5356 [file] [log] [blame]
Jingwen Chen164e0862021-02-19 00:48:40 -05001package bp2build
2
3import (
Jingwen Chen164e0862021-02-19 00:48:40 -05004 "fmt"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -05005 "os"
6 "path/filepath"
Liz Kammer6eff3232021-08-26 08:37:59 -04007 "strings"
Chris Parsons91b81f02021-12-08 11:19:06 -05008
9 "android/soong/android"
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050010 "android/soong/shared"
11 "android/soong/ui/metrics/bp2build_metrics_proto"
usta4f5d2c12022-10-28 23:32:01 -040012 "google.golang.org/protobuf/proto"
Kevin Dagostino60f562a2022-09-20 03:54:47 +000013
Chris Parsons492bd912022-01-20 12:55:05 -050014 "github.com/google/blueprint"
Jingwen Chen164e0862021-02-19 00:48:40 -050015)
16
usta4f5d2c12022-10-28 23:32:01 -040017// CodegenMetrics represents information about the Blueprint-to-BUILD
Jingwen Chen164e0862021-02-19 00:48:40 -050018// conversion process.
usta4f5d2c12022-10-28 23:32:01 -040019// Use CreateCodegenMetrics() to get a properly initialized instance
Jingwen Chen164e0862021-02-19 00:48:40 -050020type CodegenMetrics struct {
usta4f5d2c12022-10-28 23:32:01 -040021 serialized *bp2build_metrics_proto.Bp2BuildMetrics
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050022 // List of modules with unconverted deps
23 // NOTE: NOT in the .proto
Liz Kammer6eff3232021-08-26 08:37:59 -040024 moduleWithUnconvertedDepsMsgs []string
Jingwen Chen61174502021-09-17 08:40:45 +000025
Liz Kammerdaa09ef2021-12-15 15:35:38 -050026 // List of modules with missing deps
27 // NOTE: NOT in the .proto
28 moduleWithMissingDepsMsgs []string
29
Kevin Dagostino60f562a2022-09-20 03:54:47 +000030 // Map of converted modules and paths to call
usta4f5d2c12022-10-28 23:32:01 -040031 // NOTE: NOT in the .proto
Kevin Dagostino60f562a2022-09-20 03:54:47 +000032 convertedModulePathMap map[string]string
usta4f5d2c12022-10-28 23:32:01 -040033}
Kevin Dagostino60f562a2022-09-20 03:54:47 +000034
usta4f5d2c12022-10-28 23:32:01 -040035func CreateCodegenMetrics() CodegenMetrics {
36 return CodegenMetrics{
37 serialized: &bp2build_metrics_proto.Bp2BuildMetrics{
38 RuleClassCount: make(map[string]uint64),
39 ConvertedModuleTypeCount: make(map[string]uint64),
40 TotalModuleTypeCount: make(map[string]uint64),
Chris Parsons39a16972023-06-08 14:28:51 +000041 UnconvertedModules: make(map[string]*bp2build_metrics_proto.UnconvertedReason),
usta4f5d2c12022-10-28 23:32:01 -040042 },
43 convertedModulePathMap: make(map[string]string),
44 }
Jingwen Chen164e0862021-02-19 00:48:40 -050045}
46
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050047// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
usta4f5d2c12022-10-28 23:32:01 -040048func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetrics {
49 return metrics.serialized
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050050}
51
Jingwen Chen164e0862021-02-19 00:48:40 -050052// Print the codegen metrics to stdout.
Jingwen Chenafb84bd2021-09-20 10:31:46 +000053func (metrics *CodegenMetrics) Print() {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050054 generatedTargetCount := uint64(0)
Cole Faust18994c72023-02-28 16:02:16 -080055 for _, ruleClass := range android.SortedKeys(metrics.serialized.RuleClassCount) {
usta4f5d2c12022-10-28 23:32:01 -040056 count := metrics.serialized.RuleClassCount[ruleClass]
Jingwen Chen164e0862021-02-19 00:48:40 -050057 fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
58 generatedTargetCount += count
59 }
60 fmt.Printf(
Liz Kammerdaa09ef2021-12-15 15:35:38 -050061 `[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.
62%d converted modules have unconverted deps:
63 %s
64%d converted modules have missing deps:
65 %s
66`,
usta4f5d2c12022-10-28 23:32:01 -040067 metrics.serialized.GeneratedModuleCount,
Jingwen Chen164e0862021-02-19 00:48:40 -050068 generatedTargetCount,
usta4f5d2c12022-10-28 23:32:01 -040069 metrics.serialized.HandCraftedModuleCount,
Jingwen Chen310bc8f2021-09-20 10:54:27 +000070 metrics.TotalModuleCount(),
Liz Kammer6eff3232021-08-26 08:37:59 -040071 len(metrics.moduleWithUnconvertedDepsMsgs),
Liz Kammerdaa09ef2021-12-15 15:35:38 -050072 strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
73 len(metrics.moduleWithMissingDepsMsgs),
74 strings.Join(metrics.moduleWithMissingDepsMsgs, "\n\t"),
75 )
Jingwen Chen164e0862021-02-19 00:48:40 -050076}
Jingwen Chen61174502021-09-17 08:40:45 +000077
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050078const bp2buildMetricsFilename = "bp2build_metrics.pb"
79
80// fail prints $PWD to stderr, followed by the given printf string and args (vals),
81// then the given alert, and then exits with 1 for failure
82func fail(err error, alertFmt string, vals ...interface{}) {
83 cwd, wderr := os.Getwd()
84 if wderr != nil {
85 cwd = "FAILED TO GET $PWD: " + wderr.Error()
86 }
87 fmt.Fprintf(os.Stderr, "\nIn "+cwd+":\n"+alertFmt+"\n"+err.Error()+"\n", vals...)
88 os.Exit(1)
89}
90
91// Write the bp2build-protoized codegen metrics into the given directory
92func (metrics *CodegenMetrics) Write(dir string) {
93 if _, err := os.Stat(dir); os.IsNotExist(err) {
94 // The metrics dir doesn't already exist, so create it (and parents)
95 if err := os.MkdirAll(dir, 0755); err != nil { // rx for all; w for user
96 fail(err, "Failed to `mkdir -p` %s", dir)
97 }
98 } else if err != nil {
99 fail(err, "Failed to `stat` %s", dir)
100 }
101 metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
102 if err := metrics.dump(metricsFile); err != nil {
103 fail(err, "Error outputting %s", metricsFile)
104 }
105 if _, err := os.Stat(metricsFile); err != nil {
usta4f5d2c12022-10-28 23:32:01 -0400106 if os.IsNotExist(err) {
107 fail(err, "MISSING BP2BUILD METRICS OUTPUT: %s", metricsFile)
108 } else {
109 fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
110 }
111 }
112}
113
114// ReadCodegenMetrics loads CodegenMetrics from `dir`
115// returns a nil pointer if the file doesn't exist
116func ReadCodegenMetrics(dir string) *CodegenMetrics {
117 metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
118 if _, err := os.Stat(metricsFile); err != nil {
119 if os.IsNotExist(err) {
120 return nil
121 } else {
122 fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
123 panic("unreachable after fail")
124 }
125 }
126 if buf, err := os.ReadFile(metricsFile); err != nil {
127 fail(err, "FAILED TO READ BP2BUILD METRICS OUTPUT: %s", metricsFile)
128 panic("unreachable after fail")
129 } else {
130 bp2BuildMetrics := bp2build_metrics_proto.Bp2BuildMetrics{
131 RuleClassCount: make(map[string]uint64),
132 ConvertedModuleTypeCount: make(map[string]uint64),
133 TotalModuleTypeCount: make(map[string]uint64),
134 }
135 if err := proto.Unmarshal(buf, &bp2BuildMetrics); err != nil {
136 fail(err, "FAILED TO PARSE BP2BUILD METRICS OUTPUT: %s", metricsFile)
137 }
138 return &CodegenMetrics{
139 serialized: &bp2BuildMetrics,
140 convertedModulePathMap: make(map[string]string),
141 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500142 }
143}
144
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000145func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
usta4f5d2c12022-10-28 23:32:01 -0400146 metrics.serialized.RuleClassCount[ruleClass] += 1
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000147}
148
usta4f5d2c12022-10-28 23:32:01 -0400149func (metrics *CodegenMetrics) AddEvent(event *bp2build_metrics_proto.Event) {
150 metrics.serialized.Events = append(metrics.serialized.Events, event)
151}
Usta Shresthada15c612022-11-08 14:12:36 -0500152
Usta Shresthada15c612022-11-08 14:12:36 -0500153func (metrics *CodegenMetrics) SetSymlinkCount(n uint64) {
154 if m := metrics.serialized.WorkspaceSymlinkCount; m != 0 {
155 fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceSymlinkCount of %d", m)
156 }
157 metrics.serialized.WorkspaceSymlinkCount = n
158}
159
160func (metrics *CodegenMetrics) SetMkDirCount(n uint64) {
161 if m := metrics.serialized.WorkspaceMkDirCount; m != 0 {
162 fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceDirCount of %d", m)
163 }
164 metrics.serialized.WorkspaceMkDirCount = n
165}
166
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500167func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
usta4f5d2c12022-10-28 23:32:01 -0400168 return metrics.serialized.HandCraftedModuleCount +
169 metrics.serialized.GeneratedModuleCount +
170 metrics.serialized.UnconvertedModuleCount
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000171}
172
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500173// Dump serializes the metrics to the given filename
174func (metrics *CodegenMetrics) dump(filename string) (err error) {
175 ser := metrics.Serialize()
usta4f5d2c12022-10-28 23:32:01 -0400176 return shared.Save(ser, filename)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500177}
178
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000179type ConversionType int
180
181const (
182 Generated ConversionType = iota
183 Handcrafted
184)
185
Chris Parsons39a16972023-06-08 14:28:51 +0000186func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string) {
Jason Wu9948a862023-01-13 14:34:57 -0500187 //a package module has empty name
188 if moduleType == "package" {
189 return
190 }
Jingwen Chen61174502021-09-17 08:40:45 +0000191 // Undo prebuilt_ module name prefix modifications
Chris Parsons492bd912022-01-20 12:55:05 -0500192 moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
usta4f5d2c12022-10-28 23:32:01 -0400193 metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
Kevin Dagostino60f562a2022-09-20 03:54:47 +0000194 metrics.convertedModulePathMap[moduleName] = "//" + dir
usta4f5d2c12022-10-28 23:32:01 -0400195 metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
196 metrics.serialized.TotalModuleTypeCount[moduleType] += 1
Chris Parsons39a16972023-06-08 14:28:51 +0000197 metrics.serialized.GeneratedModuleCount += 1
198}
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000199
Chris Parsons39a16972023-06-08 14:28:51 +0000200func (metrics *CodegenMetrics) AddUnconvertedModule(m blueprint.Module, moduleType string, dir string,
201 reason android.UnconvertedReason) {
202 //a package module has empty name
203 if moduleType == "package" {
204 return
205 }
206 // Undo prebuilt_ module name prefix modifications
207 moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
208 metrics.serialized.UnconvertedModules[moduleName] = &bp2build_metrics_proto.UnconvertedReason{
209 Type: bp2build_metrics_proto.UnconvertedReasonType(reason.ReasonType),
210 Detail: reason.Detail,
211 }
212 metrics.serialized.UnconvertedModuleCount += 1
213 metrics.serialized.TotalModuleTypeCount[moduleType] += 1
214
215 if reason.ReasonType == int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
usta4f5d2c12022-10-28 23:32:01 -0400216 metrics.serialized.HandCraftedModuleCount += 1
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000217 }
Jingwen Chen61174502021-09-17 08:40:45 +0000218}