I’m super into measuring CPU time. If you have a slow program, the first thing you want to know is whether your program is spending that time calculating things on the CPU, or whether it’s waiting for something else (a disk, a network, user input).
At work yesterday, someone sent an email saying “Hey we’re measuring how much CPU time every HTTP request takes now!”. I didn’t know how to accomplish what they said they’d just done. So I asked “hey how does that work?”. Here’s the answer.
It turns out that if you’re a HTTP server, and you want to know exactly how much CPU time your HTTP requests are taking, you can just ask the Linux kernel!
On Linux, there’s a system call (and corresponding libc function) called
clock_gettime. I’d seen this system call before, but I thought it was only for getting the time, like 5:03pm. Not so! Here are the flags you can send to
clock_gettime on my system. (from
CLOCK_REALTIME System-wide real-time clock. Setting this clock requires appropriate privileges. CLOCK_MONOTONIC Clock that cannot be set and represents monotonic time since some unspecified starting point. CLOCK_MONOTONIC_RAW (since Linux 2.6.28; Linux-specific) Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjust‐ ments. CLOCK_PROCESS_CPUTIME_ID High-resolution per-process timer from the CPU. CLOCK_THREAD_CPUTIME_ID Thread-specific CPU-time clock.
So if you ask your kernel for
CLOCK_PROCESS_CPUTIME_ID, it will tell you how much CPU time has passed since your program started. This is awesome, because you can run
start_time = clock_gettime(CLOCK_PROCESS_CPUTIME_ID) do_maybe_expensive_thing end_time = clock_gettime(CLOCK_PROCESS_CPUTIME_ID) print "elapsed CPU time:", end_time - start_time
And you can call clock_gettime from Ruby to understand your Ruby performance!. System calls aren’t just for C hackers, they’re for everyone.
In hindsight, it makes sense to me that Linux keeps track of the CPU time spent
ps aux reports how much CPU time every program on your system has
used (in the
TIME column), and if you time a program with
time, it reports
the total time, userspace CPU time, and kernel CPU time separately.
It’s also interesting that this system call lets you get a monotonic time – that seems useful if you want a notion of time that doesn’t go back in time.