Thanks to Gabriel Hollies for his help in writing this post

TL;DR: on AWS EC2 M4 instances, calls to System.nanoTime() and System.currentTimeMillis() make system calls, and these system calls are subject to even more overhead when running in Docker due to Docker’s default seccomp profile filters. The new M5 instances no longer make system calls for these time methods, so you can upgrade to newer instances if available in your region and availability zone(s). If you are stuck on 4-series instances, you could switch the clocksource to tsc as Amazon recommends in this tuning FAQ.

Background

Appian uses Docker to run hundreds of thousands of automated tests every day. As we containerized our test applications, we started noticing that some parts of the software ran more slowly in Docker than others. It seemed that extra time was being spent somewhere in native code, so we decided to explore profiling tools that could display system calls and native code in the context of our Java call stacks. One such tool is FlameGraphs.

We found some useful blog posts about generating FlameGraphs for containerized Java: Flame graphs and perf-top for JVMs inside Docker containers and Making FlameGraphs with Containerized Java