More WIP, need to convert to uu_list. default tip
authorAlbert Lee <trisk@forkgnu.org>
Tue, 01 Feb 2011 16:10:01 -0500
changeset 4 a42e422f55c0
parent 3 380ada8fd621
More WIP, need to convert to uu_list.
intrd.c
--- a/intrd.c	Mon Apr 19 14:47:06 2010 -0400
+++ b/intrd.c	Tue Feb 01 16:10:01 2011 -0500
@@ -29,16 +29,19 @@
 #include <stdlib.h>
 #include <limits.h>
 #include <string.h>
+#include <getopt.h>
 #include <libgen.h>
 #include <syslog.h>
 #include <kstat.h>
 #include <sys/processor.h>
+#include <sys/modhash.h>
 
 #include "intrs.h"
 
+/* Interrupt vector info */
 typedef struct ivec {
 	int cookie;
-	hrtime_t time;
+	uint64_t time;
 	hrtime_t crtime;
 	int pil;
 	int ino;
@@ -49,40 +52,63 @@
 	int inum;
 } ivec_t;
 
-typedef struct bus_stat {
-	bus_stat_t *next;
+uu_list_pool_t *ivec_pool;
+
+/* MSI device info */
+typedef struct msi_dev {
+	msi_dev_t *next;
+	char *devpath[MAXPATHLEN];
+	int num_intr;
+	*ivec_t ivecs;
+} msi_dev_t;
+
+uu_list_pool_t *msi_dev_pool;
+
+/* Bus info */
+typedef struct bus_dev {
+	bus_dev_t *next;
 	char *buspath[MAXPATHLEN];
 	int num_intr;
 	ivec_t *ivecs;
-} bus_stat_t;
+	int is_pcplusmp;
+	msi_dev_t *msi_head;
+} bus_dev_t;
 
+uu_list_pool_t *bus_dev_pool;
+
+/* Per-CPU statistics */
 typedef struct cpu_stat {
 	int state;
 	uint64_t tot;
 	hrtime_t crtime;
-	bus_stat_t *bus_stats;
+	bus_dev_t *bus_head;
 } cpu_stat_t;
 
+uu_list_pool_t *cpu_stat_pool;
+
+/* Interrupt statistics */
 type def struct intr_stat {
-	double snaptime;
+	hrtime_t snaptime;
 	*cpu_stat_t *cpus;
 } intr_stat_t;
 
+uu_list_pool_t *intr_stat_pool;
+
 typedef enum sleeptime {
-	NORMAL_SLEEPTIME = 10,			/* time to sleep between samples */
-	IDLE_SLEEPTIME = 45,			/* time to sleep when idle */
-	ONECPU_SLEEPTIME = 60 * 15,		/* used if only 1 CPU on system */
+	NORMAL_SLEEPTIME = 10,		/* time to sleep between samples */
+	IDLE_SLEEPTIME = 45,		/* time to sleep when idle */
+	ONECPU_SLEEPTIME = 60 * 15,	/* used if only 1 CPU on system */
 } sleeptime_t;
 
-int using_scengen;	/* 1 if using scenario simulator */
+int using_scengen;			/* 1 if using scenario simulator */
 int debug;
 int foreground;
 
 int max_cpus;
 
-sleeptime_t sleeptime = NORMAL_SLEEPTIME;	/* either normal_ or idle_ or onecpu_ */
+sleeptime_t sleeptime = NORMAL_SLEEPTIME;
 
-float idle_intrload = 0.1; 			/*  idle if interrupt load < 10% */
+float idle_intrload = 0.1; 		/*  idle if interrupt load < 10% */
 
 float timerange_toohi = 0.1;
 int statslen = 60;	/* time period (in secs) to keep in @deltas */
@@ -93,6 +119,7 @@
 	kstat_ctl_t *kc;
 	kstat_t *ksp;
 	intr_stat_t stat;
+	char c;
 
 	max_cpus = sysconf(_SC_CPUID_MAX) + 1;
 
@@ -103,29 +130,21 @@
  * amount of syslog output. -S <filename> loads the filename as a perl
  * script. That file is expected to implement a kstat "simulator" which
  * can be used to feed information to intrd and verify intrd's responses.
-*/
-	for (; --argc > 0; ++argv) {
-		if (argv[1][0] != '-' || argv[1][1] == '\0' ||
-		    argv[1][2] != '\0') {
-			continue;
-		}
-
-		switch (argv[1][1]) {
-			case 'S':
-				using_scengen = 1;
-				foreground = 1;
-				if (argc > 1) {
-					--argc;
-					load_simulator(++argv[1]);
-				}
-				break;
-			case 'D':
-				debug = 1;
-				break;
-			case 'f':
-				foreground = 1;
-				break;
-			default:
+ */
+ 	while ((c = getopt(argc, argv, "S:Df")) != EOF) {
+		switch (c) {
+		case 'S':
+			using_scengen = 1;
+			foreground = 1;
+			load_simulator(optarg);
+			break;
+		case 'D':
+			debug = 1;
+			break;
+		case 'f':
+			foreground = 1;
+			break;
+		default:
 		}
 	}
 
@@ -155,10 +174,10 @@
  * SMF will restart us and/or report an error to the administrator. But
  * there's nothing an administrator can do. So print out a message to syslog
  * and silently pause forever.
-*/
+ */
 	for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
 		if ((ksp->ks_type == KSTAT_TYPE_NAMED) &&
-		    !strcmp(ksp->ks_module, "pci_intrs")) {
+		    (strcmp(ksp->ks_module, "pci_intrs") == 0)) {
 		    break;
 		}
 	}
@@ -166,11 +185,12 @@
 		kstat_close(kc);
 		syslog(LOG_INFO, "no interrupts were found: " \
 			"your I/O bus may not yet be supported\n");
-		do {} while (!sleep(ONECPU_SLEEPTIME));
+		do {} while (sleep(ONECPU_SLEEPTIME) == 0);
 		return 0;
 	}
 
-	if ((stat.cpus = malloc(sizeof(cpu_stat_t) * max_cpus)) == NULL) {
+	stat.cpus = malloc(sizeof (cpu_stat_t) * max_cpus);
+	if (stat.cpus == NULL) {
 		return 1;
 	}
 }
@@ -210,14 +230,14 @@
 
 
 /*
-#
+ *
  * What follow are the basic data structures routines of intrd.
-#
+ *
  * getstat() is responsible for reading the kstats and generating a "stat" hash.
-#
+ *
  * generate_delta() is responsible for taking two "stat" hashes and creating
  * a new "delta" hash that represents what has changed over time.
-#
+ *
  * compress_deltas() is responsible for taking a list of deltas and generating
  * a single delta hash that encompasses all the time periods described by the
  * deltas.
@@ -225,14 +245,14 @@
 
 
 /*
-#
+ *
  * getstat() is handed a reference to a kstat and generates a hash, returned
  * by reference, containing all the fields from the kstats which we need.
  * If it returns the scalar 0, it failed to gather the kstats, and the caller
  * should react accordingly.
-#
+ *
  * getstat() is also responsible for maintaining a reasonable $sleeptime.
-#
+ *
  * {"snaptime"}          kstat's snaptime
  * {<cpuid>}             one hash reference per online cpu
  *  ->{"tot"}            == cpu:<cpuid>:sys:cpu_nsec_{user + kernel + idle}
@@ -249,17 +269,17 @@
  *        ->{"buspath"}  == pci_intrs:<ivec#>:<nexus>:buspath
  *        ->{"name"}     == pci_intrs:<ivec#>:<nexus>:name
  *        ->{"ihs"}      == pci_intrs:<ivec#>:<nexus>:ihs
-#
+ *
 */
 
 int getstat(kstat_ctl_t *kc, intr_stat_t *stat)
 {
 	int cpucnt = 0;
 	kstat_t *ksp;
-	double minsnap, maxsnap;
+	hrtime_t minsnap, maxsnap;
 
 	/* Hash of hash which matches (MSI device, ino) combos to kstats. */
-	int *msidevs;
+	msi_dev_t *msidevs;
 
 	/*
 	 * kstats are not generated atomically. Each kstat hierarchy will
@@ -286,13 +306,13 @@
 	 */
 
 	cpu_stats = stat->cpus;
-	bzero(cpu_stats, sizeof(cpu_stat_t) * max_cpus);
+	bzero(cpu_stats, sizeof (cpu_stat_t) * max_cpus);
 
 	for (ksp = kc->kc_chain; ksp != null; ksp = ksp->ks_next) {
 		kstat_t *ksp_sys;
 		kstat_named_t *knp;
 		int cpu;
-		double snaptime;
+		hrtime_t snaptime;
 
 		if ((ksp->ks_type != kstat_type_named) ||
 		    strcmp(ksp->ks_module, "cpu_info") ||
@@ -300,20 +320,20 @@
 		    continue;
 		}
 		knp = kstat_data_lookup(ksp, "state");
-		if ((knp == NULL) || strcmp(knp->name, PS_ONLINE)) {
+		if ((knp == NULL) || strcmp(knp->name, PS_ONLINE) ||
+		    ((cpu = ksp->ks_instance) >= max_cpus)) {
 			continue;
 		}
-		cpu = ksp->ks_instance;
 		ksp_sys = kstat_lookup(kc, "cpu", cpu, "sys");
-		if ((ksp_sys == NULL) || (kstat_read(kc, ksp_sys, NULL) == -1)) {
+		if ((ksp_sys == NULL) || (kstat_read(kc, ksp_sys) == -1)) {
 			continue;
 		}
 		cpu_stats[cpu].state = P_ONLINE;
 		knp = ksp_sys->ks_data;
 		for (i = 0; i < ksp_sys->ks_ndata; i++) {
-			if (!strcmp(knp[i].name, "cpu_nsec_idle") ||
-			    !strcmp(knp[i].name, "cpu_nsec_user") ||
-			    !strcmp(knp[i].name, "cpu_nsec_kernel")) {
+			if ((strcmp(knp[i].name, "cpu_nsec_idle") == 0) ||
+			    (strcmp(knp[i].name, "cpu_nsec_user") == 0) ||
+			    (strcmp(knp[i].name, "cpu_nsec_kernel") == 0)) {
 				cpu_stats[cpu].tot += knp[i].value.ui64;
 		}
 		cpu_stats[cpu].crtime = ksp_sys->crtime;
@@ -344,7 +364,12 @@
 	for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
 		kstat_named_t *knp;
 		int cpu;
-		double snaptime;
+		int ino;
+		cpu_stat_t *cpup;
+		bus_dev_t *busp;
+		bus_dev_t *bus_last;
+		ivec_t *ivecp;
+		hrtime_t snaptime;
 
 		if ((ksp->ks_type != KSTAT_TYPE_NAMED) ||
 		    strcmp(ksp->ks_module, "pci_intrs") ||
@@ -352,10 +377,11 @@
 			continue;
 		}
 		knp = kstat_data_lookup(ksp, "cpu");
-		if ((knp == NULL) || ((cpu = knp->value.ui32) > max_cpus) ||
+		if ((knp == NULL) || ((cpu = knp->value.ui32) >= max_cpus) ||
 		    (cpu_stats[cpu].state != P_ONLINE)) {
 			continue;
 		}
+		cpup = &cpu_stats[cpu];
 		knp = kstat_data_lookup(ksp, "type");
 		if ((knp == NULL) || strcmp(knp->value.c, "disabled")) {
 			continue;
@@ -364,6 +390,70 @@
 		if (knp == NULL) {
 			continue;
 		}
+		
+		for (bus_last = NULL, busp = cpup->bus_head; busp != NULL;
+		     bus_last = busp, busp = busp->next) {
+			if (strcmp(knp->value.c, busp->buspath) == 0) {
+				break;
+			}
+		}
+
+		if (busp == NULL) {
+			busp = malloc(sizeof (bus_dev_t));
+			if (busp == NULL) {
+				return -1;
+			}
+
+			busp->next = NULL;
+
+			strlcpy(busp->buspath, knp->value.c, MAXPATHLEN);
+			busp->is_pcplusmp =
+			    intrinfo(busp->buspath, &(busp->num_intr));
+
+			busp->ivecs = malloc(sizeof (ivec_t) * busp->num_intr);
+			if (busp->ivecs == NULL) {
+				free(busp);
+				return -1;
+			}
+			bzero(busp->ivecs, sizeof (ivec_t) * busp->num_intr);
+
+			if (bus_last == NULL) {
+				cpup->bus_head = busp;
+			} else {
+				bus_last->next = busp;
+			}
+		}
+		knp = kstat_data_lookup(ksp, "ino");
+		if ((knp == NULL) ||
+		    ((ino = knp->value.ui32) >= busp->num_intr)) {
+			continue;
+		}
+		ivecp = &(busp->ivecs[ino]);
+
+		knp = kstat_data_lookup(ksp, "time");
+		if (knp == NULL) {
+			continue;
+		}
+		ivecp->time = knp->value.ui64;
+
+		if (busp->is_pcplusmp) {
+			knp = kstat_data_lookup(ksp, "type");
+			if (knp == NULL) {
+				continue;
+			}
+			if (strcmp(knp->value.c, "msi") == 0) {
+				for (msi_last = NULL, msip = busp->msi_head;
+				     msip != NULL;
+				     msi_last = msip, msip = msip->next) {
+					if (ivecp->cookie == msip->cookie) {
+						break;
+					}
+			}
+
+		}
+			
+		ivecp->num_ino = 1;
+		ivecp->crtime = ksp->crtime;
 		snaptime = ksp->snaptime;
 		if (minsnap == -1 || snaptime < minsnap) {
 			minsnap = snaptime;