GPU-accelerated emulator.wtf

2023-07-04
4 min read

TL;DR: Add gpu=auto to your test invokes to use GPU-accelerated emulators for a potential ~2x speedup in your tests.

emulator.wtf now has emulators that use GPU-acceleration! They use our server’s GPU resources, which makes UI tests quicker by handling draw requests with the host GPU. We’ve also redirected the remaining CPU cores to the emulator - enabling GPU-acceleration doesn’t just make things render faster, it also helps improve CPU processing power, particularly for tasks that use multiple threads.

This results in both time and cost savings as you’ll be able to run your tests quicker while spending less money on emulator-hours.

Closer look at performance

Not all tests get a full benefit from GPU-acceleration — a Thread.sleep(1000) will take at least a full second regardless of the hardware or software you’re running it on. On the other hand tests tapping into UI rendering or multiple threads should see a substantial speed-up.

To estimate the impact of GPU-acceleration we ran three separate test suites with both GPU-acceleration enabled and disabled:

  • a CPU-heavy single-threaded test
  • a CPU-heavy multithreaded test
  • a typical UI instrumentation test

Rough relative test runtimes (lower is better) for these three suites:

Graph of gpu-acceleration speed-up, showing roughly similar test times for single threaded workloads and a substantial 2x speedup for multiple threads and typical UI tests
Relative test runtimes with and without GPU-acceleration, lower is better, baseline is without GPU

We can see the effects of GPU-acceleration in three distinct scenarios. For a single-threaded CPU bound test the improvements are marginal. Multithreaded workloads see a massive improvements due to us being able to allocate more CPU threads to the emulator and your tests.

Finally, for a real-life benchmark of integration tests driving a UI we see a good improvement due to offloading the rendering tasks to GPU while leaving more CPU resources available for asynchronous background tasks like garbage collection.

The tests we used:

  • For measuring CPU performance we created both single and concurrent variants of generating and summing primes. The code is naive and built to pin CPU usage to 100% while also generating lots of garbage. Here’s the source.
  • For measuring UI tests we used the :app module tests from the nowinandroid project.

Caveats

There are several factors to bear in mind before opting for GPU-acceleration in your tests.

Each test has its unique needs! For instance, if your tests make liberal use Thread.sleep and wait for specific conditions, the benefits from GPU-acceleration might be minimal. Likewise, if your tests primarily consist of unit tests that are restricted by single-threaded CPU performance, the gains might be modest at best. Conversely, for a standard integration UI test involving substantial rendering, navigation, and so forth, you could anticipate approximately a ~2x speed up in test execution times.

Although GPU acceleration is available across all our emulator models, there’s a current exception for API 33 and 34. We need a bit more time to ensure these two versions operate seamlessly with the acceleration. We didn’t want to delay other versions’ benefits while we iron out these kinks.

And remember, there could be genuine scenarios where disabling GPU-acceleration is desirable. Take screenshot tests as an example: you might want to execute these with gpu=software and also turn off host GPU acceleration on your local emulators during development. This approach ensures stable and comparable screenshots between the screenshots captured locally and the ones captured during CI, regardless of the GPU in use.

Enabling GPU-acceleration

While GPU-acceleration is opt-in today we will enable this by default in the future. Give this a try today by adding gpu=auto to your test invokes. Here’s three quick examples on how to enable GPU-acceleration for a given integration.

When using ew-cli:

ew-cli --device model=Pixel7,version=31,gpu=auto ...

Or our Gradle plugin:

emulatorwtf {
    devices = [
        [model: "Pixel7", version: 31, gpu: "auto"]
    ]
    // ...
}

Or the GitHub Action:

devices: |
  model=Pixel7,version=31,gpu=auto
# ...

Inversely, if you want to disable GPU-acceleration — say, for predictable screenshot tests — specify gpu=software instead of gpu=auto.


Overall we’re really excited about the possible performance gains and cost savings with GPU-acceleration. Give this a go and let us know whether you saw similar gains as we did! You can reach us either via Twitter or the emulator.wtf community Slack.

Avatar

Madis Pink

Emu herder at emulator.wtf