Mind the scaling governor while timing code

Here’s a small bit of info that could save you some sweat and tears: when timing your code on Linux, make sure your performance scaling governor is set appropriately.

This came up back when I was trying to do frame synchronization in software for desert train. In general, when you are trying to measure how long a specific portion of your code takes to execute (maybe using something like POSIX’s clock_gettime()), you may see measurements oscillate around multiple points in a strange way, in a multimodal distribution.

In the case I mentioned, and in multiple cases since then, I was measuring the same piece of code that ran the same workload each time. For a few frames, the execution time tripled or even quadrupled, until it went back to the one I would expect for a few frames, moving back and forth between the two.

What I saw was the result of an otherwise useful and desirable behavior of the CPU frequency scaling subsystem of Linux. It seems that each frame (and their succession) took a short enough time to compute that the scaling governor kept dropping the CPU to a lower frequency-voltage configuration. While this is great when you want execution to be efficient, it’s no good for measuring wall-clock time during profiling.

Specifically, this was a result of using the schedutil scaling governor, which implements “scheduler-driven CPU frequency selection”.

Configuration

Before we proceed, I’m going to echo the warning from the related page of the Arch Linux wiki: Use CPU monitoring tools (for temperatures, voltage, etc.) when changing the default governor.

The following is one way to monitor your current core frequencies in real time.

$ watch cat /sys/devices/system/cpu/cpu[0-9]*/cpufreq/scaling_cur_freq

To monitor your temperatures, you could use the following instead.

$ watch cat /sys/class/thermal/thermal_zone*/temp

One way to get consistent timings is to temporarily set the performance governor, which will run the CPU at the maximum frequency set by the scaling_max_freq policy limit. You can activate a governor on every available CPU manually in the following way. If you are not running this as a superuser, you have to add your “super user do” before tee, which, for me, is sudo.

# echo <governor> | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

This setting is temporary, and will reset to the default cpufreq.default_governor kernel option on boot.

Even with these fairly standard tweaks, you shouldn’t just believe random people on the internet about their safety. With that said, I personally only saw my temperatures increase appreciably when I ran a heavier workload, long after I set my scaling governor to performance. The frequencies were consistently higher though, so it may have just come down to cooling.

After you’re done, don’t forget to set it back to your default, to let your processor kick back again.

created

modified