Browse Source

Parse /proc/stat for CPU load

Serj Kalichev 10 years ago
parent
commit
604dfd2f69
7 changed files with 170 additions and 8 deletions
  1. 3 1
      Makefile.am
  2. 3 2
      birq.c
  3. 5 0
      cpu.h
  4. 5 1
      cpu_parse.c
  5. 20 4
      nl.c
  6. 126 0
      statistics.c
  7. 8 0
      statistics.h

+ 3 - 1
Makefile.am

@@ -19,13 +19,15 @@ noinst_HEADERS = \
 	cpumask.h \
 	bitmap.h \
 	non-atomic.h \
-	cpu.h
+	cpu.h \
+	statistics.h
 
 birq_SOURCES = \
 	birq.c \
 	nl.c \
 	irq_parse.c \
 	cpu_parse.c \
+	statistics.c \
 	bitmap.c
 
 birq_LDADD = liblub.a

+ 3 - 2
birq.c

@@ -33,9 +33,10 @@
 #include "irq.h"
 #include "cpu.h"
 #include "nl.h"
+#include "statistics.h"
 
 #define BIRQ_PIDFILE "/var/run/birq.pid"
-#define BIRQ_INTERVAL 5 /* in seconds */
+#define BIRQ_INTERVAL 3 /* in seconds */
 
 #ifndef VERSION
 #define VERSION 1.0.0
@@ -166,7 +167,6 @@ int main(int argc, char **argv)
 
 		/* Timeout and poll for new devices */
 		while ((n = nl_poll(nl_fds, BIRQ_INTERVAL)) != 0) {
-printf("POLL NETLINK: n=%d\n", n);
 			if (-1 == n) {
 				fprintf(stderr,
 					"Error: Broken NetLink socket.\n");
@@ -182,6 +182,7 @@ printf("POLL NETLINK: n=%d\n", n);
 
 		if (opts->debug)
 			printf("Some balancing...\n");
+		parse_proc_stat(cpus);
 	}
 
 end:

+ 5 - 0
cpu.h

@@ -1,6 +1,7 @@
 #ifndef _cpu_h
 #define _cpu_h
 
+#include "lub/list.h"
 #include "cpumask.h"
 
 struct cpu_s {
@@ -8,6 +9,9 @@ struct cpu_s {
 	unsigned int package_id;
 	unsigned int core_id;
 	cpumask_t cpumask;
+	unsigned long long old_load_all;
+	unsigned long long old_load_irq;
+	float load;
 };
 typedef struct cpu_s cpu_t;
 
@@ -21,5 +25,6 @@ int cpu_list_populate(lub_list_t *cpus);
 int cpu_list_free(lub_list_t *cpus);
 int scan_cpus(lub_list_t *cpus);
 int show_cpus(lub_list_t *cpus);
+cpu_t * cpu_list_search(lub_list_t *cpus, unsigned int id);
 
 #endif

+ 5 - 1
cpu_parse.c

@@ -31,6 +31,10 @@ static cpu_t * cpu_new(unsigned int id)
 	if (!(new = malloc(sizeof(*new))))
 		return NULL;
 	new->id = id;
+	new->old_load_all = 0;
+	new->old_load_irq = 0;
+	new->load = 0;
+
 	return new;
 }
 
@@ -59,7 +63,7 @@ static cpu_t * cpu_list_search_ht(lub_list_t *cpus,
 	return NULL;
 }
 
-static cpu_t * cpu_list_search(lub_list_t *cpus, unsigned int id)
+cpu_t * cpu_list_search(lub_list_t *cpus, unsigned int id)
 {
 	lub_list_node_t *node;
 	cpu_t search;

+ 20 - 4
nl.c

@@ -36,7 +36,6 @@ nl_fds_t * nl_init(void)
 		fprintf(stderr, "Error: Can't bind NETLINK_KOBJECT_UEVENT.\n");
 		return NULL;
 	}
-printf("KOBJECT=%d\n", nl_fds[0]);
 
 	/* NETLINK_ROUTER for network events like interface up/down */
 	if ((nl_fds[1] = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) < 0) {
@@ -47,7 +46,11 @@ printf("KOBJECT=%d\n", nl_fds[0]);
 		fprintf(stderr, "Error: Can't bind NETLINK_ROUTER\n");
 		return NULL;
 	}
-printf("ROUTE=%d\n", nl_fds[1]);
+
+	/* TODO: Parse NETWORK events to filter many unneeded events */
+	/* Temporarily disable network events */
+	close(nl_fds[1]);
+	nl_fds[1] = -1;
 
 	return nl_fds;
 }
@@ -82,6 +85,8 @@ int nl_poll(nl_fds_t *nl_fds, int timeout)
 	/* Initialize the set of active sockets. */
 	FD_ZERO(&fd_set);
 	for (i = 0; i < NL_FDS_LEN; i++) {
+		if (nl_fds[i] < 0)
+			continue;
 		FD_SET(nl_fds[i], &fd_set);
 		if (nl_fds[i] > nfds)
 			nfds = nl_fds[i];
@@ -93,7 +98,6 @@ int nl_poll(nl_fds_t *nl_fds, int timeout)
 	tv.tv_usec = 0;
 
 	n = select(nfds, &fd_set, NULL, NULL, &tv);
-printf("NETLINK: n=%d\n", n);
 	if (n < 0) {
 		if (EINTR == errno)
 			return -2;
@@ -104,9 +108,21 @@ printf("NETLINK: n=%d\n", n);
 
 	/* Service all the sockets with input pending. */
 	for (i = 0; i < NL_FDS_LEN; i++) {
+		char *evtype = NULL;
 		if (!FD_ISSET(nl_fds[i], &fd_set))
 				continue;
-printf("RECV %d %d\n", i, nl_fds[i]);
+		switch (i) {
+		case 0:
+			evtype = "kernel";
+			break;
+		case 1:
+			evtype = "network";
+			break;
+		default:
+			evtype = "unknown";
+			break;
+		}
+		printf("Receive %s event\n", evtype);
 		/* Read all messages. We don't need a message content. */
 		while (recv(nl_fds[i], buf, sizeof(buf), MSG_DONTWAIT) > 0);
 	}

+ 126 - 0
statistics.c

@@ -0,0 +1,126 @@
+/* stat_parse.c
+ * Parse statistics files.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "statistics.h"
+#include "cpu.h"
+
+#define STR(str) ( str ? str : "" )
+
+void parse_proc_stat(lub_list_t *cpus)
+{
+	FILE *file;
+	char *line = NULL;
+	size_t size = 0;
+	int cpunr, rc, cpucount;
+	unsigned long long l_user;
+	unsigned long long l_nice;
+	unsigned long long l_system;
+	unsigned long long l_idle;
+	unsigned long long l_iowait;
+	unsigned long long l_irq;
+	unsigned long long l_softirq;
+	unsigned long long l_steal;
+	unsigned long long l_guest;
+	unsigned long long l_guest_nice;
+	unsigned long long load_irq, load_all;
+
+	file = fopen("/proc/stat", "r");
+	if (!file) {
+		fprintf(stderr, "Warning: Can't open /proc/stat. Balacing is broken.\n");
+		return;
+	}
+
+	/* first line is the header we don't need; nuke it */
+	if (getline(&line, &size, file) == 0) {
+		free(line);
+		fprintf(stderr, "Warning: Can't read /proc/stat. Balancing is broken.\n");
+		fclose(file);
+		return;
+	}
+
+	cpucount = 0;
+	while (!feof(file)) {
+		cpu_t *cpu;
+		if (getline(&line, &size, file)==0)
+			break;
+		if (!strstr(line, "cpu"))
+			break;
+		cpunr = strtoul(&line[3], NULL, 10);
+
+		cpu = cpu_list_search(cpus, cpunr);
+		if (!cpu)
+			continue;
+
+		rc = sscanf(line, "%*s %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu",
+			&l_user, &l_nice, &l_system, &l_idle, &l_iowait,
+			&l_irq, &l_softirq, &l_steal, &l_guest, &l_guest_nice);
+		if (rc < 2)
+			break;
+		cpucount++;
+
+		load_all = l_user + l_nice + l_system + l_idle + l_iowait +
+			l_irq + l_softirq + l_steal + l_guest + l_guest_nice;
+		load_irq = l_irq + l_softirq;
+
+		if (cpu->old_load_all == 0) {
+			cpu->load = 0;
+		} else {
+			float d_all = (float)(load_all - cpu->old_load_all);
+			float d_irq = (float)(load_irq - cpu->old_load_irq);
+			cpu->load = d_irq * 100 / d_all;
+		}
+
+		cpu->old_load_all = load_all;
+		cpu->old_load_irq = load_irq;
+
+printf("CPU %u %.2f\%\n", cpunr, cpu->load);
+
+
+		/*
+ 		 * For each cpu add the irq and softirq load and propagate that
+ 		 * all the way up the device tree
+ 		 */
+//		if (cycle_count) {
+//			cpu->load = (irq_load + softirq_load) - (cpu->last_load);
+			/*
+			 * the [soft]irq_load values are in jiffies, with
+			 * HZ jiffies per second.  Convert the load to nanoseconds
+			 * to get a better integer resolution of nanoseconds per
+			 * interrupt.
+			 */
+//			cpu->load *= NSEC_PER_SEC/HZ;
+//		}
+//		cpu->last_load = (irq_load + softirq_load);
+	}
+
+	fclose(file);
+	free(line);
+//	if (cpucount != get_cpu_count()) {
+//		fprintf(stderr, "Warning: Can't collect load info for all cpus, balancing is broken\n");
+//		return;
+//	}
+
+	/*
+ 	 * Reset the load values for all objects above cpus
+ 	 */
+//	for_each_object(cache_domains, reset_load, NULL);
+
+	/*
+ 	 * Now that we have load for each cpu attribute a fair share of the load
+ 	 * to each irq on that cpu
+ 	 */
+//	for_each_object(cpus, compute_irq_branch_load_share, NULL);
+//	for_each_object(cache_domains, compute_irq_branch_load_share, NULL);
+//	for_each_object(packages, compute_irq_branch_load_share, NULL);
+//	for_each_object(numa_nodes, compute_irq_branch_load_share, NULL);
+
+}

+ 8 - 0
statistics.h

@@ -0,0 +1,8 @@
+#ifndef _statistics_h
+#define _statistics_h
+
+#include "lub/list.h"
+
+void parse_proc_stat(lub_list_t *cpus);
+
+#endif