linguistics, computers, and puns

Load Average for the Masses

Tim Hammerquist September 09, 2012 Updated: October 11, 2023 #c #linux #unix

Some people like CPU meters. I collected them for quite a while myself. At one point I had 4 gkrellm instances on my desktop at once; one local, 3 connected to remote gkrellmd instances. More recently, I've used MenuMeters for this same effect in my OS X menubar.

But I also have quite a lot of terminals open, both local and remote, connected to up to half a dozen or more servers at one time. And I like to watch the cpu load on all of them. What to do?

I've settled on using a system's load average to casually monitor its CPU load. It's a good balance of current and past load, as well as cheap to compute, and cheap to transfer.

Up until recently I've been using shell scripts using cut(1), uname(1), and sysctl(8), or the Linux proc(5) filesystem. While effective, I sometimes worry that their contributions to system load themselves are unnecessarily high. The shell script, shown below, is executed every few seconds by at least one session on every host.

#!/bin/sh

sysname=$(uname -s)

case $sysname in
  *BSD | Darwin )
    sysctl vm.loadavg | cut -d' ' -f3,4,5
    ;;
  Linux)
    cut -d' ' -f1,2,3 < /proc/loadavg
    ;;
  *)
    echo "Unknown system:" "$sysname"
esac

Recently, however, I found myself adding a few Solaris-ish (SmartOS, specifically) machines to my flock and, it occurred to me that the standard getloadavg(3) library call was far more standard than any other method and decided to cut my losses. The result is the following, almost absurdly simple C program. Barely more advanced than the barest of "Hello, world" programs, it still didn't manage to be portable to SmartOS' Solaris-based system. A single #ifdef was added.

Behold.

#include <stdio.h>              /* fprintf */
#include <stdlib.h>             /* getloadavg(FreeBSD, Linux, macOS) */

#if defined(__sun) && defined(__SVR4)
#include <sys/time.h>           /* hrtime_t (used in `sys/loadavg.h`) */
#include <sys/loadavg.h>        /* getloadavg(smartOS) */
#endif

static double Samples[3];

int main(void) {
  getloadavg(Samples, 3);
  printf("%03.2f %03.2f %03.2f\n", Samples[0], Samples[1], Samples[2]);
}

It's a lot cheaper to run than loadavg.sh, and some of my machines are a little limited on resources. But mostly I just wanted to try my hand at a basic system utility.

You can find my loadavg codebase at GitHub.