xref: /aosp_15_r20/tools/trebuchet/trebuchet/system-server-analyzer/src/SystemServerAnalyzer.kt (revision 56b170dbe6574b1f0ec9db7a63de7238ca6a09ea)
1 /*
<lambda>null2  * Copyright 2019 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     https://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * Notes
19  *
20  * TODO (felipeal): generate .csv file
21  * TODO (felipeal): automatically generate atrace / restart system_server
22  * TODO (felipeal): add mre command-line options, like threshold value
23  */
24 
25 /*
26  * Imports
27  */
28 
29 import java.io.File
30 import trebuchet.model.Model
31 import trebuchet.extras.parseTrace
32 import trebuchet.model.base.Slice
33 import trebuchet.model.base.SliceGroup
34 import trebuchet.queries.slices.slices
35 import java.io.PrintStream
36 
37 /*
38  * Constants
39  */
40 
41 /*
42  * Class Definition
43  */
44 
45 /*
46  * Class Extensions
47  */
48 
49 /*
50  * Helper Functions
51  */
52 
53 inline fun <reified T> Slice?.ifGroup(func: (SliceGroup) -> T): T? {
54     if (this is SliceGroup) {
55         return func(this)
56     }
57     return null
58 }
59 
Doublenull60 fun Double.durationString(): String {
61     return "%.3f ms".format(this * 1000)
62 }
63 
printLinenull64 fun printLine(output: PrintStream, name: String, duration: Double, csvFormat: Boolean = false) {
65     if (csvFormat) {
66         output.println("${name};${duration * 1000}")
67     } else {
68         output.println("${name}: ${duration.durationString()}")
69     }
70 }
71 
printLinenull72 fun printLine(output: PrintStream, model: SliceGroup, csvFormat: Boolean = false) {
73     printLine(output, model.name, model.duration, csvFormat)
74 }
75 
measureServiceStartupnull76 fun measureServiceStartup(model: Model, thresholdMs: Int = 0, output: PrintStream = System.out, csvFormat: Boolean = false, otherName: String = "Other") {
77     model.slices().firstOrNull {
78         it.name == "StartServices" && it is SliceGroup
79     }.ifGroup {
80         printLine(output, "StartServices", it.duration, csvFormat);
81         val childDurations = it.children.sumByDouble { service ->
82             if (service.duration * 1000 >= thresholdMs) {
83                 printLine(output, service, csvFormat)
84                 service.duration
85             } else {
86                 0.0
87             }
88         }
89         printLine(output, "Other", it.duration - childDurations, csvFormat);
90     }
91 }
92 
93 /*
94  * Main Function
95  */
96 
mainnull97 fun main(args: Array<String>) {
98     if (args.isEmpty()) {
99         println("Usage: SystemServerAnalyzerKt <trace_filename> [-t threshold_ms] [-o output_filename]")
100         return
101     }
102 
103     val input = args[0]
104 
105     println("Opening ${input}")
106     val trace = parseTrace(File(input), verbose = true)
107 
108     var csvFormat = false
109     var output = System.out
110     var thresholdMs = 5;
111 
112     // Parse optional arguments
113     var nextArg = 1
114     while (nextArg < args.size) {
115         var arg = args[nextArg++]
116         var value = args[nextArg++]
117         when (arg) {
118             "-t" -> thresholdMs = value.toInt()
119             "-o" -> {
120                 output = PrintStream(File(value).outputStream())
121                 csvFormat = true
122                 println("Writing CSV output to ${value}")
123             }
124             else -> println("invalid option: ${arg}")
125         }
126     }
127 
128     measureServiceStartup(trace, thresholdMs, output, csvFormat)
129 }