Hi chromium java users,
On a recent CL the topic of which time source is best suited for various timing tasks came up. As it stands, we use three different time sources, at least on Android:
SystemClock.elapsedRealTime - monotonic wall time, millisecond resolution
SystemClock.elapsedRealTimeNanos - monotonic wall time, nanosecond resolution
As I see it, there are two issues with the current setup:
1) People are still using currentTImeMillis for interval timing
2) We only ever measure wall time
1) is explained sufficiently above but 2) is worth expanding on. If your thread of interest blocks for I/O or is preempted for stop the world GC, wall time will continue to advance, but the CPU isn't doing any work. Sometimes this is what you want to measure ("I care about the user-visible time it takes to fetch the data, de-serialize it, and render a widget") but sometimes it's not ("I want to know how computationally expensive this measure() call is").
For this reason, I think we should consider adopting SystemClock.currentThreadTimeMillis and Debug.threadCpuTimeNanos, which measure only single-threaded CPU time. If I understand correctly, the underlying time source for these functions, CLOCK_THREAD_CPUTIME_ID, is already used for measuring thread CPU time in TraceEvent. There is some inconsistency on what, if any, I/O time is counted by this clock; the android documentation for threadCpuTimeNanos states "The value returned indicates the amount of time that the current thread has spent executing code or waiting for certain types of I/O" but doesn't say which kinds of I/O. If I had to guess, it includes kernel time spent processing I/O but not actual time spent blocking.
Alongside this adoption maybe we should write a markdown file with formalized best practices for interval timing? It would describe when you'd want to use the various time sources. This could even become a class in base/ that implements the best practices and has descriptive function names.
My first attempt at the guidelines would go like so:
"I just want to spot check how long something takes locally; I don't need telemetry"
You can probably just use TraceEvent.
"I want to measure user visible time, including things like I/O and thread pre-emption"
Use SystemClock.elapsedRealTime for longer (>10ms) tasks and SystemClock.elapsedRealTimeNanos for shorter tasks.
"I want to measure elapsed CPU time for some potentially expensive operation, ignoring things like I/O and thread pre-emption"
Use currentThreadTimeMillis for longer (>10ms) tasks and threadCpuTimeNanos for shorter tasks.
Please let me know what you think, especially if you have more information about how the various clocks work or opinions about when they should be used.