1 # Introduction of simpleperf
3 Simpleperf is a native profiling tool for Android. Its command-line interface
4 supports broadly the same options as the linux-tools perf, but also supports
5 various Android-specific improvements.
7 Simpleperf is part of the Android Open Source Project. The source code is at
8 https://android.googlesource.com/platform/system/extras/+/master/simpleperf/.
9 Bugs and feature requests can be submitted at
10 http://github.com/android-ndk/ndk/issues.
12 ## How simpleperf works
13 Modern CPUs have a hardware component called the performance monitoring unit
14 (PMU). The PMU has several hardware counters, counting events like how many cpu
15 cycles have happened, how many instructions have executed, or how many cache
18 The Linux kernel wraps these hardware counters into hardware perf events. In
19 addition, the Linux kernel also provides hardware independent software events
20 and tracepoint events. The Linux kernel exposes all this to userspace via the
21 perf_event_open system call, which simpleperf uses.
23 Simpleperf has three main functions: stat, record and report.
25 The stat command gives a summary of how many events have happened in the
26 profiled processes in a time period. Here’s how it works:
27 1. Given user options, simpleperf enables profiling by making a system call to
29 2. Linux kernel enables counters while scheduling on the profiled processes.
30 3. After profiling, simpleperf reads counters from linux kernel, and reports a
33 The record command records samples of the profiled process in a time period.
35 1. Given user options, simpleperf enables profiling by making a system call to
37 2. Simpleperf creates mapped buffers between simpleperf and linux kernel.
38 3. Linux kernel enable counters while scheduling on the profiled processes.
39 4. Each time a given number of events happen, linux kernel dumps a sample to a
41 5. Simpleperf reads samples from the mapped buffers and generates perf.data.
43 The report command reads a "perf.data" file and any shared libraries used by
44 the profiled processes, and outputs a report showing where the time was spent.
46 ## Main simpleperf commands
47 Simpleperf supports several subcommands, including list, stat, record, report.
48 Each subcommand supports different options. This section only covers the most
49 important subcommands and options. To see all subcommands and options,
52 # List all subcommands.
55 # Print help message for record subcommand.
56 $simpleperf record --help
59 simpleperf list is used to list all events available on the device. Different
60 devices may support different events because of differences in hardware and
64 List of hw-cache events:
67 List of hardware events:
71 List of software events:
77 simpleperf stat is used to get a raw event counter information of the profiled program
78 or system-wide. By passing options, we can select which events to use, which
79 processes/threads to monitor, how long to monitor and the print interval.
82 # Stat using default events (cpu-cycles,instructions,...), and monitor
83 # process 7394 for 10 seconds.
84 $simpleperf stat -p 7394 --duration 10
85 Performance counter statistics:
87 1,320,496,145 cpu-cycles # 0.131736 GHz (100%)
88 510,426,028 instructions # 2.587047 cycles per instruction (100%)
89 4,692,338 branch-misses # 468.118 K/sec (100%)
90 886.008130(ms) task-clock # 0.088390 cpus used (100%)
91 753 context-switches # 75.121 /sec (100%)
92 870 page-faults # 86.793 /sec (100%)
94 Total test time: 10.023829 seconds.
97 We can select which events to use via -e option. Below are examples:
99 # Stat event cpu-cycles.
100 $simpleperf stat -e cpu-cycles -p 11904 --duration 10
102 # Stat event cache-references and cache-misses.
103 $simpleperf stat -e cache-references,cache-misses -p 11904 --duration 10
105 When running the stat command, if the number of hardware events is larger than
106 the number of hardware counters available in the PMU, the kernel shares hardware
107 counters between events, so each event is only monitored for part of the total
108 time. In the example below, there is a percentage at the end of each row,
109 showing the percentage of the total time that each event was actually monitored.
111 # Stat using event cache-references, cache-references:u,....
112 $simpleperf stat -p 7394 -e cache-references,cache-references:u,cache-references:k,cache-misses,cache-misses:u,cache-misses:k,instructions --duration 1
113 Performance counter statistics:
115 4,331,018 cache-references # 4.861 M/sec (87%)
116 3,064,089 cache-references:u # 3.439 M/sec (87%)
117 1,364,959 cache-references:k # 1.532 M/sec (87%)
118 91,721 cache-misses # 102.918 K/sec (87%)
119 45,735 cache-misses:u # 51.327 K/sec (87%)
120 38,447 cache-misses:k # 43.131 K/sec (87%)
121 9,688,515 instructions # 10.561 M/sec (89%)
123 Total test time: 1.026802 seconds.
125 In the example above, each event is monitored about 87% of the total time. But
126 there is no guarantee that any pair of events are always monitored at the same
127 time. If we want to have some events monitored at the same time, we can use
128 --group option. Below is an example.
130 # Stat using event cache-references, cache-references:u,....
131 $simpleperf stat -p 7394 --group cache-references,cache-misses --group cache-references:u,cache-misses:u --group cache-references:k,cache-misses:k -e instructions --duration 1
132 Performance counter statistics:
134 3,638,900 cache-references # 4.786 M/sec (74%)
135 65,171 cache-misses # 1.790953% miss rate (74%)
136 2,390,433 cache-references:u # 3.153 M/sec (74%)
137 32,280 cache-misses:u # 1.350383% miss rate (74%)
138 879,035 cache-references:k # 1.251 M/sec (68%)
139 30,303 cache-misses:k # 3.447303% miss rate (68%)
140 8,921,161 instructions # 10.070 M/sec (86%)
142 Total test time: 1.029843 seconds.
144 #### Select target to monitor
145 We can select which processes or threads to monitor via -p option or -t option.
146 Monitoring a process is the same as monitoring all threads in the process.
147 Simpleperf can also fork a child process to run the new command and then monitor
148 the child process. Below are examples.
150 # Stat process 11904 and 11905.
151 $simpleperf stat -p 11904,11905 --duration 10
153 # Stat thread 11904 and 11905.
154 $simpleperf stat -t 11904,11905 --duration 10
156 # Start a child process running `ls`, and stat it.
159 #### Decide how long to monitor
160 When monitoring existing threads, we can use --duration option to decide how long
161 to monitor. When monitoring a child process running a new command, simpleperf
162 monitors until the child process ends. In this case, we can use Ctrl-C to stop monitoring
163 at any time. Below are examples.
165 # Stat process 11904 for 10 seconds.
166 $simpleperf stat -p 11904 --duration 10
168 # Stat until the child process running `ls` finishes.
171 # Stop monitoring using Ctrl-C.
172 $simpleperf stat -p 11904 --duration 10
175 #### Decide the print interval
176 When monitoring perf counters, we can also use --interval option to decide the print
177 interval. Below are examples.
179 # Print stat for process 11904 every 300ms.
180 $simpleperf stat -p 11904 --duration 10 --interval 300
181 # Stop by using Ctrl-C.
184 # Print system wide stat at interval of 300ms for 10 seconds (rooted device only).
185 # system wide profiling needs root privilege
186 $su 0 simpleperf stat -a --duration 10 --interval 300
188 #### Display counters in systrace
189 simpleperf can also work with systrace to dump counters in the collected trace.
190 Below is an example to do a system wide stat
192 # capture instructions (kernel only) and cache misses with interval of 300 milliseconds for 15 seconds
193 $su 0 simpleperf stat -e instructions:k,cache-misses -a --interval 300 --duration 15
194 # on host launch systrace to collect trace for 10 seconds
195 (HOST)$external/chromium-trace/systrace.py --time=10 -o new.html sched gfx view
196 # open the collected new.html in browser and perf counters will be shown up
198 ### simpleperf record
199 simpleperf record is used to dump records of the profiled program. By passing
200 options, we can select which events to use, which processes/threads to monitor,
201 what frequency to dump records, how long to monitor, and where to store records.
203 # Record on process 7394 for 10 seconds, using default event (cpu-cycles),
204 # using default sample frequency (4000 samples per second), writing records
206 $simpleperf record -p 7394 --duration 10
207 simpleperf I 07-11 21:44:11 17522 17522 cmd_record.cpp:316] Samples recorded: 21430. Samples lost: 0.
210 In most cases, the cpu-cycles event is used to evaluate consumed cpu time.
211 As a hardware event, it is both accurate and efficient. We can also use other
212 events via -e option. Below is an example.
214 # Record using event instructions.
215 $simpleperf record -e instructions -p 11904 --duration 10
217 #### Select target to monitor
218 The way to select target in record command is similar to that in stat command.
221 # Record process 11904 and 11905.
222 $simpleperf record -p 11904,11905 --duration 10
224 # Record thread 11904 and 11905.
225 $simpleperf record -t 11904,11905 --duration 10
227 # Record a child process running `ls`.
228 $simpleperf record ls
230 #### Set the frequency to record
231 We can set the frequency to dump records via the -f or -c options. For example,
232 -f 4000 means dumping approximately 4000 records every second when the monitored
233 thread runs. If a monitored thread runs 0.2s in one second (it can be preempted
234 or blocked in other times), simpleperf dumps about 4000 * 0.2 / 1.0 = 800
235 records every second. Another way is using -c option. For example, -c 10000
236 means dumping one record whenever 10000 events happen. Below are examples.
238 # Record with sample frequency 1000: sample 1000 times every second running.
239 $simpleperf record -f 1000 -p 11904,11905 --duration 10
241 # Record with sample period 100000: sample 1 time every 100000 events.
242 $simpleperf record -c 100000 -t 11904,11905 --duration 10
244 #### Decide how long to monitor
245 The way to decide how long to monitor in record command is similar to that in
246 stat command. Below are examples.
248 # Record process 11904 for 10 seconds.
249 $simpleperf record -p 11904 --duration 10
251 # Record until the child process running `ls` finishes.
252 $simpleperf record ls
254 # Stop monitoring using Ctrl-C.
255 $simpleperf record -p 11904 --duration 10
258 #### Set the path to store records
259 By default, simpleperf stores records in perf.data in current directory. We can
260 use -o option to set the path to store records. Below is an example.
262 # Write records to data/perf2.data.
263 $simpleperf record -p 11904 -o data/perf2.data --duration 10
265 ### simpleperf report
266 simpleperf report is used to report based on perf.data generated by simpleperf
267 record command. Report command groups records into different sample entries,
268 sorts sample entries based on how many events each sample entry contains, and
269 prints out each sample entry. By passing options, we can select where to find
270 perf.data and executable binaries used by the monitored program, filter out
271 uninteresting records, and decide how to group records.
273 Below is an example. Records are grouped into 4 sample entries, each entry is
274 a row. There are several columns, each column shows piece of information
275 belonging to a sample entry. The first column is Overhead, which shows the
276 percentage of events inside current sample entry in total events. As the
277 perf event is cpu-cycles, the overhead can be seen as the percentage of cpu
278 time used in each function.
280 # Reports perf.data, using only records sampled in libsudo-game-jni.so,
281 # grouping records using thread name(comm), process id(pid), thread id(tid),
282 # function name(symbol), and showing sample count for each row.
283 $simpleperf report --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort comm,pid,tid,symbol -n
284 Cmdline: /data/data/com.example.sudogame/simpleperf record -p 7394 --duration 10
286 Event: cpu-cycles (type 0, config 0)
288 Event count: 546356211
290 Overhead Sample Command Pid Tid Symbol
291 59.25% 16680 sudogame 7394 7394 checkValid(Board const&, int, int)
292 20.42% 5620 sudogame 7394 7394 canFindSolution_r(Board&, int, int)
293 13.82% 4088 sudogame 7394 7394 randomBlock_r(Board&, int, int, int, int, int)
294 6.24% 1756 sudogame 7394 7394 @plt
296 #### Set the path to read records
297 By default, simpleperf reads perf.data in current directory. We can use -i
298 option to select another file to read records.
300 $simpleperf report -i data/perf2.data
302 #### Set the path to find executable binaries
303 If reporting function symbols, simpleperf needs to read executable binaries
304 used by the monitored processes to get symbol table and debug information. By
305 default, the paths are the executable binaries used by monitored processes while
306 recording. However, these binaries may not exist when reporting or not contain
307 symbol table and debug information. So we can use --symfs to redirect the paths.
311 # In this case, when simpleperf wants to read executable binary /A/b,
312 # it reads file in /A/b.
314 $simpleperf report --symfs /debug_dir
315 # In this case, when simpleperf wants to read executable binary /A/b,
316 # it prefers file in /debug_dir/A/b to file in /A/b.
319 When reporting, it happens that not all records are of interest. Simpleperf
320 supports five filters to select records of interest. Below are examples.
322 # Report records in threads having name sudogame.
323 $simpleperf report --comms sudogame
325 # Report records in process 7394 or 7395
326 $simpleperf report --pids 7394,7395
328 # Report records in thread 7394 or 7395.
329 $simpleperf report --tids 7394,7395
331 # Report records in libsudo-game-jni.so.
332 $simpleperf report --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so
334 # Report records in function checkValid or canFindSolution_r.
335 $simpleperf report --symbols "checkValid(Board const&, int, int);canFindSolution_r(Board&, int, int)"
337 #### Decide how to group records into sample entries
338 Simpleperf uses --sort option to decide how to group sample entries. Below are
341 # Group records based on their process id: records having the same process
342 # id are in the same sample entry.
343 $simpleperf report --sort pid
345 # Group records based on their thread id and thread comm: records having
346 # the same thread id and thread name are in the same sample entry.
347 $simpleperf report --sort tid,comm
349 # Group records based on their binary and function: records in the same
350 # binary and function are in the same sample entry.
351 $simpleperf report --sort dso,symbol
353 # Default option: --sort comm,pid,tid,dso,symbol. Group records in the same
354 # thread, and belong to the same function in the same binary.
357 ## Features of simpleperf
358 Simpleperf works similar to linux-tools-perf, but it has following improvements:
359 1. Aware of Android environment. Simpleperf handles some Android specific
360 situations when profiling. For example, it can profile embedded shared libraries
361 in apk, read symbol table and debug information from .gnu_debugdata section. If
362 possible, it gives suggestions when facing errors, like how to disable
363 perf_harden to enable profiling.
364 2. Support unwinding while recording. If we want to use -g option to record and
365 report call-graph of a program, we need to dump user stack and register set in
366 each record, and then unwind the stack to find the call chain. Simpleperf
367 supports unwinding while recording, so it doesn’t need to store user stack in
368 perf.data. So we can profile for a longer time with limited space on device.
369 3. Build in static binaries. Simpleperf is a static binary, so it doesn’t need
370 supporting shared libraries to run. It means there is no limitation of Android
371 version that simpleperf can run on, although some devices don’t support
374 # Steps to profile native libraries
375 After introducing simpleperf, this section uses a simple example to show how to
376 profile jni native libraries on Android using simpleperf. The example profiles
377 an app called com.example.sudogame, which uses a jni native library
378 sudo-game-jni.so. We focus on sudo-game-jni.so, not the java code or system
381 ## 1. Run debug version of the app on device
382 We need to run debug version of the app, because we can’t use *run-as* for non
385 ## 2. Download simpleperf to the app’s directory
386 Use *uname* to find the architecture on device
391 "aarch64" means we should download arm64 version of simpleperf to device.
393 $adb push device/arm64/simpleperf /data/local/tmp
394 $adb shell run-as com.example.sudogame cp /data/local/tmp/simpleperf .
395 $adb shell run-as com.example.sudogame chmod a+x simpleperf
396 $adb shell run-as com.example.sudogame ls -l
397 -rwxrwxrwx 1 u0_a90 u0_a90 3059208 2016-01-01 10:40 simpleperf
399 Note that some apps use arm native libraries even on arm64 devices (We can
400 verify this by checking /proc/<process\_id\_of\_app>/maps). In that case, we
401 should use arm/simpleperf instead of arm64/simpleperf.
403 ## 3. Enable profiling
404 Android devices may disable profiling by default, and we need to enable
407 $adb shell setprop security.perf_harden 0
409 ## 4. Find the target process/thread to record
411 # Use `ps` to get process id of sudogame.
412 $adb shell ps | grep sudogame
413 u0_a102 15869 545 1629824 76888 SyS_epoll_ 0000000000 S com.example.sudogame
415 # Use `ps -t` to get thread ids of process 15869.
416 # If this doesn’t work, you can try `ps -eT`.
417 $adb shell ps -t | grep 15869
418 u0_a102 15869 545 1629824 76888 SyS_epoll_ 0000000000 S com.example.sudogame
419 u0_a102 15874 15869 1629824 76888 futex_wait 0000000000 S Jit thread pool
422 ## 5. Record perf.data
424 # Record process 15869 for 30s, and use the app while recording it.
425 $adb shell run-as com.example.sudogame ./simpleperf record -p 15869 --duration 30
426 simpleperf W 07-12 20:00:33 16022 16022 environment.cpp:485] failed to read /proc/sys/kernel/kptr_restrict: Permission denied
427 simpleperf I 07-12 20:01:03 16022 16022 cmd_record.cpp:315] Samples recorded: 81445. Samples lost: 0.
429 $adb shell run-as com.example.sudogame ls -lh perf.data
430 -rw-rw-rw- 1 u0_a102 u0_a102 4.3M 2016-07-12 20:01 perf.data
432 Now we have recorded perf.data with 81445 records. There is a warning about
433 failing to read kptr_restrict. It doesn’t matter in our case, but is a notification that we
434 can’t read kernel symbol addresses.
436 ## 6. Report perf.data
437 Below are several examples reporting on device.
439 ### Report samples in different binaries
441 # Report how samples distribute on different binaries.
442 $adb shell run-as com.example.sudogame ./simpleperf report -n --sort dso
443 simpleperf W 07-12 19:15:10 11389 11389 dso.cpp:309] Symbol addresses in /proc/kallsyms are all zero. `echo 0 >/proc/sys/kernel/kptr_restrict` if possible.
444 Cmdline: /data/data/com.example.sudogame/simpleperf record -p 15869 --duration 30
446 Event: cpu-cycles (type 0, config 0)
448 Event count: 34263925309
450 Overhead Sample Shared Object
451 75.31% 58231 [kernel.kallsyms]
452 8.44% 6845 /system/lib64/libc.so
453 4.30% 4667 /vendor/lib64/egl/libGLESv2_adreno.so
454 2.30% 2433 /system/lib64/libhwui.so
455 1.88% 1952 /system/lib64/libart.so
456 1.88% 1967 /system/framework/arm64/boot-framework.oat
457 1.59% 1218 /system/lib64/libcutils.so
458 0.69% 728 /system/lib64/libskia.so
459 0.63% 489 /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so
460 0.34% 312 /system/lib64/libart-compiler.so
463 According to the report above, most time is spent in kernel, and
464 libsudo-game-jni.so costs only 0.63% by itself. It seems libsudo-game-jni.so
465 can’t be the bottleneck. However, it is possible we didn’t record long enough
466 to hit the hot spot, or code in libsudo-game-jni.so calls other libraries
469 ### Report samples in different functions
471 # Report how samples distribute inside libsudo-game-jni.so.
472 $adb shell run-as com.example.sudogame ./simpleperf report -n --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort symbol
474 Overhead Sample Symbol
477 0.20% 1 Java_com_example_sudogame_GameModel_findConflictPairs
478 0.14% 1 Java_com_example_sudogame_GameModel_canFindSolution
480 In the report above, most samples belong to unknown symbol. It is because the
481 libsudo-game-jni.so used on device doesn’t contain symbol table. We need to
482 download shared library with symbol table to device. In android studio 2.1.2,
483 the binary with symbol table is in
484 [app_dir]/app/build/intermediates/binaries/debug/obj/arm64-v8a (for amr64).
486 # Make a proper directory to download binary to device. This directory
487 # should be the same as the directory of
488 # /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so.
489 $adb shell run-as com.example.sudogame mkdir -p data/app/com.example.sudogame-2/lib/arm64
490 # Download binary with symbol table.
491 $adb push [app_dir]/app/build/intermediates/binaries/debug/obj/arm64-v8a/libsudo-game-jni.so /data/local/tmp
492 $adb shell run-as com.example.sudogame cp /data/local/tmp/libsudo-game-jni.so data/app/com.example.sudogame-2/lib/arm64
494 # Report how samples distribute inside libsudo-game-jni.so with debug binary
496 $adb shell run-as com.example.sudogame ./simpleperf report -n --dsos /data/app/com.example.sudogame-2/lib/arm64/libsudo-game-jni.so --sort symbol --symfs .
498 Overhead Sample Symbol
499 71.08% 347 checkValid(Board const&, int, int)
500 15.13% 74 randomBlock_r(Board&, int, int, int, int, int)
501 7.94% 38 canFindSolution_r(Board&, int, int)
503 0.30% 2 randomBoard(Board&)
504 0.20% 1 Java_com_example_sudogame_GameModel_findConflictPairs
505 0.14% 1 Java_com_example_sudogame_GameModel_canFindSolution
507 With the help of debug version of libsudo-game-jni.so, the report above shows that most
508 time in libsudo-game-jni.so is spent in function checkValid. So now we can look
511 ### Report samples in one function
513 # Report how samples distribute inside checkValid() function.
514 # adb shell command can’t pass ‘(‘ in arguments, so we run the command
515 # inside `adb shell`.
517 device$ run-as com.example.sudogame ./simpleperf report -n --symbols "checkValid(Board const&, int, int)" --sort vaddr_in_file --symfs .
519 Overhead Sample VaddrInFile
525 The report above shows samples hitting different places inside function
526 checkValid(). By using objdump to disassemble libsudo-game-jni.so, we can find
527 which are the hottest instructions in checkValid() function.
529 # Disassemble libsudo-game-jni.so.
530 $aarch64-linux-android-objdump -d -S -l libsudo-game-jni.so >libsudo-game-jni.asm
532 ## 7. Record and report call graph
533 ### What is a call graph
534 A call graph is a tree showing function call relations. For example, a program
535 starts at main() function, and main() calls functionOne() and functionTwo(),
536 and functionOne() calls functionTwo() and functionThree(). Then the call graph
539 main() -> functionOne()
546 ### Record dwarf based call graph
547 To generate call graph, simpleperf needs to generate call chain for each record.
548 Simpleperf requests kernel to dump user stack and user register set for each
549 record, then it backtraces the user stack to find the function call chain. To
550 parse the call chain, it needs support of dwarf call frame information, which
551 usually resides in .eh_frame or .debug_frame section of the binary. So we need
552 to use --symfs to point out where is libsudo-game-jni.so with debug information.
554 # Record thread 11546 for 30s, use the app while recording it.
555 $adb shell run-as com.example.sudogame ./simpleperf record -t 11546 -g --symfs . --duration 30
556 simpleperf I 01-01 07:13:08 9415 9415 cmd_record.cpp:336] Samples recorded: 65279. Samples lost: 16740.
557 simpleperf W 01-01 07:13:08 9415 9415 cmd_record.cpp:343] Lost 20.4099% of samples, consider increasing mmap_pages(-m), or decreasing sample frequency(-f), or increasing sample period(-c).
559 $adb shell run-as com.example.sudogame ls -lh perf.data
560 -rw-rw-rw- 1 u0_a96 u0_a96 8.3M 2016-01-01 08:49 perf.data
562 Note that kernel can’t dump user stack >= 64K, so the dwarf based call graph
563 doesn’t contain call chains consuming >= 64K stack. So avoiding allocating
564 large memory on stack is a good way to improve dwarf based call graph.
566 ### Record stack frame based call graph
567 Another way to generate call graph is to rely on the kernel parsing the call
568 chain for each record. To make it possible, kernel has to be able to identify
569 the stack frame of each function call. This is not always possible, because
570 compilers can optimize away stack frames, or use a stack frame style not
571 recognized by the kernel. So how well it works depends.
573 # Record thread 11546 for 30s, use the app while recording it.
574 $adb shell run-as com.example.sudogame ./simpleperf record -t 11546 --call-graph fp --symfs . --duration 30
575 simpleperf W 01-02 05:43:24 23277 23277 environment.cpp:485] failed to read /proc/sys/kernel/kptr_restrict: Permission denied
576 simpleperf I 01-02 05:43:54 23277 23277 cmd_record.cpp:323] Samples recorded: 95023. Samples lost: 0.
578 $adb shell run-as com.example.sudogame ls -lh perf.data
579 -rw-rw-rw- 1 u0_a96 u0_a96 39M 2016-01-02 05:43 perf.data
581 ### Report call graph
582 #### Report call graph on device
584 $adb shell run-as com.example.sudogame ./simpleperf report -n -g --symfs .
585 Cmdline: /data/data/com.example.sudogame/simpleperf record -t 11546 -g --symfs . -f 1000 --duration 30
587 Event: cpu-cycles (type 0, config 0)
589 Event count: 41301992088
591 Children Self Sample Command Pid Tid Shared Object Symbol
592 97.98% 0.69% 162 xample.sudogame 11546 11546 /data/app/com.example.sudogame-1/lib/arm64/libsudo-game-jni.so checkValid(Board const&, int, int)
594 -- checkValid(Board const&, int, int)
596 |--99.95%-- __android_log_print
598 | |--92.19%-- __android_log_buf_write
600 | | |--73.50%-- libcutils.so[+1120c]
603 #### Report call graph in callee mode
604 Call graph can be shown in two modes. One is caller mode, showing how functions
605 call others. The other is callee mode, showing how functions are called by
606 others. We can use *-g callee* option to show call graph in callee mode.
609 $host/simpleperf report -n -g callee --symfs .
610 Cmdline: /data/data/com.example.sudogame/simpleperf record -t 11546 -g --symfs . -f 1000 --duration 30
612 Event: cpu-cycles (type 0, config 0)
614 Event count: 41301992088
616 Children Self Sample Command Pid Tid Shared Object Symbol
617 97.58% 0.21% 48 xample.sudogame 11546 11546 /system/lib64/liblog.so __android_log_print
619 -- __android_log_print
621 |--99.70%-- checkValid(Board const&, int, int)
623 | |--99.31%-- canFindSolution_r(Board&, int, int)
626 #### Report using report.py
627 The call graph generated by simpleperf report may be hard to read in text mode.
628 Simpleperf provides a python script showing GUI of call graph.
629 It can be used as below.
631 # Show call graph in GUI.
632 $adb shell run-as com.example.sudogame ./simpleperf report -n -g --symfs . >perf.report
633 $python report.py perf.report
635 # Steps to profile java code on rooted devices
636 Simpleperf only supports profiling native instructions in binaries in ELF
637 format. If the java code is executed by interpreter, or with jit cache, it
638 can’t be profiled by simpleperf. As Android supports Ahead-of-time compilation,
639 it can compile java bytecode into native instructions. We currently need root
640 privilege to force Android fully compiling java code into native instructions
641 in ELF binaries with debug information (this could be fixed by a
642 profileable=”true” in AndroidManifest that causes PackageManager to pass -g to
643 dex2oat). We also need root privilege to read compiled native binaries
644 (because installd writes them to a directory whose uid/gid is system:install).
645 So profiling java code can currently only be done on rooted devices.
647 ## 1. Fully compile java code into native instructions
650 # Restart adb as root. It needs root privilege to setprop below.
652 # Set the property to compile with debug information.
653 $adb shell setprop dalvik.vm.dex2oat-flags -g
655 # Fully compile the app instead of using interpreter or jit.
656 $adb shell cmd package compile -f -m speed com.example.sudogame
658 # Restart the app on device.
662 # Restart adb as root. It needs root privilege to setprop below.
664 # Set the property to compile with debug information.
665 $adb shell setprop dalvik.vm.dex2oat-flags -g
668 $adb install -r app-debug.apk
672 # Restart adb as root. It needs root privilege to setprop below.
674 # Set the property to compile with debug information.
675 $adb shell setprop dalvik.vm.dex2oat-flags --include-debug-symbols
678 $adb install -r app-debug.apk
680 ## 2. Record perf.data
682 # Change to the app’s data directory.
683 $ adb root && adb shell
684 device# cd `run-as com.example.sudogame pwd`
686 # Record as root as simpleperf needs to read the generated native binary.
687 device#./simpleperf record -t 25636 -g --symfs . -f 1000 --duration 30
688 simpleperf I 01-02 07:18:20 27182 27182 cmd_record.cpp:323] Samples recorded: 23552. Samples lost: 39.
690 device#ls -lh perf.data
691 -rw-rw-rw- 1 root root 11M 2016-01-02 07:18 perf.data
693 ## 3. Report perf.data
694 # Report how samples distribute on different binaries.
695 device#./simpleperf report -n --sort dso
696 Cmdline: /data/data/com.example.sudogame/simpleperf record -t 25636 -g --symfs . -f 1000 --duration 30
698 Event: cpu-cycles (type 0, config 0)
700 Event count: 40662494587
702 Overhead Sample Shared Object
703 85.73% 20042 [kernel.kallsyms]
704 9.41% 2198 /system/lib64/libc.so
705 2.29% 535 /system/lib64/libcutils.so
706 0.95% 222 /data/app/com.example.sudogame-1/lib/arm64/libsudo-game-jni.so
708 0.04% 16 /system/lib64/libandroid_runtime.so
709 0.03% 10 /data/app/com.example.sudogame-1/oat/arm64/base.odex
712 As in the report above, there are samples in
713 /data/app/com.example.sudogame-1/oat/arm64/base.odex, which is the native binary
714 compiled from java code.
717 device#./simpleperf report -n -g --symfs .
718 Cmdline: /data/data/com.example.sudogame/simpleperf record -t 25636 -g --symfs . -f 1000 --duration 30
720 Event: cpu-cycles (type 0, config 0)
722 Event count: 40662494587
724 Children Self Sample Command Pid Tid Shared Object Symbol
725 98.32% 0.00% 1 xample.sudogame 25636 25636 /data/app/com.example.sudogame-1/oat/arm64/base.odex void com.example.sudogame.GameModel.reInit()
727 -- void com.example.sudogame.GameModel.reInit()
729 |--98.98%-- boolean com.example.sudogame.GameModel.canFindSolution(int[][])
730 | Java_com_example_sudogame_GameModel_canFindSolution
732 | |--99.93%-- canFindSolution(Board&)
735 As in the report above, reInit() and canFindSolution() are java