Java Build Benchmarks with Apple M1

Sat, 21 Nov 2020 12:15:00 GMT

Tags: #java #applesilicon #mac

I compare an iMac Pro, Macbook Pro, Macbook Air 2020 M1 for a common Gradle Java build.

iMac Pro 2017

CharacteristicValue
Model NameiMac Pro 2017
Processor3GHz 10-Core Intel Xeon W
Memory32 GB 2666 MHz DDR4
Total Number of Cores10
Operating SystemMac OS X 10.15.7 (Mojave)

Macbook Pro 2014

CharacteristicValue
Model NameMacBook Pro (Retina, 13-inch, Mid 2014)
Processor3 GHz Dual-Core Intel Core i7
Memory16 GB 1600 MHz DDR3
Total Number of Cores2
Operating SystemMac OS X 10.15.7 (Mojave)

Macbook Air 2020 M1

CharacteristicValue
Model NameMacBook Air
ProcessorM1 2020
Memory16 GB
CPU cores8 cores
Operating systemMac OS X 10.16

Java version

Micronaut is still JDK 8 compatible. I run the tests with Corretto 8 JDK. I installed it via SDKMan.

% sdk install java 8.0.275-amzn
CharacteristicValue
Java runtimeAmazon.com Inc. OpenJDK Runtime Environment 1.8.0_275-b01
Java VMAmazon.com Inc. OpenJDK 64-Bit Server VM 25.275-b01 (mixed mode)

Code sample

I use Micronaut Security module.

Command

I run the Gradle build task which compiles the code, runs the tests and checksytle. It is one of the most common tasks.

% ./gradlew clean;./gradlew -Dtestcontainers=false build 
    --no-daemon
    --no-build-cache 
    -x dependencyUpdates 
    --parallel 
    --scan

I supply some arguments:

  • I use --no-build-cache because I want to have an easy way to compare between machines. I use Gradle build cache in my projects. It is a great feature. You should use it.

  • I disable the Gradle Daemon with --no-daemon. For the same reasons as in the previous item, to compare different machines in the fairest way.

  • I skip the task dependencyUpdates as it may add inconsistency to the test.

  • I ignore tests which required Docker (which does not run with Apple M1), hence the argument -Dtestcontainers=false.

  • I use Gradle Parallel execution with --parallel flag.

Most builds consist of more than one project and some of those projects are usually independent of one another. Yet Gradle will only run one task at a time by default, regardless of the project structure (this will be improved soon). By using the --parallel switch, you can force Gradle to execute tasks in parallel as long as those tasks are in different projects.

Results

ComputerDurationGradle Build Scan
iMac Pro - 3GHz 10 Core Intel Xeon W1m 44sGradle Build Scan
Macbook Air M1 8 Core2m 54sGradle Build Scan
Macbook Pro 2 Core 3GHz I74m 33sGradle Build Scan

Caveats

This is not an empirical comparison. The goal of the post is to put in numbers my feelings. Java builds are fast in a Macbook Air M1.

These benchmarks should have been calculated with the Gradle Profiler. However, I was not able to get the Gradle Profiler to run with the M1 computer.

Don't consider this post as a measurement Micronaut security's build performance.

Neither, it is intended to showcase of Gradle's performance. It will be unfair for Gradle. I explicitly disabled several features (Build Cache, Daemon) which make Gradle builds much faster.

Conclusion

  • My 2017 iMac Pro, a powerhouse, still beats an Macbook Air M1.
  • The Macbook Air M1 smokes old Macbook Pros.
  • Macbook Air M1 will get you similar Java build times for current top of the line Macbook Pros.

The exciting thing is that Java builds are not taking full advantage of the transition. It is Rosetta emulation:

the Java runtime support will run under Rosetta 2 which will translate Intel compiled code to run on Apple Silicon. The Java Virtual Machine will need to be recompiled for Apple Silicon to fully utilize its power, but Java based applications should continue to run as expected on both Intel and Apple Silicon hardware.

Once the Java story improves in Apple silicon, I will write about it. I am thrilled.