--- 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;