+
+struct load_sample {
+ time_t sample_time;
+ ULONGLONG idle;
+ ULONGLONG kernel;
+ ULONGLONG user;
+};
+
+/* Number of processors on this machine. */
+static unsigned num_of_processors;
+
+/* We maintain 1-sec samples for the last 16 minutes in a circular buffer. */
+static struct load_sample samples[16*60];
+static int first_idx = -1, last_idx = -1;
+static int max_idx = sizeof (samples) / sizeof (samples[0]);
+
+static int
+buf_next (int from)
+{
+ int next_idx = from + 1;
+
+ if (next_idx >= max_idx)
+ next_idx = 0;
+
+ return next_idx;
+}
+
+static int
+buf_prev (int from)
+{
+ int prev_idx = from - 1;
+
+ if (prev_idx < 0)
+ prev_idx = max_idx - 1;
+
+ return prev_idx;
+}
+
+static void
+sample_system_load (ULONGLONG *idle, ULONGLONG *kernel, ULONGLONG *user)
+{
+ SYSTEM_INFO sysinfo;
+ FILETIME ft_idle, ft_user, ft_kernel;
+
+ /* Initialize the number of processors on this machine. */
+ if (num_of_processors <= 0)
+ {
+ get_native_system_info (&sysinfo);
+ num_of_processors = sysinfo.dwNumberOfProcessors;
+ if (num_of_processors <= 0)
+ {
+ GetSystemInfo (&sysinfo);
+ num_of_processors = sysinfo.dwNumberOfProcessors;
+ }
+ if (num_of_processors <= 0)
+ num_of_processors = 1;
+ }
+
+ /* TODO: Take into account threads that are ready to run, by
+ sampling the "\System\Processor Queue Length" performance
+ counter. The code below accounts only for threads that are
+ actually running. */
+
+ if (get_system_times (&ft_idle, &ft_kernel, &ft_user))
+ {
+ ULARGE_INTEGER uidle, ukernel, uuser;
+
+ memcpy (&uidle, &ft_idle, sizeof (ft_idle));
+ memcpy (&ukernel, &ft_kernel, sizeof (ft_kernel));
+ memcpy (&uuser, &ft_user, sizeof (ft_user));
+ *idle = uidle.QuadPart;
+ *kernel = ukernel.QuadPart;
+ *user = uuser.QuadPart;
+ }
+ else
+ {
+ *idle = 0;
+ *kernel = 0;
+ *user = 0;
+ }
+}
+
+/* Produce the load average for a given time interval, using the
+ samples in the samples[] array. WHICH can be 0, 1, or 2, meaning
+ 1-minute, 5-minute, or 15-minute average, respectively. */
+static double
+getavg (int which)
+{
+ double retval = -1.0;
+ double tdiff;
+ int idx;
+ double span = (which == 0 ? 1.0 : (which == 1 ? 5.0 : 15.0)) * 60;
+ time_t now = samples[last_idx].sample_time;
+
+ if (first_idx != last_idx)
+ {
+ for (idx = buf_prev (last_idx); ; idx = buf_prev (idx))
+ {
+ tdiff = difftime (now, samples[idx].sample_time);
+ if (tdiff >= span - 2*DBL_EPSILON*now)
+ {
+ long double sys =
+ samples[last_idx].kernel + samples[last_idx].user
+ - (samples[idx].kernel + samples[idx].user);
+ long double idl = samples[last_idx].idle - samples[idx].idle;
+
+ retval = (1.0 - idl / sys) * num_of_processors;
+ break;
+ }
+ if (idx == first_idx)
+ break;
+ }
+ }
+
+ return retval;
+}
+