Skip to content

Motivation

Brian Attwell edited this page Apr 18, 2018 · 18 revisions

Nanoscope is optimized to provide extremely low profiling overhead and complete instrumentation. When you use Nanoscope you can see an accurate picture of every single java method in your app and framework.

Nanoscope requires installing a custom ROM. By making this tradeoff, Nanoscope could be built in a way that only adds percentage points of overhead and exposes additional OS metadata. Nanoscope makes it easy to answer questions about local app builds such as the following:

  1. Why is my ExpermentManager.isTreated() call, which I execute thousands of times a second, always 20us slower than I expect?
  2. Why does it take so long to instantiate a Dagger component when the component's constructor is basically empty?
  3. Why are my TextView’s being inflated slowly?

Comparisons

Lots of existing profilers exist. Why write a new one? Because existing profilers don't allow us to quickly answer all of the the above questions when used during local development.

Android Studio's Instrumentation

Android Studio's instrumentation is built in a way that minimizes its overhead when it isn't being used. This is a smart tradeoff since instrumentation code is shipped as a part of every single phone regardless of whether the phones are ever used for debugging performance.

However, when the instrumentation is enabled on an application it prevents all JIT/AOT compiled code from running. Ie, your app runs using a line-by-line interpreter. This makes your app a couple times slower. In addition to this, for every single java method that is instrumented hundreds of additional C++ lines are executed (some example lines). The overall effect: your application runs an order of magnitude slower when using the instrumentation that is built into AOSP. You can see this in the following figure.

Android Studio comparison

This makes Android Studio's instrumentation unsuitable for answering the questions posted at the top of this page.

Sampling

To illustrate the problems with sampling, imagine we want to instrument the behavior of some example function call.

Accurately tracing the behavior of this example function and its subfunctions requires 40 measurements if you use function tracing. This is shown below.

Accurate tracing

Now, instead imagine we wanted to instrument this function using sampling. If we want a similar amount of information, we must sample at a period at least as high as the above tracing example. The following figure shows the information we gather from this. In this figure, the function timing is only a little distorted. We only miss a few subfunction calls.

Accurate sampling

In practice the sampling period cannot be as small as the instrumentation period. Consider the work that needs to be done to obtain each measurement:

  • Tracing: Store a reference to the function name. Read from a virtual register to obtain a timestamp and store it.
  • Sampling: Read and store the function name then recursively lookup the parent function and analyze it. Store all these function names. Read from a virtual register to obtain a timestamp and store it.

Each measurement is roughly STACK_DEPTH times more expensive in an efficient sampling implementation then an efficient tracing implementation. Therefore, in order to avoid significantly slowing down the program when using sampling we must perform significantly less measurements. The following diagram demonstrates the information we receive if we sample avg(STACK_DEPTH) times slower.

Accurate sampling

We receive a less useful information in a single sampling run than a single tracing run. This makes sampling inconvenient for local usage during development or quick local analysis.

Application Layer Instrumention

You could instrument your own method calls directly inside your app. If you wanted to do this in a scalable way you could write a bytecode transform that adds instrumentation into every single method within your app as a build step (ex1, ex2).

However, instrumentation that is built into your app can not instrument method calls within the Android frameworks since you have no way to modify the app frameworks. They aren't included as a part of your app's binary.

This makes app layer instrumentation unsuitable for answering question (3) posted at the top of this page.

Clone this wiki locally