The most efficient way to waste time
In profiling CPU Usage, I need to get my CPUs busy so that the CPU-usage views have something to do. This means that I need a program to busy-wait.
Busy-waiting means running a tight loop that doesn’t actually do anything except run. In C, the most efficient such loop is:
for(;;);
That’s all well and good, but it only busy-waits a single processor. I have four, and I need 1 < n < 4 of them to be lit up so that CPU Usage has something to indicate (otherwise it will sit there showing 0-0-0-0, which doesn’t make good profiling—busy processors will jump around a bit, which gives CPU Usage something to do).
Now, my first approach was to write this in Python. That’s my go-to language for anything without a GUI. Here’s what came out:
#!/usr/bin/env python def busy_wait(): from itertools import repeat for x in repeat(None): pass import thread, sys try: num_threads = int(sys.argv[1]) except IndexError: num_threads = 100 for i in xrange(1, num_threads): #We'll do the first one ourselves after starting all the other threads. throwaway = thread.start_new_thread(busy_wait, ()) busy_wait()
Looks good, right?
What was weird is that I couldn’t seem to get it to max out all my processors, even with num_threads=5000. That seemed mighty suspicious.
It was then that I remembered the Global Interpreter Lock.
You see, in CPython, only one thread can be running Python code at a time. (Exceptions exist for things like I/O, of which my program contains none.) This means that my yummy multithreaded busy-wait program—being purely Python—was effectively running single-threaded.
I reimplemented the program in pure C. Not only does it run much more efficiently now (no interpreter overhead), but it also requires far fewer threads: Four threads will light up all four processors. Victory!
If you want a copy for yourself, here it is. It takes one argument, being the number of threads to spawn. It defaults to the number of logical CPUs in your machine (HW_CPU
in sysctl), so if you just run it with no arguments, it will will spawn one thread per processor.
May 18th, 2007 at 11:26:18
Try this in a Terminal window:
yes > /dev/null
That’ll max out one of your cores. You’ll have to open up multiple Terminal windows if you want to max them all out.
May 18th, 2007 at 11:53:43
Or just do yes > /dev/null& and use one window