diff options
Diffstat (limited to 'multiload/linux-proc.c')
-rw-r--r-- | multiload/linux-proc.c | 406 |
1 files changed, 406 insertions, 0 deletions
diff --git a/multiload/linux-proc.c b/multiload/linux-proc.c new file mode 100644 index 00000000..e1687224 --- /dev/null +++ b/multiload/linux-proc.c @@ -0,0 +1,406 @@ +/* From wmload.c, v0.9.2, licensed under the GPL. */ +#include <config.h> +#include <sys/types.h> +#include <math.h> +#include <fcntl.h> +#include <unistd.h> + +#include <glibtop.h> +#include <glibtop/cpu.h> +#include <glibtop/mem.h> +#include <glibtop/swap.h> +#include <glibtop/loadavg.h> +#include <glibtop/netload.h> +#include <glibtop/netlist.h> +#include <glibtop/mountlist.h> +#include <glibtop/fsusage.h> + +#include "linux-proc.h" +#include "autoscaler.h" + +static const unsigned needed_cpu_flags = +(1 << GLIBTOP_CPU_USER) + +(1 << GLIBTOP_CPU_IDLE) + +(1 << GLIBTOP_CPU_SYS) + +(1 << GLIBTOP_CPU_NICE); + +#if 0 +static const unsigned needed_page_flags = +(1 << GLIBTOP_SWAP_PAGEIN) + +(1 << GLIBTOP_SWAP_PAGEOUT); +#endif + +static const unsigned needed_mem_flags = +(1 << GLIBTOP_MEM_USED) + +(1 << GLIBTOP_MEM_FREE); + +static const unsigned needed_swap_flags = +(1 << GLIBTOP_SWAP_USED) + +(1 << GLIBTOP_SWAP_FREE); + +static const unsigned needed_loadavg_flags = +(1 << GLIBTOP_LOADAVG_LOADAVG); + +static const unsigned needed_netload_flags = +(1 << GLIBTOP_NETLOAD_IF_FLAGS) + +(1 << GLIBTOP_NETLOAD_BYTES_TOTAL); + + +void +GetLoad (int Maximum, int data [5], LoadGraph *g) +{ + int usr, nice, sys, iowait, free; + int total; + + glibtop_cpu cpu; + + glibtop_get_cpu (&cpu); + + g_return_if_fail ((cpu.flags & needed_cpu_flags) == needed_cpu_flags); + + g->cpu_time [0] = cpu.user; + g->cpu_time [1] = cpu.nice; + g->cpu_time [2] = cpu.sys; + g->cpu_time [3] = cpu.iowait + cpu.irq + cpu.softirq; + g->cpu_time [4] = cpu.idle; + + if (!g->cpu_initialized) { + memcpy (g->cpu_last, g->cpu_time, sizeof (g->cpu_last)); + g->cpu_initialized = 1; + } + + usr = g->cpu_time [0] - g->cpu_last [0]; + nice = g->cpu_time [1] - g->cpu_last [1]; + sys = g->cpu_time [2] - g->cpu_last [2]; + iowait = g->cpu_time [3] - g->cpu_last [3]; + free = g->cpu_time [4] - g->cpu_last [4]; + + total = usr + nice + sys + free + iowait; + + memcpy(g->cpu_last, g->cpu_time, sizeof g->cpu_last); + + usr = rint (Maximum * (float)(usr) / total); + nice = rint (Maximum * (float)(nice) / total); + sys = rint (Maximum * (float)(sys) / total); + iowait = rint (Maximum * (float)(iowait) / total); + free = Maximum - usr - nice - sys - iowait; + + data [0] = usr; + data [1] = sys; + data [2] = nice; + data [3] = iowait; + data [4] = free; +} + +void +GetDiskLoad (int Maximum, int data [3], LoadGraph *g) +{ + static gboolean first_call = TRUE; + static guint64 lastread = 0, lastwrite = 0; + static AutoScaler scaler; + + glibtop_mountlist mountlist; + glibtop_mountentry *mountentries; + guint i; + int max; + + guint64 read, write; + guint64 readdiff, writediff; + + + if(first_call) + { + autoscaler_init(&scaler, 60, 500); + } + + read = write = 0; + + mountentries = glibtop_get_mountlist (&mountlist, FALSE); + + for (i = 0; i < mountlist.number; i++) + { + glibtop_fsusage fsusage; + + if (strcmp(mountentries[i].type, "smbfs") == 0 + || strcmp(mountentries[i].type, "nfs") == 0 + || strcmp(mountentries[i].type, "cifs") == 0) + continue; + + glibtop_get_fsusage(&fsusage, mountentries[i].mountdir); + read += fsusage.read; write += fsusage.write; + } + + g_free(mountentries); + + readdiff = read - lastread; + writediff = write - lastwrite; + + lastread = read; + lastwrite = write; + + if(first_call) + { + first_call = FALSE; + memset(data, 0, 3 * sizeof data[0]); + return; + } + + max = autoscaler_get_max(&scaler, readdiff + writediff); + + data[0] = (float)Maximum * readdiff / (float)max; + data[1] = (float)Maximum * writediff / (float)max; + data[2] = (float)Maximum - (data [0] + data[1]); +} + +#if 0 +void +GetPage (int Maximum, int data [3], LoadGraph *g) +{ + static int max = 100; /* guess at maximum page rate (= in + out) */ + static u_int64_t lastin = 0; + static u_int64_t lastout = 0; + int in, out, idle; + + glibtop_swap swap; + + glibtop_get_swap (&swap); + + assert ((swap.flags & needed_page_flags) == needed_page_flags); + + if ((lastin > 0) && (lastin < swap.pagein)) { + in = swap.pagein - lastin; + } + else { + in = 0; + } + lastin = swap.pagein; + + if ((lastout > 0) && (lastout < swap.pageout)) { + out = swap.pageout - lastout; + } + else { + out = 0; + } + lastout = swap.pageout; + + if ((in + out) > max) { + /* Maximum page rate has increased. Change the scale without + any indication whatsoever to the user (not a nice thing to + do). */ + max = in + out; + } + + in = rint (Maximum * ((float)in / max)); + out = rint (Maximum * ((float)out / max)); + idle = Maximum - in - out; + + data [0] = in; + data [1] = out; + data [2] = idle; +} +#endif /* 0 */ + +void +GetMemory (int Maximum, int data [5], LoadGraph *g) +{ + int user, shared, buffer, cached; + + glibtop_mem mem; + + glibtop_get_mem (&mem); + + g_return_if_fail ((mem.flags & needed_mem_flags) == needed_mem_flags); + + user = rint (Maximum * (float)mem.user / (float)mem.total); + shared = rint (Maximum * (float)mem.shared / (float)mem.total); + buffer = rint (Maximum * (float)mem.buffer / (float)mem.total); + cached = rint (Maximum * (float)mem.cached / (float)mem.total); + + data [0] = user; + data [1] = shared; + data [2] = buffer; + data[3] = cached; + data [4] = Maximum-user-shared-buffer-cached; +} + +void +GetSwap (int Maximum, int data [2], LoadGraph *g) +{ + int used, free; + + glibtop_swap swap; + + glibtop_get_swap (&swap); + g_return_if_fail ((swap.flags & needed_swap_flags) == needed_swap_flags); + + if (swap.total == 0) { + used = 0; + free = Maximum; + } + else { + used = rint (Maximum * (float)swap.used / swap.total); + free = rint (Maximum * (float)swap.free / swap.total); + } + + data [0] = used; + data [1] = Maximum - used; +} + +void +GetLoadAvg (int Maximum, int data [2], LoadGraph *g) +{ + const float per_cpu_max_loadavg = 5.0f; + float max_loadavg; + float loadavg1; + float used, free; + + glibtop_loadavg loadavg; + glibtop_get_loadavg (&loadavg); + + g_return_if_fail ((loadavg.flags & needed_loadavg_flags) == needed_loadavg_flags); + + max_loadavg = per_cpu_max_loadavg * (1 + glibtop_global_server->ncpu); + + g->loadavg1 = loadavg.loadavg[0]; + loadavg1 = MIN(loadavg.loadavg[0], max_loadavg); + + used = loadavg1 / max_loadavg; + free = (max_loadavg - loadavg1) / max_loadavg; + + data [0] = rint ((float) Maximum * used); + data [1] = Maximum - data[0]; +} + +/* + * Return true if a network device (identified by its name) is virtual + * (ie: not corresponding to a physical device). In case it is a physical + * device or unknown, returns false. + */ +static gboolean +is_net_device_virtual(char *device) +{ + /* + * There is not definitive way to find out. On some systems (Linux + * kernels ≳ 2.19 without option SYSFS_DEPRECATED), there exist a + * directory /sys/devices/virtual/net which only contains virtual + * devices. It's also possible to detect by the fact that virtual + * devices do not have a symlink "device" in + * /sys/class/net/name-of-dev/ . This second method is more complex + * but more reliable. + */ + char path[PATH_MAX]; + + /* Check if /sys/class/net/name-of-dev/ exists (may be old linux kernel + * or not linux at all). */ + if (sprintf(path, "/sys/class/net/%s", device) < 0) + return FALSE; + if (access(path, F_OK) != 0) + return FALSE; /* unknown */ + + if (sprintf(path, "/sys/class/net/%s/device", device) < 0) + return FALSE; + if (access(path, F_OK) != 0) + return TRUE; + + return FALSE; +} + +void +GetNet (int Maximum, int data [4], LoadGraph *g) +{ + enum Types { + IN_COUNT = 0, + OUT_COUNT = 1, + LOCAL_COUNT = 2, + COUNT_TYPES = 3 + }; + + static int ticks = 0; + static gulong past[COUNT_TYPES] = {0}; + static AutoScaler scaler; + + gulong present[COUNT_TYPES] = {0}; + + guint i; + gchar **devices; + glibtop_netlist netlist; + + + if(ticks == 0) + { + autoscaler_init(&scaler, 60, 501); + } + + + devices = glibtop_get_netlist(&netlist); + + for(i = 0; i < netlist.number; ++i) + { + int index; + glibtop_netload netload; + + glibtop_get_netload(&netload, devices[i]); + + g_return_if_fail((netload.flags & needed_netload_flags) == needed_netload_flags); + + if (!(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_UP))) + continue; + + if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_LOOPBACK)) { + /* for loopback in and out are identical, so only count in */ + present[LOCAL_COUNT] += netload.bytes_in; + continue; + } + + /* + * Do not include virtual devices (VPN, PPPOE...) to avoid + * counting the same throughput several times. + */ + if (is_net_device_virtual(devices[i])) + continue; + + present[IN_COUNT] += netload.bytes_in; + present[OUT_COUNT] += netload.bytes_out; + } + + g_strfreev(devices); + netspeed_add(g->netspeed_in, present[IN_COUNT]); + netspeed_add(g->netspeed_out, present[OUT_COUNT]); + + if(ticks < 2) /* avoid initial spike */ + { + ticks++; + memset(data, 0, COUNT_TYPES * sizeof data[0]); + } + else + { + int delta[COUNT_TYPES]; + int max; + int total = 0; + + for (i = 0; i < COUNT_TYPES; i++) + { + /* protect against weirdness */ + if (present[i] >= past[i]) + delta[i] = (present[i] - past[i]); + else + delta[i] = 0; + total += delta[i]; + } + + max = autoscaler_get_max(&scaler, total); + + for (i = 0; i < COUNT_TYPES; i++) + data[i] = rint (Maximum * (float)delta[i] / max); + } + + //data[4] = Maximum - data[3] - data[2] - data[1] - data[0]; + data[COUNT_TYPES] = Maximum; + for (i = 0; i < COUNT_TYPES; i++) + data[COUNT_TYPES] -= data[i]; + + memcpy(past, present, sizeof past); +} + + + |