/* GPL (includes a few bits from the linux kernel) */ /* gcc -lm loadavg.c */ #include #include #include #include #include #include #include #include /* gets SI_LOAD_SHIFT 16 from linux/kernel.h */ #include #define HZ 100 /* linux-2.6.32.27/include/linux/sched.h */ #define FSHIFT 11 /* nr of bits of precision */ #define FIXED_1 (1<>= FSHIFT; /* linux-2.6.32.27/kernel/sched.c */ static unsigned long calc_load(unsigned long load, unsigned long exp, unsigned long active) { load *= exp; load += active * (FIXED_1 - exp); return load >> FSHIFT; } /* fs/proc/loadavg.c */ #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) /* end from kernel */ #define OUTSECS 5 /* length of rrd output interval */ #define OUTTICKS (100*OUTSECS) /* we assume HZ 100 regardless of actual value */ static int fakeload; /* first fakeload ticks per sec have load 1 */ static int intervals = 720; /* 1 hour at 5 sec intervals */ static int load_freq = 461; /* freq at which we probe */ static int printick; /* print each nth tick */ static unsigned long load, fload, pload; /* computed, fakeload, printload */ static long long nextmsec; static double kload; /* kernel load */ static int basetime = 946684805; /* 1.1.2000 UTC + 5 sec, rrdtool refuses <1980 */ static int exp_1 = 1896; /* for 13 probes/min: 1896 2017 2038 */ int main (int argc, char **argv) { struct timeval tv; int tick = 0, i,t,m,probesmin; while (--argc && '-' == **++argv) switch ((*argv)[1]) { case 'i': intervals = atoi((*argv)+2); break; /* -i1440 */ case 'f': load_freq = atoi((*argv)+2); break; /* -f501 */ case 'l': fakeload = atoi((*argv)+2); break; /* -l30 */ case 'p': printick = atoi((*argv)+2); break; /* -p1 */ case 'b': basetime = atoi((*argv)+2); break; /* -b0 */ case 'e': probesmin = atoi((*argv)+2); /* -e13 */ exp_1 = round(FIXED_1 / exp(1./probesmin)); fprintf(stderr, "EXP_1 %d %d %d\n", exp_1, (int)round(FIXED_1 / exp(1./5/probesmin)), (int)round(FIXED_1 / exp(1./15/probesmin))); } gettimeofday(&tv, 0); nextmsec = tv.tv_sec*1000 + tv.tv_usec/1000 + 1; if (!basetime) basetime = OUTSECS*(tv.tv_sec/OUTSECS); for (i=0; i(t%100) ? 1 : 0; tickload = 10*curload; if (!(tick % LOAD_FREQ)) { fload = calc_load(fload, EXP_1, curload*FIXED_1); kload = (double)fload/FIXED_1; } } else { /* take 10 msec probes */ int runnable; double kl5, kl15; tickload = 0; for (m=10; m--; nextmsec++) { char buf[100]; int f; long long udiff; gettimeofday(&tv, 0); udiff = nextmsec*1000 - tv.tv_sec*1000000 - tv.tv_usec; if (0 < udiff) usleep((__useconds_t)udiff); /* sysinfo has the loads but not runnable processes */ f = open("/proc/loadavg", O_RDONLY); read(f, buf, sizeof buf); close(f); sscanf(buf, "%lf %lf %lf %d", &kload, &kl5, &kl15, &runnable); tickload += runnable - 1; /* do not count this process */ } curload = runnable - 1; } sumload += tickload; if (!(tick % load_freq)) load = calc_load(load, exp_1, curload*FIXED_1); if (printick && !(t % printick)) fprintf(stderr, "%d\t%.3f\t%lu.%03lu\t%.2f\n", tick, tickload/10., LOAD_INT(load), LOAD_INT(((load) & (FIXED_1-1)) * 1000), kload ); } pload = load + FIXED_1/200; /* +0.5% as in fs/proc/loadavg.c get_avenrun */ printf("update loadavg.rrd %d:%.3f:%lu.%02lu:%.2f\n", basetime + i*OUTSECS, sumload/(OUTSECS*1000.), /* real interval load on msec basis */ LOAD_INT(pload), LOAD_FRAC(pload), kload ); } /* for intervals */ return 0; }