1# Scripts reference 2 3[TOC] 4 5## Record a profile 6 7### app_profiler.py 8 9`app_profiler.py` is used to record profiling data for Android applications and native executables. 10 11```sh 12# Record an Android application. 13$ ./app_profiler.py -p simpleperf.example.cpp 14 15# Record an Android application with Java code compiled into native instructions. 16$ ./app_profiler.py -p simpleperf.example.cpp --compile_java_code 17 18# Record the launch of an Activity of an Android application. 19$ ./app_profiler.py -p simpleperf.example.cpp -a .SleepActivity 20 21# Record a native process. 22$ ./app_profiler.py -np surfaceflinger 23 24# Record a native process given its pid. 25$ ./app_profiler.py --pid 11324 26 27# Record a command. 28$ ./app_profiler.py -cmd \ 29 "dex2oat --dex-file=/data/local/tmp/app-debug.apk --oat-file=/data/local/tmp/a.oat" 30 31# Record an Android application, and use -r to send custom options to the record command. 32$ ./app_profiler.py -p simpleperf.example.cpp \ 33 -r "-e cpu-clock -g --duration 30" 34 35# Record both on CPU time and off CPU time. 36$ ./app_profiler.py -p simpleperf.example.cpp \ 37 -r "-e task-clock -g -f 1000 --duration 10 --trace-offcpu" 38 39# Save profiling data in a custom file (like perf_custom.data) instead of perf.data. 40$ ./app_profiler.py -p simpleperf.example.cpp -o perf_custom.data 41``` 42 43### Profile from launch of an application 44 45Sometimes we want to profile the launch-time of an application. To support this, we added `--app` in 46the record command. The `--app` option sets the package name of the Android application to profile. 47If the app is not already running, the record command will poll for the app process in a loop with 48an interval of 1ms. So to profile from launch of an application, we can first start the record 49command with `--app`, then start the app. Below is an example. 50 51```sh 52$ ./run_simpleperf_on_device.py record --app simpleperf.example.cpp \ 53 -g --duration 1 -o /data/local/tmp/perf.data 54# Start the app manually or using the `am` command. 55``` 56 57To make it convenient to use, `app_profiler.py` supports using the `-a` option to start an Activity 58after recording has started. 59 60```sh 61$ ./app_profiler.py -p simpleperf.example.cpp -a .MainActivity 62``` 63 64### api_profiler.py 65 66`api_profiler.py` is used to control recording in application code. It does preparation work 67before recording, and collects profiling data files after recording. 68 69[Here](./android_application_profiling.md#control-recording-in-application-code) are the details. 70 71### run_simpleperf_without_usb_connection.py 72 73`run_simpleperf_without_usb_connection.py` records profiling data while the USB cable isn't 74connected. Maybe `api_profiler.py` is more suitable, which also don't need USB cable when recording. 75Below is an example. 76 77```sh 78$ ./run_simpleperf_without_usb_connection.py start -p simpleperf.example.cpp 79# After the command finishes successfully, unplug the USB cable, run the 80# SimpleperfExampleCpp app. After a few seconds, plug in the USB cable. 81$ ./run_simpleperf_without_usb_connection.py stop 82# It may take a while to stop recording. After that, the profiling data is collected in perf.data 83# on host. 84``` 85 86### binary_cache_builder.py 87 88The `binary_cache` directory is a directory holding binaries needed by a profiling data file. The 89binaries are expected to be unstripped, having debug information and symbol tables. The 90`binary_cache` directory is used by report scripts to read symbols of binaries. It is also used by 91`report_html.py` to generate annotated source code and disassembly. 92 93By default, `app_profiler.py` builds the binary_cache directory after recording. But we can also 94build `binary_cache` for existing profiling data files using `binary_cache_builder.py`. It is useful 95when you record profiling data using `simpleperf record` directly, to do system wide profiling or 96record without the USB cable connected. 97 98`binary_cache_builder.py` can either pull binaries from an Android device, or find binaries in 99directories on the host (via `-lib`). 100 101```sh 102# Generate binary_cache for perf.data, by pulling binaries from the device. 103$ ./binary_cache_builder.py 104 105# Generate binary_cache, by pulling binaries from the device and finding binaries in 106# SimpleperfExampleCpp. 107$ ./binary_cache_builder.py -lib path_of_SimpleperfExampleCpp 108``` 109 110### run_simpleperf_on_device.py 111 112This script pushes the `simpleperf` executable on the device, and run a simpleperf command on the 113device. It is more convenient than running adb commands manually. 114 115## Viewing the profile 116 117Scripts in this section are for viewing the profile or converting profile data into formats used by 118external UIs. For recommended UIs, see [view_the_profile.md](view_the_profile.md). 119 120### report.py 121 122report.py is a wrapper of the `report` command on the host. It accepts all options of the `report` 123command. 124 125```sh 126# Report call graph 127$ ./report.py -g 128 129# Report call graph in a GUI window implemented by Python Tk. 130$ ./report.py -g --gui 131``` 132 133### report_html.py 134 135`report_html.py` generates `report.html` based on the profiling data. Then the `report.html` can show 136the profiling result without depending on other files. So it can be shown in local browsers or 137passed to other machines. Depending on which command-line options are used, the content of the 138`report.html` can include: chart statistics, sample table, flamegraphs, annotated source code for 139each function, annotated disassembly for each function. 140 141```sh 142# Generate chart statistics, sample table and flamegraphs, based on perf.data. 143$ ./report_html.py 144 145# Add source code. 146$ ./report_html.py --add_source_code --source_dirs path_of_SimpleperfExampleCpp 147 148# Add disassembly. 149$ ./report_html.py --add_disassembly 150 151# Adding disassembly for all binaries can cost a lot of time. So we can choose to only add 152# disassembly for selected binaries. 153$ ./report_html.py --add_disassembly --binary_filter libgame.so 154 155# report_html.py accepts more than one recording data file. 156$ ./report_html.py -i perf1.data perf2.data 157``` 158 159Below is an example of generating html profiling results for SimpleperfExampleCpp. 160 161```sh 162$ ./app_profiler.py -p simpleperf.example.cpp 163$ ./report_html.py --add_source_code --source_dirs path_of_SimpleperfExampleCpp \ 164 --add_disassembly 165``` 166 167After opening the generated [`report.html`](./report_html.html) in a browser, there are several tabs: 168 169The first tab is "Chart Statistics". You can click the pie chart to show the time consumed by each 170process, thread, library and function. 171 172The second tab is "Sample Table". It shows the time taken by each function. By clicking one row in 173the table, we can jump to a new tab called "Function". 174 175The third tab is "Flamegraph". It shows the graphs generated by [`inferno`](./inferno.md). 176 177The fourth tab is "Function". It only appears when users click a row in the "Sample Table" tab. 178It shows information of a function, including: 179 1801. A flamegraph showing functions called by that function. 1812. A flamegraph showing functions calling that function. 1823. Annotated source code of that function. It only appears when there are source code files for 183 that function. 1844. Annotated disassembly of that function. It only appears when there are binaries containing that 185 function. 186 187### inferno 188 189[`inferno`](./inferno.md) is a tool used to generate flamegraph in a html file. 190 191```sh 192# Generate flamegraph based on perf.data. 193# On Windows, use inferno.bat instead of ./inferno.sh. 194$ ./inferno.sh -sc --record_file perf.data 195 196# Record a native program and generate flamegraph. 197$ ./inferno.sh -np surfaceflinger 198``` 199 200### purgatorio 201 202[`purgatorio`](../scripts/purgatorio/README.md) is a visualization tool to show samples in time order. 203 204### pprof_proto_generator.py 205 206It converts a profiling data file into `pprof.proto`, a format used by [pprof](https://github.com/google/pprof). 207 208```sh 209# Convert perf.data in the current directory to pprof.proto format. 210$ ./pprof_proto_generator.py 211# Show report in pdf format. 212$ pprof -pdf pprof.profile 213 214# Show report in html format. To show disassembly, add --tools option like: 215# --tools=objdump:<ndk_path>/toolchains/llvm/prebuilt/linux-x86_64/aarch64-linux-android/bin 216# To show annotated source or disassembly, select `top` in the view menu, click a function and 217# select `source` or `disassemble` in the view menu. 218$ pprof -http=:8080 pprof.profile 219``` 220 221### gecko_profile_generator.py 222 223Converts `perf.data` to [Gecko Profile 224Format](https://github.com/firefox-devtools/profiler/blob/main/docs-developer/gecko-profile-format.md), 225the format read by https://profiler.firefox.com/. 226 227Firefox Profiler is a powerful general-purpose profiler UI which runs locally in 228any browser (not just Firefox), with: 229 230- Per-thread tracks 231- Flamegraphs 232- Search, focus for specific stacks 233- A time series view for seeing your samples in timestamp order 234- Filtering by thread and duration 235 236Usage: 237 238``` 239# Record a profile of your application 240$ ./app_profiler.py -p simpleperf.example.cpp 241 242# Convert and gzip. 243$ ./gecko_profile_generator.py -i perf.data | gzip > gecko-profile.json.gz 244``` 245 246Then open `gecko-profile.json.gz` in https://profiler.firefox.com/. 247 248### report_sample.py 249 250`report_sample.py` converts a profiling data file into the `perf script` text format output by 251`linux-perf-tool`. 252 253This format can be imported into: 254 255- [FlameGraph](https://github.com/brendangregg/FlameGraph) 256- [Flamescope](https://github.com/Netflix/flamescope) 257- [Firefox 258 Profiler](https://github.com/firefox-devtools/profiler/blob/main/docs-user/guide-perf-profiling.md), 259 but prefer using `gecko_profile_generator.py`. 260- [Speedscope](https://github.com/jlfwong/speedscope/wiki/Importing-from-perf-(linux)) 261 262```sh 263# Record a profile to perf.data 264$ ./app_profiler.py <args> 265 266# Convert perf.data in the current directory to a format used by FlameGraph. 267$ ./report_sample.py --symfs binary_cache >out.perf 268 269$ git clone https://github.com/brendangregg/FlameGraph.git 270$ FlameGraph/stackcollapse-perf.pl out.perf >out.folded 271$ FlameGraph/flamegraph.pl out.folded >a.svg 272``` 273 274### stackcollapse.py 275 276`stackcollapse.py` converts a profiling data file (`perf.data`) to [Brendan 277Gregg's "Folded Stacks" 278format](https://queue.acm.org/detail.cfm?id=2927301#:~:text=The%20folded%20stack%2Dtrace%20format,trace%2C%20followed%20by%20a%20semicolon). 279 280Folded Stacks are lines of semicolon-delimited stack frames, root to leaf, 281followed by a count of events sampled in that stack, e.g.: 282 283``` 284BusyThread;__start_thread;__pthread_start(void*);java.lang.Thread.run 17889729 285``` 286 287All similar stacks are aggregated and sample timestamps are unused. 288 289Folded Stacks format is readable by: 290 291- The [FlameGraph](https://github.com/brendangregg/FlameGraph) toolkit 292- [Inferno](https://github.com/jonhoo/inferno) (Rust port of FlameGraph) 293- [Speedscope](https://speedscope.app/) 294 295Example: 296 297```sh 298# Record a profile to perf.data 299$ ./app_profiler.py <args> 300 301# Convert to Folded Stacks format 302$ ./stackcollapse.py --kernel --jit | gzip > profile.folded.gz 303 304# Visualise with FlameGraph with Java Stacks and nanosecond times 305$ git clone https://github.com/brendangregg/FlameGraph.git 306$ gunzip -c profile.folded.gz \ 307 | FlameGraph/flamegraph.pl --color=java --countname=ns \ 308 > profile.svg 309``` 310 311## simpleperf_report_lib.py 312 313`simpleperf_report_lib.py` is a Python library used to parse profiling data files generated by the 314record command. Internally, it uses libsimpleperf_report.so to do the work. Generally, for each 315profiling data file, we create an instance of ReportLib, pass it the file path (via SetRecordFile). 316Then we can read all samples through GetNextSample(). For each sample, we can read its event info 317(via GetEventOfCurrentSample), symbol info (via GetSymbolOfCurrentSample) and call chain info 318(via GetCallChainOfCurrentSample). We can also get some global information, like record options 319(via GetRecordCmd), the arch of the device (via GetArch) and meta strings (via MetaInfo). 320 321Examples of using `simpleperf_report_lib.py` are in `report_sample.py`, `report_html.py`, 322`pprof_proto_generator.py` and `inferno/inferno.py`. 323