Closed Bug 1457481 Opened 6 years ago Closed 6 years ago

Add nsIProfiler.GetSymbolTable and implement it in C++ / rust in order to obtain symbol tables from system libraries on Android

Categories

(Core :: Gecko Profiler, enhancement, P1)

enhancement

Tracking

()

RESOLVED FIXED
mozilla64
Tracking Status
firefox61 --- wontfix
firefox62 --- wontfix
firefox63 --- wontfix
firefox64 --- fixed

People

(Reporter: mstange, Assigned: mstange)

References

(Blocks 1 open bug)

Details

Attachments

(4 files)

The primary motivation for this is to have the ability to dump symbol tables from system libraries on Android, on the device itself.

Rather than transmitting the system library files to a Desktop machine and extracting their symbol table there, we can ship a bit of code in the Firefox binary which knows how to extract symbols from ELF object files (for example using the rust "object" crate) without the need for a command line tool like nm. Then, when you profile Firefox for Android using the new devtools performance panel on a desktop machine, we can call nsIProfiler.GetSymbolTable on the device and transmit the symbol table over to the desktop machine.

This also allows for a profiling workflow that doesn't involve a connection to a desktop machine at all. This is something that Ehsan has proposed: We could have an add-on for Firefox for Android which only knows how to record, symbolicate and upload profiles, but not display them. That way you'd be able to record profiles on your phone on the go, without a desktop machine around, and then inspect the collected profiles later. In that scenario, symbolication of system libraries would happen on the phone, and symbolication of libxul would happen in perf.html (using the mozilla symbol server) once you look at the collected profile in your desktop browser.

Having symbolication code in the platform also enables the following use cases:
 - Symbolication of system libraries on macOS on machines that don't have Xcode installed and thus don't have "nm"
 - Getting inline stacks from debug information on macOS and linux, using the addr2line crate (includes file + line number information)
 - Getting symbol information on Windows using msdia*.dll, which would be a lot faster than waiting for dump_syms
 - Getting inline stacks from debug information on Windows, also using msdia*.dll, without having to wait for the rust pdb crate to add support for the relevant information
Blocks: 1456606
Blocks: 1444893
Priority: -- → P1
Depends on: 1484488
I am going to implement this for Android only for now. That's the only place where we don't get any support from the OS to obtain symbol tables. There's no nm binary on the phone.
Blocks: 1446574
Summary: Add nsIProfiler.GetSymbolTable and implement it in C++ / rust → Add nsIProfiler.GetSymbolTable and implement it in C++ / rust in order to obtain symbol tables from system libraries on Android
This will be used to conditionally compile the rust code for ELF binary parsing,
which will be used by the profiler to dump symbols from system libraries on
Android.

Ideally I'd like to make this only apply to Nightly + Beta configurations, and
not to Release, but there doesn't seem to be an easy way to differentiate
between Beta and Release and doing so might be frowned upon. So now it's going
to be built on all channels on Android, even Release, even though developers
won't be profiling Release channel builds much, and the extra code size isn't
all that valuable for our users.

We definitely need this code to be included on the Beta channel, though, because
Firefox Focus Nightly uses GeckoView from the Beta channel, and we want to get
good profiling information from Focus.
r?njn for the profiler parts
r?jrmuizel for the ELF parsing parts

Depends on D7020
Most importantly, this picks up "object" and "goblin" for ELF binary parsing.
We only use the ELF code from goblin, so the mach-O parsing code gets
eliminated by the linker. Overall, this increases the Android installer size
by 20KB.

Try pushes for reference:
before: https://treeherder.mozilla.org/#/jobs?repo=try&revision=834b56dc5ab3d63a43a32f740ee8212296ac726d&selectedJob=201600899
after: https://treeherder.mozilla.org/#/jobs?repo=try&revision=6983b27e8d3cb715d3b7e6cbd276683f6466e3cc&selectedJob=201600475

installer size: 34524820 -> 34542861 (34.52MB -> 34.54MB)

$ mach vendor rust
    Updating registry `https://github.com/rust-lang/crates.io-index`
      Adding goblin v0.0.17
      Adding memmap v0.6.2
      Adding miniz-sys v0.1.10
      Adding object v0.10.0
      Adding parity-wasm v0.31.3
      Adding plain v0.2.3
      Adding profiler_helper v0.1.0 (file:///Users/mstange/code/mozilla/tools/profiler/rust-helper)
      Adding scroll v0.9.1
      Adding scroll_derive v0.9.5
      Adding syn v0.15.5
      Adding thin-vec v0.1.0
      Adding uuid v0.6.5
 0:30.11 The following files exceed the filesize limit of 102400:

third_party/rust/miniz-sys/miniz.c
third_party/rust/syn-0.14.6/src/expr.rs
third_party/rust/syn-0.14.6/src/gen/fold.rs
third_party/rust/syn-0.14.6/src/gen/visit.rs
third_party/rust/syn-0.14.6/src/gen/visit_mut.rs

The syn dependency is not compiled for goblin, as far as I can tell - it's only
needed for the 'syn' feature of scroll_derive, and scroll does not ask for
scroll_derive/syn.

object -> goblin -> scroll -> scroll_derive -/-> syn

But it looks like other versions of syn were already in the tree.

Depends on D7021
Here's a profile obtained from my Android phone using a macOS build that includes the last patch on a GeckoView-example.apk from this try build: https://treeherder.mozilla.org/#/jobs?repo=try&revision=6983b27e8d3cb715d3b7e6cbd276683f6466e3cc&selectedJob=201600475

http://bit.ly/2Q9g0OI

It has full symbols for both libxul.so and for system libraries, for example libESXGLESv2_adreno.so.
Comment on attachment 9012410 [details]
Bug 1457481 - Add nsIProfiler.GetSymbolTable and a profiler/rust-helper crate which implements it for ELF binaries. r?njn,jrmuizel

Nicholas Nethercote [:njn] has approved the revision.
Attachment #9012410 - Flags: review+
Comment on attachment 9012407 [details]
Bug 1457481 - Add a MOZ_GECKO_PROFILER_PARSE_ELF define that's only true on Android.

Ted Mielczarek [:ted] [:ted.mielczarek] has approved the revision.
Attachment #9012407 - Flags: review+
Here's what I did compared to my initial implementation in order to cut down on code size:
 - I made it Android-only
 - I removed the demangling code, which saved about 200KB in binary size. Instead, demangling is now performed by perf.html (we added a WebAssembly module to it which does C++ and rust demangling).
 - I "forked" the ELF binary ID divination code from https://github.com/getsentry/symbolic/blob/master/debuginfo/src/elf.rs in order to eliminate the dependencies regex, symbolic-common/with_dwarf, and others

The biggest remaining factor seems to be the binary parsing code in goblin, which uses scroll's Pread, which seems to generate more code than necessary because it does bounds checks and copies per element instead of per known-size struct. Jeff filed https://github.com/m4b/scroll_derive/issues/8 about this problem.
Comment on attachment 9012412 [details]
Bug 1457481 - Run mach vendor rust. r?froydnj,erahm

Nathan Froyd [:froydnj] has approved the revision.
Attachment #9012412 - Flags: review+
Comment on attachment 9012413 [details]
Bug 1457481 - Hook up the new devtools performance panel to nsIProfiler.getSymbolTable. r?gregtatum

Greg Tatum [:gregtatum] has approved the revision.
Attachment #9012413 - Flags: review+
Comment on attachment 9012410 [details]
Bug 1457481 - Add nsIProfiler.GetSymbolTable and a profiler/rust-helper crate which implements it for ELF binaries. r?njn,jrmuizel

Jeff Muizelaar [:jrmuizel] has approved the revision.
Attachment #9012410 - Flags: review+
Comment on attachment 9012412 [details]
Bug 1457481 - Run mach vendor rust. r?froydnj,erahm

Eric Rahm [:erahm] has approved the revision.
Attachment #9012412 - Flags: review+
Pushed by mstange@themasta.com:
https://hg.mozilla.org/integration/autoland/rev/1c8460b1d6da
Add a MOZ_GECKO_PROFILER_PARSE_ELF define that's only true on Android. r=ted
https://hg.mozilla.org/integration/autoland/rev/4478820fbcaa
Add nsIProfiler.GetSymbolTable and a profiler/rust-helper crate which implements it for ELF binaries. r=njn,jrmuizel
https://hg.mozilla.org/integration/autoland/rev/ac3deff9340f
Run mach vendor rust. r=froydnj,erahm
https://hg.mozilla.org/integration/autoland/rev/212450f77860
Hook up the new devtools performance panel to nsIProfiler.getSymbolTable. r=gregtatum
Backout by shindli@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/00eb79fc9f8a
Backed out 4 changesets for c1 failures in devtools/client/performance-new/test/chrome/test_perf-settings-entries.html
Pushed by mstange@themasta.com:
https://hg.mozilla.org/integration/autoland/rev/7c0eb6f58c1c
Add a MOZ_GECKO_PROFILER_PARSE_ELF define that's only true on Android. r=ted
https://hg.mozilla.org/integration/autoland/rev/7566a6bac33d
Add nsIProfiler.GetSymbolTable and a profiler/rust-helper crate which implements it for ELF binaries. r=njn,jrmuizel
https://hg.mozilla.org/integration/autoland/rev/255e04ebe3bd
Run mach vendor rust. r=froydnj,erahm
https://hg.mozilla.org/integration/autoland/rev/c4a515cf1d8f
Hook up the new devtools performance panel to nsIProfiler.getSymbolTable. r=gregtatum
Flags: needinfo?(mstange)
Depends on: 1505719
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: