Native Client‎ > ‎2: How Tos‎ > ‎

Limited Profiling with Oprofile on x86-64

How to use Oprofile with NaCl on x86-64.

Overview:

Currently, the NaCl loader copies code from nexe files into memory so that changes to the file are not reflected in memory. This is especially important since the code is only validated once, and not every time the file changes. However, this copying can confuse tools like profilers, which do not know how these memory addresses map to the code in the original executable. The good news is, it is still possible to use tools like profilers if there is a tool to map the sampled instruction addresses to functions. There is an experimental script in the native client repository that will do this mapping for you, when using oprofile. Eventually, we will have a cleaner solution.

Limitations: This does not work for the x86-32 sandbox and has not yet been tested with ARM (please update this if it is found to work =)). Also, this does not work with the oprofile "--callgraph" option. It has only been tested with static linking and not dynamic linking with glibc.

Steps:
  • (be sure to have oprofile installed in Linux)
  • Run oprofile and save the samples with "opreport --details" to a log.
  • Disassemble the nexe.
  • Process the log and disassembled code with the script.
This should work with nexes that are loaded through chrome as well as the command-line tool "sel_ldr".

Example:


> sudo opcontrol --reset
> sudo opcontrol --event=CPU_CLK_UNHALTED:100000:0x0:0:1 --no-vmlinux

> sudo opcontrol --start

<< in chrome, get your program running -- say test_nacl64.nexe, which should have symbol information (built with -g) >>
<< wait for "enough" samples to be collected >>

> sudo opcontrol --shutdown
> sudo opreport --details > testlog

> grep "anon" testlog

<< this should show at least one "anon"... look for one that says range:0xZYX..00010000-... and "chrome" or "sel_ldr" or "nacl_helper_bootstrap". Let $B = the actual numeric value of 0xZYX.00010000, but change the 10000 to 00000. For example, $B=0x18a900000000. >>


> objdump -C -d test_nacl64.nexe > test_nacl64.nexe.dump

> native_client/tools/process_oprofile_x86_64.py --oprofilelog testlog --assembly test_nacl64.nexe.dump --untrusted_base $B -o test_nacl64.nexe.annotated

<< Observe output and/or view the annotated assembly dump in test_nacl64.nexe.annotated >>


This will print the top 30 most CPU intensive functions in the untrusted sandbox (the anon region) along with samples in trusted code (e.g., chrome). The script will also generate an annotated output file (test_nacl64.nexe.annotated in the example) that contains the disassembly along with annotations such as:

 2050f: 6b c0 61 imul $0x61,%eax,%eax #; EVENTS: 265

where 265, is the number of samples taken by oprofile for that instruction.

Alternative Ways to Find Base Address

  • Run chrome from the commandline, with the environment variable NACLVERBOSITY set to 1 or higher.  After you load your nacl application, look for debug log output that says "Native Client module will be loaded at base address ...".
  • or, attach a debugger to your nacl application and print the value of the $r15 register.

Where to Find Script

Comments