blob: 20002c67fd6be2bd6696870bedbc178605250cb0 [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"
Liz Kammer32c634b2023-08-25 17:42:42 -040012
usta4f5d2c12022-10-28 23:32:01 -040013 "google.golang.org/protobuf/proto"
Kevin Dagostino60f562a2022-09-20 03:54:47 +000014
Chris Parsons492bd912022-01-20 12:55:05 -050015 "github.com/google/blueprint"
Jingwen Chen164e0862021-02-19 00:48:40 -050016)
17
Liz Kammer32c634b2023-08-25 17:42:42 -040018type moduleInfo struct {
19 Name string `json:"name"`
20 Type string `json:"type"`
21}
22
usta4f5d2c12022-10-28 23:32:01 -040023// CodegenMetrics represents information about the Blueprint-to-BUILD
Jingwen Chen164e0862021-02-19 00:48:40 -050024// conversion process.
usta4f5d2c12022-10-28 23:32:01 -040025// Use CreateCodegenMetrics() to get a properly initialized instance
Jingwen Chen164e0862021-02-19 00:48:40 -050026type CodegenMetrics struct {
usta4f5d2c12022-10-28 23:32:01 -040027 serialized *bp2build_metrics_proto.Bp2BuildMetrics
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050028 // List of modules with unconverted deps
29 // NOTE: NOT in the .proto
Liz Kammer6eff3232021-08-26 08:37:59 -040030 moduleWithUnconvertedDepsMsgs []string
Jingwen Chen61174502021-09-17 08:40:45 +000031
Liz Kammerdaa09ef2021-12-15 15:35:38 -050032 // List of modules with missing deps
33 // NOTE: NOT in the .proto
34 moduleWithMissingDepsMsgs []string
35
Kevin Dagostino60f562a2022-09-20 03:54:47 +000036 // Map of converted modules and paths to call
usta4f5d2c12022-10-28 23:32:01 -040037 // NOTE: NOT in the .proto
Kevin Dagostino60f562a2022-09-20 03:54:47 +000038 convertedModulePathMap map[string]string
Liz Kammer32c634b2023-08-25 17:42:42 -040039
40 // Name and type of converted modules
41 convertedModuleWithType []moduleInfo
usta4f5d2c12022-10-28 23:32:01 -040042}
Kevin Dagostino60f562a2022-09-20 03:54:47 +000043
usta4f5d2c12022-10-28 23:32:01 -040044func CreateCodegenMetrics() CodegenMetrics {
45 return CodegenMetrics{
46 serialized: &bp2build_metrics_proto.Bp2BuildMetrics{
47 RuleClassCount: make(map[string]uint64),
48 ConvertedModuleTypeCount: make(map[string]uint64),
49 TotalModuleTypeCount: make(map[string]uint64),
Chris Parsons39a16972023-06-08 14:28:51 +000050 UnconvertedModules: make(map[string]*bp2build_metrics_proto.UnconvertedReason),
usta4f5d2c12022-10-28 23:32:01 -040051 },
52 convertedModulePathMap: make(map[string]string),
53 }
Jingwen Chen164e0862021-02-19 00:48:40 -050054}
55
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050056// Serialize returns the protoized version of CodegenMetrics: bp2build_metrics_proto.Bp2BuildMetrics
usta4f5d2c12022-10-28 23:32:01 -040057func (metrics *CodegenMetrics) Serialize() *bp2build_metrics_proto.Bp2BuildMetrics {
58 return metrics.serialized
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050059}
60
Jingwen Chen164e0862021-02-19 00:48:40 -050061// Print the codegen metrics to stdout.
Jingwen Chenafb84bd2021-09-20 10:31:46 +000062func (metrics *CodegenMetrics) Print() {
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050063 generatedTargetCount := uint64(0)
Cole Faust18994c72023-02-28 16:02:16 -080064 for _, ruleClass := range android.SortedKeys(metrics.serialized.RuleClassCount) {
usta4f5d2c12022-10-28 23:32:01 -040065 count := metrics.serialized.RuleClassCount[ruleClass]
Jingwen Chen164e0862021-02-19 00:48:40 -050066 fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
67 generatedTargetCount += count
68 }
69 fmt.Printf(
Liz Kammerdaa09ef2021-12-15 15:35:38 -050070 `[bp2build] Converted %d Android.bp modules to %d total generated BUILD targets. Included %d handcrafted BUILD targets. There are %d total Android.bp modules.
71%d converted modules have unconverted deps:
72 %s
73%d converted modules have missing deps:
74 %s
75`,
usta4f5d2c12022-10-28 23:32:01 -040076 metrics.serialized.GeneratedModuleCount,
Jingwen Chen164e0862021-02-19 00:48:40 -050077 generatedTargetCount,
usta4f5d2c12022-10-28 23:32:01 -040078 metrics.serialized.HandCraftedModuleCount,
Jingwen Chen310bc8f2021-09-20 10:54:27 +000079 metrics.TotalModuleCount(),
Liz Kammer6eff3232021-08-26 08:37:59 -040080 len(metrics.moduleWithUnconvertedDepsMsgs),
Liz Kammerdaa09ef2021-12-15 15:35:38 -050081 strings.Join(metrics.moduleWithUnconvertedDepsMsgs, "\n\t"),
82 len(metrics.moduleWithMissingDepsMsgs),
83 strings.Join(metrics.moduleWithMissingDepsMsgs, "\n\t"),
84 )
Jingwen Chen164e0862021-02-19 00:48:40 -050085}
Jingwen Chen61174502021-09-17 08:40:45 +000086
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -050087const bp2buildMetricsFilename = "bp2build_metrics.pb"
88
89// fail prints $PWD to stderr, followed by the given printf string and args (vals),
90// then the given alert, and then exits with 1 for failure
91func fail(err error, alertFmt string, vals ...interface{}) {
92 cwd, wderr := os.Getwd()
93 if wderr != nil {
94 cwd = "FAILED TO GET $PWD: " + wderr.Error()
95 }
96 fmt.Fprintf(os.Stderr, "\nIn "+cwd+":\n"+alertFmt+"\n"+err.Error()+"\n", vals...)
97 os.Exit(1)
98}
99
100// Write the bp2build-protoized codegen metrics into the given directory
101func (metrics *CodegenMetrics) Write(dir string) {
102 if _, err := os.Stat(dir); os.IsNotExist(err) {
103 // The metrics dir doesn't already exist, so create it (and parents)
104 if err := os.MkdirAll(dir, 0755); err != nil { // rx for all; w for user
105 fail(err, "Failed to `mkdir -p` %s", dir)
106 }
107 } else if err != nil {
108 fail(err, "Failed to `stat` %s", dir)
109 }
110 metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
111 if err := metrics.dump(metricsFile); err != nil {
112 fail(err, "Error outputting %s", metricsFile)
113 }
114 if _, err := os.Stat(metricsFile); err != nil {
usta4f5d2c12022-10-28 23:32:01 -0400115 if os.IsNotExist(err) {
116 fail(err, "MISSING BP2BUILD METRICS OUTPUT: %s", metricsFile)
117 } else {
118 fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
119 }
120 }
121}
122
123// ReadCodegenMetrics loads CodegenMetrics from `dir`
124// returns a nil pointer if the file doesn't exist
125func ReadCodegenMetrics(dir string) *CodegenMetrics {
126 metricsFile := filepath.Join(dir, bp2buildMetricsFilename)
127 if _, err := os.Stat(metricsFile); err != nil {
128 if os.IsNotExist(err) {
129 return nil
130 } else {
131 fail(err, "FAILED TO `stat` BP2BUILD METRICS OUTPUT: %s", metricsFile)
132 panic("unreachable after fail")
133 }
134 }
135 if buf, err := os.ReadFile(metricsFile); err != nil {
136 fail(err, "FAILED TO READ BP2BUILD METRICS OUTPUT: %s", metricsFile)
137 panic("unreachable after fail")
138 } else {
139 bp2BuildMetrics := bp2build_metrics_proto.Bp2BuildMetrics{
140 RuleClassCount: make(map[string]uint64),
141 ConvertedModuleTypeCount: make(map[string]uint64),
142 TotalModuleTypeCount: make(map[string]uint64),
143 }
144 if err := proto.Unmarshal(buf, &bp2BuildMetrics); err != nil {
145 fail(err, "FAILED TO PARSE BP2BUILD METRICS OUTPUT: %s", metricsFile)
146 }
147 return &CodegenMetrics{
148 serialized: &bp2BuildMetrics,
149 convertedModulePathMap: make(map[string]string),
150 }
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500151 }
152}
153
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000154func (metrics *CodegenMetrics) IncrementRuleClassCount(ruleClass string) {
usta4f5d2c12022-10-28 23:32:01 -0400155 metrics.serialized.RuleClassCount[ruleClass] += 1
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000156}
157
usta4f5d2c12022-10-28 23:32:01 -0400158func (metrics *CodegenMetrics) AddEvent(event *bp2build_metrics_proto.Event) {
159 metrics.serialized.Events = append(metrics.serialized.Events, event)
160}
Usta Shresthada15c612022-11-08 14:12:36 -0500161
Usta Shresthada15c612022-11-08 14:12:36 -0500162func (metrics *CodegenMetrics) SetSymlinkCount(n uint64) {
163 if m := metrics.serialized.WorkspaceSymlinkCount; m != 0 {
164 fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceSymlinkCount of %d", m)
165 }
166 metrics.serialized.WorkspaceSymlinkCount = n
167}
168
169func (metrics *CodegenMetrics) SetMkDirCount(n uint64) {
170 if m := metrics.serialized.WorkspaceMkDirCount; m != 0 {
171 fmt.Fprintf(os.Stderr, "unexpected non-zero workspaceDirCount of %d", m)
172 }
173 metrics.serialized.WorkspaceMkDirCount = n
174}
175
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500176func (metrics *CodegenMetrics) TotalModuleCount() uint64 {
usta4f5d2c12022-10-28 23:32:01 -0400177 return metrics.serialized.HandCraftedModuleCount +
178 metrics.serialized.GeneratedModuleCount +
179 metrics.serialized.UnconvertedModuleCount
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000180}
181
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500182// Dump serializes the metrics to the given filename
183func (metrics *CodegenMetrics) dump(filename string) (err error) {
184 ser := metrics.Serialize()
usta4f5d2c12022-10-28 23:32:01 -0400185 return shared.Save(ser, filename)
Alex Márquez Pérez Muñíz Díaz Púras Thaureaux947fdbf2021-11-10 09:55:20 -0500186}
187
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000188type ConversionType int
189
190const (
191 Generated ConversionType = iota
192 Handcrafted
193)
194
Chris Parsons39a16972023-06-08 14:28:51 +0000195func (metrics *CodegenMetrics) AddConvertedModule(m blueprint.Module, moduleType string, dir string) {
Jason Wu9948a862023-01-13 14:34:57 -0500196 //a package module has empty name
197 if moduleType == "package" {
198 return
199 }
Jingwen Chen61174502021-09-17 08:40:45 +0000200 // Undo prebuilt_ module name prefix modifications
Chris Parsons492bd912022-01-20 12:55:05 -0500201 moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
usta4f5d2c12022-10-28 23:32:01 -0400202 metrics.serialized.ConvertedModules = append(metrics.serialized.ConvertedModules, moduleName)
Liz Kammer32c634b2023-08-25 17:42:42 -0400203 metrics.convertedModuleWithType = append(metrics.convertedModuleWithType, moduleInfo{
204 moduleName,
205 moduleType,
206 })
Kevin Dagostino60f562a2022-09-20 03:54:47 +0000207 metrics.convertedModulePathMap[moduleName] = "//" + dir
usta4f5d2c12022-10-28 23:32:01 -0400208 metrics.serialized.ConvertedModuleTypeCount[moduleType] += 1
209 metrics.serialized.TotalModuleTypeCount[moduleType] += 1
Chris Parsons39a16972023-06-08 14:28:51 +0000210 metrics.serialized.GeneratedModuleCount += 1
211}
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000212
Chris Parsons39a16972023-06-08 14:28:51 +0000213func (metrics *CodegenMetrics) AddUnconvertedModule(m blueprint.Module, moduleType string, dir string,
214 reason android.UnconvertedReason) {
215 //a package module has empty name
216 if moduleType == "package" {
217 return
218 }
219 // Undo prebuilt_ module name prefix modifications
220 moduleName := android.RemoveOptionalPrebuiltPrefix(m.Name())
221 metrics.serialized.UnconvertedModules[moduleName] = &bp2build_metrics_proto.UnconvertedReason{
222 Type: bp2build_metrics_proto.UnconvertedReasonType(reason.ReasonType),
223 Detail: reason.Detail,
224 }
225 metrics.serialized.UnconvertedModuleCount += 1
226 metrics.serialized.TotalModuleTypeCount[moduleType] += 1
227
228 if reason.ReasonType == int(bp2build_metrics_proto.UnconvertedReasonType_DEFINED_IN_BUILD_FILE) {
usta4f5d2c12022-10-28 23:32:01 -0400229 metrics.serialized.HandCraftedModuleCount += 1
Jingwen Chen310bc8f2021-09-20 10:54:27 +0000230 }
Jingwen Chen61174502021-09-17 08:40:45 +0000231}