summaryrefslogtreecommitdiff
path: root/multiload/linux-proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'multiload/linux-proc.c')
-rw-r--r--multiload/linux-proc.c406
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);
+}
+
+
+