[Orca-checkins] rev 199 - in trunk/orca/lib/SE: 3.2.1 3.3

blair at orcaware.com blair at orcaware.com
Tue Jan 21 13:36:21 PST 2003


Author: blair
Date: 2003-01-21 13:36:06 -0800 (Tue, 21 Jan 2003)
New Revision: 199

Added:
   trunk/orca/lib/SE/3.2.1/live_rules.se
   trunk/orca/lib/SE/3.3/live_rules.se
Log:
* lib/SE/3.2.1/live_rules.se,
* lib/SE/3.3/live_rules.se:
  New files to be included by SE instead of the live_rules.se packaged
  with SE 3.2.1.  These files fix an issue where the pvm.idle_time is
  calculated in such a way that the total CPU time
  (pvm.user_time + pvm.system_time + pvm.wait_time + pvm.idle_time)
  can be greater than 100%, which causes the orcallator.cfg.in file to
  ignore that data measurement.  The new calculation ensures that the
  total CPU time will be less than 100%, which is better than being
  greater than 100%.  These files are only included by the new
  start_orcallator.sh.in script, which starts SE with a -I command
  line option.


Added: trunk/orca/lib/SE/3.2.1/live_rules.se
==============================================================================
--- trunk/orca/lib/SE/3.2.1/live_rules.se	(original)
+++ trunk/orca/lib/SE/3.2.1/live_rules.se	2003-01-21 13:36:17.000000000 -0800
@@ -0,0 +1,945 @@
+
+/*
+
+      Copyright (c) 1995-1998, by Sun Microsystems, Inc. 
+        All Rights Reserved
+
+Written by Adrian Cockcroft, based on Appendix A of "Sun Performance
+and Tuning", ISBN 0-13-095249-4
+
+Version 1.8	31 May 99	Added disk errors to disk rule
+Version 1.7	19 Mar 99	Make GLOBAL_disk a dynamic array
+Version 1.6	17 Feb 99	Fixes to partition exclusion code
+Version 1.5	25 Jul 98	Updated mutex rule data feed
+Version 1.4	26 Dec 97	Fixes for disk_count in 2.6 disk rule
+Version 1.3	 7 Nov 97	Fixed handspread for ram rule
+Version 1.2	23 Oct 97	Fixes for 2.6 partitions
+Version 1.1	 8 Oct 96	Use explanations from pure rules
+Version 1.00	 9 Aug 96	Extra info for new net_rule
+Version 0.20	23 Aug 95	Added data rates to lr_rpcclient
+Version 0.19	22 Aug 95	Added hme ethernet device
+Version 0.18	 8 Aug 95	Fixed init of kmem
+Version 0.17	29 May 95	Added extra data to kmem rule
+Version 0.16	16 May 95	Added print_lr_disk
+Version 0.15	14 May 95	Bugfix dnlc and inode rules
+Version 0.14	10 May 95	Fixed kmem to work on 2.3
+Version 0.13	 7 May 95	Added new live rules, and thresh code
+Version 0.12	24 Apr 95	Modified to remove live thresholds
+Version 0.11	14 Apr 95	Added vmglobal_total function
+Version 0.10	18 Mar 95	Added debug defines, fixed bugs
+Version 0.9	16 Mar 95	Made local into GLOBAL storage - Adrian
+Version 0.8	24 Feb 95	Fixes by Rich to recognise smc ethernets
+Version 0.7	25 Jan 95	Made source classes global, added mutex
+Version 0.6	18 Dec 94	Added swapspace and ram rules
+Version 0.5     13 Dec 94       Added rpcc rule, fixed some bugs
+Version 0.4     15 Nov 94       Created, matching pure_rules version
+
+Live Rules use the rules found in pure_rules.se but contain the code
+to obtain the measurements and feed them into the rules using current
+data measured on the live system. Each live rule is a class, with
+output variables, threshold variables, private variables and code. No inputs
+should be required apart from changes to any special live-only thresholds.
+
+Thresholds for the underlying pure rules are read from environment
+variables when the pure rule is reset. Resetting the live rule causes
+the pure rule to be reset. Use putenv if you must tweak them...
+
+Each rule has a state and an action, the state is the evaluated condition,
+the action is a short text string that may indicate what should be done.
+A longer string called an explanation may span multiple lines.
+
+Each live rule class type is lr_xxxx_t with active prefix lr_xxxx$
+for the code section. Each matches a pr_xxxx_t pure rule.
+
+The live_rules read directly from the vmstat_class and iostat_class etc,
+to make the raw data available to programs that read a rule, and want to
+show the same underlying numbers, the classes and temporary copies are
+defined globally. Rich doesn't like globals, so I put GLOBAL in the
+name of each variable to make it obvious that they are special.
+Each GLOBAL active class has a GLOBAL_update_time so that multiple rules
+that use it know that they don't have to reevaluate the data more often
+than the specified UPDATE_RATE
+
+Include file dependencies - these should be included by the application:
+#include <stdio.se>
+#include <stdlib.se>
+#include <unistd.se>
+#include <string.se>
+#include <kstat.se>
+#include <sysdepend.se>
+#include <netif.se>
+#include <dirent.se>
+#include <inst_to_path.se>
+#include <p_iostat_class.se>
+#include <p_netstat_class.se>
+#include <p_vmstat_class.se>
+#include <pure_rules.se> 
+*/
+
+/* common string to use */
+string uninit = "Rule initializing...";
+
+/* global iostat class and recorded data available for use */
+p_iostat p_iostat$GLOBAL_disk;
+ks_sderr kstat$sderr;
+ulong	 GLOBAL_disk_update_time;	/* when last evaluated */
+#define  DISK_UPDATE_RATE	2	/* 2 seconds between samples */
+/* GLOBAL_disk[0].disk_count indicates how many entries are valid */
+p_iostat GLOBAL_disk[];	/* on 2.6 partition data is excluded */
+ks_sderr GLOBAL_sderr[];/* MAX_DISK is bigger than needed */
+int	 GLOBAL_sderr_state[];  /* rule status */
+int	 GLOBAL_sderr_errcnt[]; /* total error count */
+int      GLOBAL_disk_size = MAX_DISK;
+int	 GLOBAL_sderr_size = MAX_DISK;
+int	 GLOBAL_disk_count;
+
+/* global net class and recorded data available for use */
+p_netstat p_netstat$GLOBAL_net;
+ulong    GLOBAL_net_update_time;        /* when last evaluated */
+#define  NET_UPDATE_RATE	2	/* 2 seconds between samples */
+/* GLOBAL_net[0].net_count indicates how many entries are valid */
+p_netstat GLOBAL_net[MAX_IF];
+
+/* global client rpc class available for use */
+ks_rpc_client kstat$GLOBAL_ks_rpc_client;
+ulong     GLOBAL_ks_rpc_client_update_time;
+#define  KS_RPC_CLIENT_UPDATE_RATE 1	/* 1 second between samples */
+ks_rpc_client GLOBAL_last_rpcc;
+ks_rpc_client GLOBAL_this_rpcc;
+
+/* global per-cpu vmstat class and recorded data */
+p_vmstat p_vmstat$GLOBAL_pvm;
+ulong    GLOBAL_pvm_update_time;        /* when last evaluated */
+#define  PVM_UPDATE_RATE	2	/* 2 seconds between samples */
+int	 GLOBAL_pvm_ncpus;		/* number of valid entries */
+p_vmstat GLOBAL_pvm[MAX_CPU];
+
+/* function to total up global per_cpu data into vmstat form */
+p_vmstat vmglobal_total() {
+  int i;
+  double total;
+  p_vmstat pvm;
+
+  pvm = GLOBAL_pvm[0];
+  for(i=1; i < GLOBAL_pvm_ncpus; i++) {
+    pvm.pages_in += GLOBAL_pvm[i].pages_in;
+    pvm.pages_out += GLOBAL_pvm[i].pages_out;
+    pvm.interrupts += GLOBAL_pvm[i].interrupts;
+    pvm.system_calls += GLOBAL_pvm[i].system_calls;
+    pvm.context_switches += GLOBAL_pvm[i].context_switches;
+    pvm.user_time += GLOBAL_pvm[i].user_time;
+    pvm.system_time += GLOBAL_pvm[i].system_time;
+    pvm.wait_time += GLOBAL_pvm[i].wait_time;
+    pvm.idle_time += GLOBAL_pvm[i].idle_time;
+    pvm.scan += GLOBAL_pvm[i].scan;
+    pvm.smtx += GLOBAL_pvm[i].smtx;
+  }
+  if (GLOBAL_pvm_ncpus > 1) {
+    /* average over cpu count */
+    pvm.user_time        /= GLOBAL_pvm_ncpus;
+    pvm.system_time      /= GLOBAL_pvm_ncpus;
+    pvm.wait_time        /= GLOBAL_pvm_ncpus;
+    pvm.idle_time        /= GLOBAL_pvm_ncpus;
+#if MINOR_VERSION < 70
+    /* reduce wait time - only one CPU can ever be waiting - others are idle */
+    /* system counts all idle CPUs as waiting if any I/O is outstanding */
+    pvm.wait_time        /= GLOBAL_pvm_ncpus;
+#endif
+  }
+  total = pvm.user_time + pvm.system_time + pvm.wait_time + pvm.idle_time;
+  if (total < 100.0) {
+    pvm.idle_time += (100.0 - total);
+  }
+
+  /* Make sure that total is never greater than 100%.  Better less
+   * than 100% than greater than 100%.  */
+  total = pvm.user_time + pvm.system_time + pvm.wait_time + pvm.idle_time;
+  if (total > 100.0) {
+    pvm.idle_time -= (total - 100.0);
+  }
+  return pvm;
+}
+
+/* Disk I/O live rule - special extra disk type thresholds */
+rule_thresh_dbl slowfd_thr = {"LR_DISK_SLOW_FD", 10.0, "x", 4, 1,
+	"derate slow floppys" }; 
+rule_thresh_dbl slowcd_thr = {"LR_DISK_SLOW_CD", 10.0, "x", 4, 1, 
+	"derate slow CDs" }; 
+rule_thresh_str fdname = {"LR_DISK_FLOPPY", "fd0", "", 6, "default floppy device" };
+rule_thresh_str cdname = {"LR_DISK_CDROM", "c0t6d0", "", 6, "default CD device" };
+rule_thresh_str diskerr_thr = {"LR_DISK_ERROR", "new", "", 4, "report on <any> since boot, or only <new> errors" };
+
+print_lr_disk(ulong f) {
+   print_thresh_dbl(f, slowfd_thr);
+   print_thresh_dbl(f, slowcd_thr); 
+   print_thresh_str(f, fdname); 
+   print_thresh_str(f, cdname); 
+   print_thresh_str(f, diskerr_thr);
+}
+
+class lr_disk_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  int disk_count;	/* inicates how many entries are valid */
+  int states[MAX_DISK]; /* per-disk state */
+  string names[MAX_DISK]; /* dynamic arrays don't work here */
+  /* threshold variables */
+  string floppy;	/* don't include floppy and CD in normal rules */
+  string cdrom;
+  string diskerr_mode;
+  double slowfd; /* assume floppy and CD are slower */
+  double slowcd;
+
+  lr_disk$() {
+    pr_disk_t disk_rule;
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    int i;
+    int update;
+    int d;
+    int e;
+    int n;
+    string dname;
+    char dummy[32];
+
+#ifdef LIVE_DISK_DEBUG
+    debug_on();
+#endif
+    if (timestamp == 0) {       /* reset defaults */
+      p_iostat$GLOBAL_disk.number$ = 0;
+      GLOBAL_disk = new p_iostat[GLOBAL_disk_size];
+      GLOBAL_disk_count = 0;
+      for(i=0; ; i++) {
+        if (GLOBAL_disk_count == GLOBAL_disk_size) {
+          GLOBAL_disk_size += 4;
+          GLOBAL_disk = renew GLOBAL_disk[GLOBAL_disk_size];
+        }
+        p_iostat$GLOBAL_disk.number$ = i;
+        GLOBAL_disk[GLOBAL_disk_count] = p_iostat$GLOBAL_disk;
+        if (GLOBAL_disk[GLOBAL_disk_count].number$ == -1) {
+	  break;	/* we have run out of io kstats */
+        }
+        // ignore slices
+        if (strchr(GLOBAL_disk[GLOBAL_disk_count].info.long_name, 's') == nil) {
+          GLOBAL_disk_count++;
+        }
+      }
+      disk_count = GLOBAL_disk_count;
+      disk_rule.ndisks = GLOBAL_disk_count;
+      disk_rule.timestamp = 0;	/* reset pure rule */
+      refresh$(disk_rule);
+      state = ST_WHITE;
+      for(i=0; i < MAX_DISK; i++){
+        states[i] = ST_WHITE;
+      }
+      action = uninit;
+      explanation = uninit;
+      slowfd = get_thresh_dbl(slowfd_thr);
+      slowcd = get_thresh_dbl(slowcd_thr);
+      floppy = get_thresh_str(fdname);
+      cdrom = get_thresh_str(cdname);
+
+      diskerr_mode = get_thresh_str(diskerr_thr);
+      GLOBAL_sderr = new ks_sderr[GLOBAL_sderr_size];
+      GLOBAL_sderr_state = new int[GLOBAL_sderr_size]; 
+      GLOBAL_sderr_errcnt = new int[GLOBAL_sderr_size]; 
+
+      timestamp = time(0);
+      lasttime = timestamp;
+      GLOBAL_disk_update_time = timestamp;
+#ifdef LIVE_DISK_DEBUG 
+      debug_off();
+#endif
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;	/* wait at least a second between rule invocations */
+    }
+
+    if (timestamp - GLOBAL_disk_update_time >= DISK_UPDATE_RATE) {
+      update = 1;
+    } else {
+      update = 0;
+    }
+    /* use the disk rule  - if there are no disks then one appears then */
+    /* this code never sees it until the live_rule is reinitialized */
+    /* its unlikely to happen so I kept the code simpler - Adrian */
+    for(i=0; ; i++) {
+      /* some other rule may have already updated the GLOBAL recently */
+      /* so don't reread the data, but do use the existing data */
+      if (update == 1) {
+        if (i == GLOBAL_disk_size) {
+          GLOBAL_disk_size += 4;
+          GLOBAL_disk = renew GLOBAL_disk[GLOBAL_disk_size];
+        }
+        p_iostat$GLOBAL_disk.number$ = GLOBAL_disk[i].number$;
+        GLOBAL_disk[i] = p_iostat$GLOBAL_disk;
+        GLOBAL_disk_update_time = timestamp;
+        if (GLOBAL_disk[i].number$ == -1) {
+          GLOBAL_disk_count = i;
+          break;
+        } else {
+          // skip it if it's a slice
+          if (strchr(GLOBAL_disk[i].info.long_name,'s') != nil) {
+	    continue;	/* go find another I/O record */
+          }
+        }
+      }
+
+      /* check that there is good data */
+      if (GLOBAL_disk[i].number$ == -1) {
+        GLOBAL_disk_count = i;
+        break;
+      }
+      names[i] = GLOBAL_disk[i].info.long_name;
+      disk_rule.busy[i] = GLOBAL_disk[i].run_percent;
+
+/* note previous error and throughput, if no activity since error then
+stay black, count new errors black, media/soft errors red */
+
+      if (names[i] == cdrom) {
+        disk_rule.svc_t[i] = GLOBAL_disk[i].service / slowcd;
+      } else {
+        if (names[i] == floppy) {
+          disk_rule.svc_t[i] = GLOBAL_disk[i].service / slowfd;
+        } else {
+          disk_rule.svc_t[i] = GLOBAL_disk[i].service;
+        }
+      }
+    }
+    disk_rule.timestamp = timestamp;
+    refresh$(disk_rule);
+    state = disk_rule.state;
+    action = disk_rule.action;
+    explanation = disk_rule.explanation;
+    disk_count = GLOBAL_disk_count;
+    for(i=0; i < disk_count; i++){
+      states[i] = disk_rule.states[i];
+    } 
+#ifdef LIVE_PRINTOUT
+    printf("\nDisk       %-5s %s\n", state_string(state), action);
+    printf("disk      r/s  w/s   Kr/s   Kw/s wait actv  svc_t  %%w  %%b State\n");
+    for(i=0; i < GLOBAL_disk[0].disk_count; i++) {
+      printf("%-8.8s %4.1f %4.1f %6.1f %6.1f %4.1f %4.1f %6.1f %3.0f %3.0f %-5s\n",
+        names[i],
+        GLOBAL_disk[i].reads, GLOBAL_disk[i].writes,
+        GLOBAL_disk[i].kreads, GLOBAL_disk[i].kwrites,
+        GLOBAL_disk[i].avg_wait, GLOBAL_disk[i].avg_run,
+        GLOBAL_disk[i].service,
+        GLOBAL_disk[i].wait_percent, GLOBAL_disk[i].run_percent,
+	state_string(states[i]));
+    }
+#endif
+
+    /* now check for disk errors */
+    /* if we find one then figure out which disk it is later */
+    for(i=0; ; i++) {	/* grab new data */
+      if (i == GLOBAL_sderr_size) {
+        GLOBAL_sderr_size += 4;       /* grow the arrays a bit  */
+        GLOBAL_sderr = renew GLOBAL_sderr[GLOBAL_sderr_size];
+	GLOBAL_sderr_state = renew GLOBAL_sderr_state[GLOBAL_sderr_size];
+	GLOBAL_sderr_errcnt = renew GLOBAL_sderr_errcnt[GLOBAL_sderr_size];
+      }
+      kstat$sderr.number$ = i;
+      GLOBAL_sderr[i] = kstat$sderr;
+      if (GLOBAL_sderr[i].number$ == -1) {
+        break;
+      }
+      e = GLOBAL_sderr[i].Soft_Errors + GLOBAL_sderr[i].Hard_Errors
+	+ GLOBAL_sderr[i].Transport_Errors;
+      if (e > (diskerr_mode == "new" ? GLOBAL_sderr_errcnt[i]: 0)) {
+	/* this disk needs a closer look */
+	GLOBAL_sderr_errcnt[i] = e;
+	/* work out which disk it really is */
+	d = strcspn(GLOBAL_sderr[i].name$, ",");
+	dname = strncpy(dummy, GLOBAL_sderr[i].name$, d); /* chop ,err */
+#ifdef FIND_INST
+	d = find_inst(dname); /* fast but buggy */
+#else
+	for(n=0; n < GLOBAL_disk_count; n++) {
+	  if (dname == GLOBAL_disk[n].info.short_name) {
+	    d = n;
+	    break;
+	  }
+	}
+#endif
+	if (d != -1) {
+		dname = GLOBAL_disk[d].info.long_name;
+	}
+	/* process rules in order of increasing error level */
+	if (GLOBAL_sderr[i].No_Device > 0) {
+	  explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+		dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].No_Device, "green Warning - No Device - cprboot spinup?");
+	  GLOBAL_sderr_state[i] = ST_GREEN;
+	}
+        if (GLOBAL_sderr[i].Recoverable > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Recoverable, "amber - Recoverable Error Retry");
+          GLOBAL_sderr_state[i] = ST_AMBER;
+        }
+        if (GLOBAL_sderr[i].Predictive_Failure_Analysis > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Predictive_Failure_Analysis, "red   - Predictive_Failure_Analysis - Replace Disk");
+          GLOBAL_sderr_state[i] = ST_RED;
+        }
+	// it's not uncommon for the CD to not be ready... richp
+        if (GLOBAL_sderr[i].Device_Not_Ready > 0 && dname != cdrom) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Device_Not_Ready, "black - Device Not Ready - disk offline?");
+          GLOBAL_sderr_state[i] = ST_BLACK;
+        }
+        if (GLOBAL_sderr[i].Media_Error > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Media_Error, "black - Media Error - replace disk");
+          GLOBAL_sderr_state[i] = ST_BLACK;
+        }
+        if (GLOBAL_sderr[i].Illegal_Request > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Illegal_Request, "black - Illegal Request Error");
+          GLOBAL_sderr_state[i] = ST_BLACK;
+        }
+	/* update disk state */
+	if (d != -1) {
+	  if (states[d] < GLOBAL_sderr_state[i]) {
+	    states[d] = GLOBAL_sderr_state[i];
+	    if (state < states[d]) {
+	      state = states[d];
+	    }
+	    switch(GLOBAL_sderr_state[i]) {
+	      case ST_AMBER:
+		action = "Disk error warning - check disk";
+		break;
+	      case ST_RED:
+		action = "Disk error problem - replace disk";
+		break;
+	      case ST_BLACK:
+		action = "Disk failed - check cables or replace disk";
+	    }
+	  }
+	}
+      }
+    }
+
+    lasttime = timestamp;
+#ifdef LIVE_DISK_DEBUG 
+    debug_off();
+#endif
+  }
+};
+
+/* Network live rule - picks out ethernets only for now */
+/* reports anything else as green */
+
+class lr_net_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  int net_count;
+  int states[MAX_IF]; /* per-net state */
+  string names[MAX_IF];
+  int speeds[MAX_IF]; /* network speed in bytes/sec */
+  /* make snapshot of pure rule available */
+  pr_enet_t net_rule;
+
+  lr_net$() {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    int i;
+    int update;
+    char ifname[12];
+    int enet_count;
+    int net[MAX_IF];	/* index between ethernets and all nets */
+ 
+    if (timestamp == 0) {       /* reset defaults */
+      GLOBAL_net[0] = p_netstat$GLOBAL_net;
+      net_count = GLOBAL_net[0].net_count;
+      for(i=1; i < GLOBAL_net[0].net_count; i++){
+        p_netstat$GLOBAL_net.number$ = i;
+        GLOBAL_net[i] = p_netstat$GLOBAL_net;
+      }  
+      net_rule.enet_count = net_count;
+      net_rule.timestamp = 0;	/* force pure rule to reset */
+      refresh$(net_rule);
+      state = ST_GREEN;	/* non-ethernets should default to ST_GREEN */
+      for(i=0; i < MAX_IF; i++){
+        states[i] = ST_GREEN;
+      }  
+      action = uninit;
+      explanation = action;
+      timestamp = time(0);
+      lasttime = timestamp;
+      GLOBAL_net_update_time = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+
+    if (timestamp - GLOBAL_net_update_time >= NET_UPDATE_RATE) {
+      update = 1;
+    } else {
+      update = 0;
+    }
+    enet_count = 0;
+    for(i=0; i < GLOBAL_net[0].net_count; i++) {
+      if (update == 1) {
+        p_netstat$GLOBAL_net.number$ = i;
+        GLOBAL_net[i] = p_netstat$GLOBAL_net;
+        GLOBAL_net_update_time = timestamp;
+      }
+      names[i] = GLOBAL_net[i].name$;
+      ifname = GLOBAL_net[i].name$;
+      speeds[i] = GLOBAL_net[i].ifspeed;
+      if (GLOBAL_net[i].iftype == NT_CSMACD) {
+        net_rule.opackets[enet_count] = GLOBAL_net[i].opackets;
+        net_rule.collpercent[enet_count] = GLOBAL_net[i].collpercent;
+        net_rule.errors[i] = GLOBAL_net[i].ierrors + GLOBAL_net[i].oerrors;
+        net_rule.defer[i] = GLOBAL_net[i].defer;
+        net_rule.nocanput[i] = GLOBAL_net[i].nocanput;
+        net[enet_count++] = i;
+      } else {
+	/* XXX: add code to check FDDI, ATM, token ring here */
+        states[i] = ST_GREEN;	/* not an ethernet so assume its OK */
+      }
+    }  
+    net_rule.enet_count = enet_count;
+    net_rule.timestamp = timestamp;
+    refresh$(net_rule);
+    state = net_rule.state;
+    action = net_rule.action;
+    explanation = net_rule.explanation;
+    net_count = GLOBAL_net[0].net_count;
+    for(i=0; i < enet_count; i++){
+      states[net[i]] = net_rule.states[i];
+    }
+    lasttime = timestamp;
+  }
+};
+
+
+/* NFS client RPC live rule */
+
+class lr_rpcclient_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  double calls;		/* per second rates for info */
+  double timeouts;
+  double badxids;
+
+  lr_rpcclient$()
+  { 
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_rpcclient_t rpcc_rule;
+    double ttmp;
+    double dtmp;
+ 
+    if (timestamp == 0) {
+      rpcc_rule.timestamp = 0;
+      refresh$(rpcc_rule);
+      GLOBAL_last_rpcc = kstat$GLOBAL_ks_rpc_client;
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      calls = 0.0;
+      timeouts = 0.0;
+      badxids = 0.0;
+      timestamp = time(0);
+      lasttime = timestamp;
+      GLOBAL_ks_rpc_client_update_time = lasttime;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    if (timestamp - GLOBAL_ks_rpc_client_update_time >= 
+		KS_RPC_CLIENT_UPDATE_RATE) {
+      GLOBAL_this_rpcc = kstat$GLOBAL_ks_rpc_client;
+      GLOBAL_ks_rpc_client_update_time = lasttime; 
+    }
+    ttmp = timestamp - lasttime;       /* double temporaries */
+    dtmp = GLOBAL_this_rpcc.calls - GLOBAL_last_rpcc.calls;
+    calls = dtmp / ttmp;
+    rpcc_rule.calls = calls;
+    dtmp = GLOBAL_this_rpcc.timeouts - GLOBAL_last_rpcc.timeouts;
+    timeouts = dtmp / ttmp;
+    rpcc_rule.timeouts = timeouts;
+    dtmp = GLOBAL_this_rpcc.badxids - GLOBAL_last_rpcc.badxids;
+    badxids = dtmp / ttmp;
+    rpcc_rule.badxids = badxids;
+    rpcc_rule.timestamp = timestamp;
+    refresh$(rpcc_rule);
+    state = rpcc_rule.state;
+    action = rpcc_rule.action;
+    explanation = rpcc_rule.explanation;
+    lasttime = timestamp;
+    GLOBAL_last_rpcc = GLOBAL_this_rpcc;
+  }
+};
+
+
+/* shared function to update the global pvm data */
+pvm_update(ulong timestamp) {
+  int i;
+
+  if (timestamp == 0 || timestamp - GLOBAL_pvm_update_time >= PVM_UPDATE_RATE) {
+    GLOBAL_pvm_ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+    for(i = 0; i < GLOBAL_pvm_ncpus; i++) {
+      p_vmstat$GLOBAL_pvm.number$ = i;
+      GLOBAL_pvm[i] = p_vmstat$GLOBAL_pvm;
+    }
+    GLOBAL_pvm_update_time = timestamp;
+  }
+}
+
+/* Virtual Memory - Swap Space - live rule */
+class lr_swapspace_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+ 
+  lr_swapspace$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_swapspace_t swap_rule;
+ 
+    if (timestamp == 0) {
+      timestamp = time(0);
+      pvm_update(timestamp);
+      swap_rule.swap_avail = GLOBAL_pvm[0].swap_avail;
+      swap_rule.timestamp = timestamp;
+      refresh$(swap_rule);
+      action = uninit;
+      explanation = uninit;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    swap_rule.swap_avail = GLOBAL_pvm[0].swap_avail;
+    swap_rule.timestamp = timestamp;
+    refresh$(swap_rule);
+    state = swap_rule.state;
+    action = swap_rule.action;
+    explanation = swap_rule.explanation;
+    lasttime = timestamp;
+  }
+};
+
+
+/* Real Memory - RAM page residency - live rule using improved pure_rule */
+class lr_ram_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  int restime;
+  ulong handspreadpages;	/* estimated on startup, can be set if known */
+
+  lr_ram$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_ram_t ram_rule;
+    ulong pages;
+ 
+    if (timestamp == 0) {
+      ram_rule.timestamp = 0;
+      /* default max handspread is 64MB worth of pages */
+      handspreadpages = 64 * 1048576 / sysconf(_SC_PAGESIZE);
+      pages = sysconf(_SC_PHYS_PAGES);
+      if (handspreadpages > pages / 4) {
+        handspreadpages = pages / 4;
+      }
+      ram_rule.handspread = handspreadpages;
+      refresh$(ram_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      timestamp = time(0);
+      lasttime = timestamp;
+      pvm_update(timestamp);
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    ram_rule.handspread = handspreadpages; /* allow it to be changed */
+    ram_rule.scan = GLOBAL_pvm[0].scan;
+    ram_rule.timestamp = timestamp;
+    refresh$(ram_rule);
+    state = ram_rule.state;
+    action = ram_rule.action;
+    explanation = ram_rule.explanation;
+    restime = ram_rule.restime;
+    lasttime = timestamp;
+  }
+};
+
+/* Kernel memory live rule */
+class lr_kmem_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  ulong kmem_errors;
+
+  lr_kmem$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    ks_kmem_misc kmem;
+    pr_kmem_t kmem_rule;
+    int pagesize = sysconf(_SC_PAGESIZE) / 1024;
+
+    if (timestamp == 0) {
+      kmem_rule.timestamp = 0;
+      kmem_rule.freemem = 0;
+      refresh$(kmem);
+      kmem_errors = kmem.huge_alloc_fail + kmem.perm_alloc_fail;
+      kmem_rule.kmem_errs = kmem_errors;
+      refresh$(kmem_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      timestamp = time(0);
+      lasttime = timestamp;
+      pvm_update(timestamp);
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    refresh$(kmem);
+    kmem_errors = kmem.huge_alloc_fail + kmem.perm_alloc_fail;
+    kmem_rule.kmem_errs = kmem_errors;
+    kmem_rule.freemem = GLOBAL_pvm[0].freemem / pagesize;
+    kmem_rule.timestamp = timestamp;
+    refresh$(kmem_rule);
+    state = kmem_rule.state;
+    action = kmem_rule.action;
+    explanation = kmem_rule.explanation;
+    lasttime = timestamp;
+  }
+};
+
+
+/* CPU power - live rule */
+class lr_cpu_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+
+  lr_cpu$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_cpu_t cpu_rule;
+
+    if (timestamp == 0) {
+      timestamp = time(0);
+      pvm_update(timestamp);
+      cpu_rule.ncpus = GLOBAL_pvm_ncpus;
+      cpu_rule.timestamp = 0;
+      refresh$(cpu_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);  
+    if (timestamp == lasttime) { 
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    cpu_rule.runque = GLOBAL_pvm[0].runque;
+    cpu_rule.timestamp = timestamp;  
+    refresh$(cpu_rule);
+    state = cpu_rule.state;
+    action = cpu_rule.action;
+    explanation = cpu_rule.explanation;
+    lasttime = timestamp;   
+  }
+};
+
+/* mutex contention - live rule */
+class lr_mutex_t {
+  /* output variables */
+  int state;
+  int states[MAX_CPU];
+  string action;
+  string explanation;
+  int smtx;  /* back compatible sum of p_vmstat.smtx for all cpus */
+  int ncpus;     /* i.e. sysconf(_SC_NPROCESSORS_ONLN) */
+ 
+  lr_mutex$()
+  { 
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_mutex_t mutex_rule;
+    int i;
+ 
+    if (timestamp == 0) {
+      timestamp = time(0);
+      pvm_update(timestamp);
+      ncpus = GLOBAL_pvm_ncpus;
+      mutex_rule.ncpus = ncpus;
+      mutex_rule.timestamp = 0;
+      refresh$(mutex_rule);
+      smtx = 0;
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    pvm_update(timestamp);
+    /* use the rule */
+    ncpus = GLOBAL_pvm_ncpus;
+    smtx = 0;
+    for(i = 0; i < ncpus; i++) {
+      smtx += GLOBAL_pvm[i].smtx;
+      mutex_rule.smtx[i] = GLOBAL_pvm[i].smtx;
+      mutex_rule.usr[i] = GLOBAL_pvm[i].user_time;
+      mutex_rule.sys[i] = GLOBAL_pvm[i].system_time;
+    }
+    mutex_rule.ncpus = ncpus;
+    mutex_rule.timestamp = timestamp;
+    refresh$(mutex_rule);
+    state = mutex_rule.state;
+    for(i = 0; i < ncpus; i++) {
+      states[i] = mutex_rule.states[i];
+    }
+    action = mutex_rule.action;
+    explanation = mutex_rule.explanation;
+    lasttime = timestamp;
+  }
+};
+
+/*  Directory Name Lookup Cache hit rate */
+class lr_dnlc_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  double refrate;               /* current DNLC reference rate */
+  double hitrate;               /* current DNLC hit rate */
+ 
+  lr_dnlc$()
+  { 
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_dnlc_t dnlc_rule;
+    ks_ncstats ncstats;
+    int i;
+ 
+    if (timestamp == 0) {
+      timestamp = time(0);
+      dnlc_rule.timestamp = 0;
+      refresh$(dnlc_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    refresh$(ncstats);
+    dnlc_rule.hits = ncstats.hits;
+    dnlc_rule.misses = ncstats.misses;
+    dnlc_rule.timestamp = timestamp;
+    refresh$(dnlc_rule);
+    state = dnlc_rule.state;
+    action = dnlc_rule.action;
+    explanation = dnlc_rule.explanation;
+    refrate = dnlc_rule.refrate;
+    hitrate = dnlc_rule.hitrate;
+    lasttime = timestamp;
+  }
+};
+
+/*  Inode Cache hit rate */
+class lr_inode_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  double refrate;               /* current inode cache reference rate */
+  double hitrate;               /* current inode cache hit rate */
+  double iprate;		/* current inode w/page steal rate */
+
+  lr_inode$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_inode_t inode_rule;
+    ks_inode_cache inostats;
+    int i;
+
+    if (timestamp == 0) {
+      timestamp = time(0);
+      inode_rule.timestamp = 0;
+      refresh$(inode_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    refresh$(inostats);
+    inode_rule.hits = inostats.hits;
+    inode_rule.misses = inostats.misses;
+    inode_rule.timestamp = timestamp;
+    refresh$(inode_rule);
+    state = inode_rule.state;
+    action = inode_rule.action;
+    explanation = inode_rule.explanation;
+    refrate = inode_rule.refrate;
+    hitrate = inode_rule.hitrate;
+    lasttime = timestamp;
+  }
+};

Added: trunk/orca/lib/SE/3.3/live_rules.se
==============================================================================
--- trunk/orca/lib/SE/3.3/live_rules.se	(original)
+++ trunk/orca/lib/SE/3.3/live_rules.se	2003-01-21 13:36:18.000000000 -0800
@@ -0,0 +1,977 @@
+//
+//    Copyright (c) 1995-1998, by Sun Microsystems, Inc. 
+//      All Rights Reserved
+//
+
+#ifndef _LIVE_RULES_SE_
+#define _LIVE_RULES_SE_
+
+/*
+
+Written by Adrian Cockcroft, based on Appendix A of "Sun Performance
+and Tuning", ISBN 0-13-095249-4
+
+Version 1.8	31 May 99	Added disk errors to disk rule
+Version 1.7	19 Mar 99	Make GLOBAL_disk a dynamic array
+Version 1.6	17 Feb 99	Fixes to partition exclusion code
+Version 1.5	25 Jul 98	Updated mutex rule data feed
+Version 1.4	26 Dec 97	Fixes for disk_count in 2.6 disk rule
+Version 1.3	 7 Nov 97	Fixed handspread for ram rule
+Version 1.2	23 Oct 97	Fixes for 2.6 partitions
+Version 1.1	 8 Oct 96	Use explanations from pure rules
+Version 1.00	 9 Aug 96	Extra info for new net_rule
+Version 0.20	23 Aug 95	Added data rates to lr_rpcclient
+Version 0.19	22 Aug 95	Added hme ethernet device
+Version 0.18	 8 Aug 95	Fixed init of kmem
+Version 0.17	29 May 95	Added extra data to kmem rule
+Version 0.16	16 May 95	Added print_lr_disk
+Version 0.15	14 May 95	Bugfix dnlc and inode rules
+Version 0.14	10 May 95	Fixed kmem to work on 2.3
+Version 0.13	 7 May 95	Added new live rules, and thresh code
+Version 0.12	24 Apr 95	Modified to remove live thresholds
+Version 0.11	14 Apr 95	Added vmglobal_total function
+Version 0.10	18 Mar 95	Added debug defines, fixed bugs
+Version 0.9	16 Mar 95	Made local into GLOBAL storage - Adrian
+Version 0.8	24 Feb 95	Fixes by Rich to recognise smc ethernets
+Version 0.7	25 Jan 95	Made source classes global, added mutex
+Version 0.6	18 Dec 94	Added swapspace and ram rules
+Version 0.5     13 Dec 94       Added rpcc rule, fixed some bugs
+Version 0.4     15 Nov 94       Created, matching pure_rules version
+
+Live Rules use the rules found in pure_rules.se but contain the code
+to obtain the measurements and feed them into the rules using current
+data measured on the live system. Each live rule is a class, with
+output variables, threshold variables, private variables and code. No inputs
+should be required apart from changes to any special live-only thresholds.
+
+Thresholds for the underlying pure rules are read from environment
+variables when the pure rule is reset. Resetting the live rule causes
+the pure rule to be reset. Use putenv if you must tweak them...
+
+Each rule has a state and an action, the state is the evaluated condition,
+the action is a short text string that may indicate what should be done.
+A longer string called an explanation may span multiple lines.
+
+Each live rule class type is lr_xxxx_t with active prefix lr_xxxx$
+for the code section. Each matches a pr_xxxx_t pure rule.
+
+The live_rules read directly from the vmstat_class and iostat_class etc,
+to make the raw data available to programs that read a rule, and want to
+show the same underlying numbers, the classes and temporary copies are
+defined globally. Rich doesn't like globals, so I put GLOBAL in the
+name of each variable to make it obvious that they are special.
+Each GLOBAL active class has a GLOBAL_update_time so that multiple rules
+that use it know that they don't have to reevaluate the data more often
+than the specified UPDATE_RATE
+
+Include file dependencies - these should be included by the application:
+#include <stdio.se>
+#include <stdlib.se>
+#include <unistd.se>
+#include <string.se>
+#include <kstat.se>
+#include <sysdepend.se>
+#include <netif.se>
+#include <dirent.se>
+#include <inst_to_path.se>
+#include <p_iostat_class.se>
+#include <p_netstat_class.se>
+#include <p_vmstat_class.se>
+#include <pure_rules.se> 
+*/
+
+/* common string to use */
+string uninit = "Rule initializing...";
+
+/* global iostat class and recorded data available for use */
+p_iostat p_iostat$GLOBAL_disk;
+ks_sderr kstat$sderr;
+ulong	 GLOBAL_disk_update_time;	/* when last evaluated */
+#define  DISK_UPDATE_RATE	2	/* 2 seconds between samples */
+/* GLOBAL_disk[0].disk_count indicates how many entries are valid */
+p_iostat GLOBAL_disk[];	/* on 2.6 partition data is excluded */
+ks_sderr GLOBAL_sderr[];/* MAX_DISK is bigger than needed */
+int	 GLOBAL_sderr_state[];  /* rule status */
+int	 GLOBAL_sderr_errcnt[]; /* total error count */
+int      GLOBAL_disk_size = MAX_DISK;
+int	 GLOBAL_sderr_size = MAX_DISK;
+int	 GLOBAL_disk_count;
+
+/* global net class and recorded data available for use */
+p_netstat p_netstat$GLOBAL_net;
+ulong    GLOBAL_net_update_time;        /* when last evaluated */
+#define  NET_UPDATE_RATE	2	/* 2 seconds between samples */
+/* GLOBAL_net[0].net_count indicates how many entries are valid */
+p_netstat GLOBAL_net[MAX_IF];
+
+/* global client rpc class available for use */
+ks_rpc_client kstat$GLOBAL_ks_rpc_client;
+ulong     GLOBAL_ks_rpc_client_update_time;
+#define  KS_RPC_CLIENT_UPDATE_RATE 1	/* 1 second between samples */
+ks_rpc_client GLOBAL_last_rpcc;
+ks_rpc_client GLOBAL_this_rpcc;
+
+/* global per-cpu vmstat class and recorded data */
+p_vmstat p_vmstat$GLOBAL_pvm;
+ulong    GLOBAL_pvm_update_time;        /* when last evaluated */
+#define  PVM_UPDATE_RATE	2	/* 2 seconds between samples */
+int	 GLOBAL_pvm_ncpus;		/* number of valid entries */
+p_vmstat GLOBAL_pvm[MAX_CPU];
+
+/* function to total up global per_cpu data into vmstat form */
+p_vmstat vmglobal_total() {
+  int i;
+  double total;
+  p_vmstat pvm;
+
+  pvm = GLOBAL_pvm[0];
+  for(i=1; i < GLOBAL_pvm_ncpus; i++) {
+    pvm.pages_in += GLOBAL_pvm[i].pages_in;
+    pvm.pages_out += GLOBAL_pvm[i].pages_out;
+    pvm.interrupts += GLOBAL_pvm[i].interrupts;
+    pvm.system_calls += GLOBAL_pvm[i].system_calls;
+    pvm.context_switches += GLOBAL_pvm[i].context_switches;
+    pvm.user_time += GLOBAL_pvm[i].user_time;
+    pvm.system_time += GLOBAL_pvm[i].system_time;
+    pvm.wait_time += GLOBAL_pvm[i].wait_time;
+    pvm.idle_time += GLOBAL_pvm[i].idle_time;
+    pvm.scan += GLOBAL_pvm[i].scan;
+    pvm.smtx += GLOBAL_pvm[i].smtx;
+  }
+  if (GLOBAL_pvm_ncpus > 1) {
+    /* average over cpu count */
+    pvm.user_time        /= GLOBAL_pvm_ncpus;
+    pvm.system_time      /= GLOBAL_pvm_ncpus;
+    pvm.wait_time        /= GLOBAL_pvm_ncpus;
+    pvm.idle_time        /= GLOBAL_pvm_ncpus;
+#if MINOR_VERSION < 70
+    /* reduce wait time - only one CPU can ever be waiting - others are idle */
+    /* system counts all idle CPUs as waiting if any I/O is outstanding */
+    pvm.wait_time        /= GLOBAL_pvm_ncpus;
+#endif
+  }
+  total = pvm.user_time + pvm.system_time + pvm.wait_time + pvm.idle_time;
+  if (total < 100.0) {
+    pvm.idle_time += (100.0 - total);
+  }
+
+  /* Make sure that total is never greater than 100%.  Better less
+   * than 100% than greater than 100%.  */
+  total = pvm.user_time + pvm.system_time + pvm.wait_time + pvm.idle_time;
+  if (total > 100.0) {
+    pvm.idle_time -= (total - 100.0);
+  }
+  return pvm;
+}
+
+/* Disk I/O live rule - special extra disk type thresholds */
+rule_thresh_dbl slowfd_thr = {"LR_DISK_SLOW_FD", 10.0, "x", 4, 1,
+	"derate slow floppys" }; 
+rule_thresh_dbl slowcd_thr = {"LR_DISK_SLOW_CD", 10.0, "x", 4, 1, 
+	"derate slow CDs" }; 
+rule_thresh_str fdname = {"LR_DISK_FLOPPY", "fd0", "", 6, "default floppy device" };
+rule_thresh_str cdname = {"LR_DISK_CDROM", "c0t6d0", "", 6, "default CD device" };
+rule_thresh_str diskerr_thr = {"LR_DISK_ERROR", "new", "", 4, "report on <any> since boot, or only <new> errors" };
+
+print_lr_disk(ulong f) {
+   print_thresh_dbl(f, slowfd_thr);
+   print_thresh_dbl(f, slowcd_thr); 
+   print_thresh_str(f, fdname); 
+   print_thresh_str(f, cdname); 
+   print_thresh_str(f, diskerr_thr);
+}
+
+class lr_disk_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  int disk_count;	/* inicates how many entries are valid */
+  int states[MAX_DISK]; /* per-disk state */
+  string names[MAX_DISK]; /* dynamic arrays don't work here */
+  /* threshold variables */
+  string floppy;	/* don't include floppy and CD in normal rules */
+  string cdrom;
+  string diskerr_mode;
+  double slowfd; /* assume floppy and CD are slower */
+  double slowcd;
+
+  lr_disk$() {
+    pr_disk_t disk_rule;
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    int i;
+    int update;
+    int d;
+    int e;
+    int n;
+    string dname;
+    char dummy[32];
+
+#ifdef LIVE_DISK_DEBUG
+    debug_on();
+#endif
+    if (timestamp == 0) {       /* reset defaults */
+      p_iostat$GLOBAL_disk.number$ = 0;
+      GLOBAL_disk = new p_iostat[GLOBAL_disk_size];
+      GLOBAL_disk_count = 0;
+      for(i=0; ; i++) {
+        if (GLOBAL_disk_count == GLOBAL_disk_size) {
+          GLOBAL_disk_size += 4;
+          GLOBAL_disk = renew GLOBAL_disk[GLOBAL_disk_size];
+        }
+        p_iostat$GLOBAL_disk.number$ = i;
+        GLOBAL_disk[GLOBAL_disk_count] = p_iostat$GLOBAL_disk;
+        if (GLOBAL_disk[GLOBAL_disk_count].number$ == -1) {
+	  break;	/* we have run out of io kstats */
+        }
+        // ignore slices
+        if (strchr(GLOBAL_disk[GLOBAL_disk_count].info.long_name, 's') == nil) {
+          GLOBAL_disk_count++;
+        }
+      }
+      disk_count = GLOBAL_disk_count;
+      disk_rule.ndisks = GLOBAL_disk_count;
+      disk_rule.timestamp = 0;	/* reset pure rule */
+      refresh$(disk_rule);
+      state = ST_WHITE;
+      for(i=0; i < MAX_DISK; i++){
+        states[i] = ST_WHITE;
+      }
+      action = uninit;
+      explanation = uninit;
+      slowfd = get_thresh_dbl(slowfd_thr);
+      slowcd = get_thresh_dbl(slowcd_thr);
+      floppy = get_thresh_str(fdname);
+      cdrom = get_thresh_str(cdname);
+
+      diskerr_mode = get_thresh_str(diskerr_thr);
+      GLOBAL_sderr = new ks_sderr[GLOBAL_sderr_size];
+      GLOBAL_sderr_state = new int[GLOBAL_sderr_size]; 
+      GLOBAL_sderr_errcnt = new int[GLOBAL_sderr_size]; 
+
+      timestamp = time(0);
+      lasttime = timestamp;
+      GLOBAL_disk_update_time = timestamp;
+#ifdef LIVE_DISK_DEBUG 
+      debug_off();
+#endif
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;	/* wait at least a second between rule invocations */
+    }
+
+    if (timestamp - GLOBAL_disk_update_time >= DISK_UPDATE_RATE) {
+      update = 1;
+    } else {
+      update = 0;
+    }
+    /* use the disk rule  - if there are no disks then one appears then */
+    /* this code never sees it until the live_rule is reinitialized */
+    /* its unlikely to happen so I kept the code simpler - Adrian */
+    for(i=0; ; i++) {
+      /* some other rule may have already updated the GLOBAL recently */
+      /* so don't reread the data, but do use the existing data */
+      if (update == 1) {
+        if (i == GLOBAL_disk_size) {
+          GLOBAL_disk_size += 4;
+          GLOBAL_disk = renew GLOBAL_disk[GLOBAL_disk_size];
+        }
+        p_iostat$GLOBAL_disk.number$ = GLOBAL_disk[i].number$;
+        GLOBAL_disk[i] = p_iostat$GLOBAL_disk;
+        GLOBAL_disk_update_time = timestamp;
+        if (GLOBAL_disk[i].number$ == -1) {
+          GLOBAL_disk_count = i;
+          break;
+        } else {
+          // skip it if it's a slice
+          if (strchr(GLOBAL_disk[i].info.long_name,'s') != nil) {
+	    continue;	/* go find another I/O record */
+          }
+        }
+      }
+
+      /* check that there is good data */
+      if (GLOBAL_disk[i].number$ == -1) {
+        GLOBAL_disk_count = i;
+        break;
+      }
+      names[i] = GLOBAL_disk[i].info.long_name;
+      disk_rule.busy[i] = GLOBAL_disk[i].run_percent;
+
+/* note previous error and throughput, if no activity since error then
+stay black, count new errors black, media/soft errors red */
+
+      if (names[i] == cdrom) {
+        disk_rule.svc_t[i] = GLOBAL_disk[i].service / slowcd;
+      } else {
+        if (names[i] == floppy) {
+          disk_rule.svc_t[i] = GLOBAL_disk[i].service / slowfd;
+        } else {
+          disk_rule.svc_t[i] = GLOBAL_disk[i].service;
+        }
+      }
+    }
+    disk_rule.timestamp = timestamp;
+    refresh$(disk_rule);
+    state = disk_rule.state;
+    action = disk_rule.action;
+    explanation = disk_rule.explanation;
+    disk_count = GLOBAL_disk_count;
+    for(i=0; i < disk_count; i++){
+      states[i] = disk_rule.states[i];
+    } 
+#ifdef LIVE_PRINTOUT
+    printf("\nDisk       %-5s %s\n", state_string(state), action);
+    printf("disk      r/s  w/s   Kr/s   Kw/s wait actv  svc_t  %%w  %%b State\n");
+    for(i=0; i < GLOBAL_disk[0].disk_count; i++) {
+      printf("%-8.8s %4.1f %4.1f %6.1f %6.1f %4.1f %4.1f %6.1f %3.0f %3.0f %-5s\n",
+        names[i],
+        GLOBAL_disk[i].reads, GLOBAL_disk[i].writes,
+        GLOBAL_disk[i].kreads, GLOBAL_disk[i].kwrites,
+        GLOBAL_disk[i].avg_wait, GLOBAL_disk[i].avg_run,
+        GLOBAL_disk[i].service,
+        GLOBAL_disk[i].wait_percent, GLOBAL_disk[i].run_percent,
+	state_string(states[i]));
+    }
+#endif
+
+    /* now check for disk errors */
+    /* if we find one then figure out which disk it is later */
+    for(i=0; ; i++) {	/* grab new data */
+      if (i == GLOBAL_sderr_size) {
+        GLOBAL_sderr_size += 4;       /* grow the arrays a bit  */
+        GLOBAL_sderr = renew GLOBAL_sderr[GLOBAL_sderr_size];
+	GLOBAL_sderr_state = renew GLOBAL_sderr_state[GLOBAL_sderr_size];
+	GLOBAL_sderr_errcnt = renew GLOBAL_sderr_errcnt[GLOBAL_sderr_size];
+      }
+      kstat$sderr.number$ = i;
+      GLOBAL_sderr[i] = kstat$sderr;
+      if (GLOBAL_sderr[i].number$ == -1) {
+        break;
+      }
+      e = GLOBAL_sderr[i].Soft_Errors + GLOBAL_sderr[i].Hard_Errors
+	+ GLOBAL_sderr[i].Transport_Errors;
+      if (e > (diskerr_mode == "new" ? GLOBAL_sderr_errcnt[i]: 0)) {
+	/* this disk needs a closer look */
+	GLOBAL_sderr_errcnt[i] = e;
+	/* work out which disk it really is */
+	d = strcspn(GLOBAL_sderr[i].name$, ",");
+	dname = strncpy(dummy, GLOBAL_sderr[i].name$, d); /* chop ,err */
+#ifdef FIND_INST
+	d = find_inst(dname); /* fast but buggy */
+#else
+	for(n=0; n < GLOBAL_disk_count; n++) {
+	  if (dname == GLOBAL_disk[n].info.short_name) {
+	    d = n;
+	    break;
+	  }
+	}
+#endif
+	if (d != -1) {
+		dname = GLOBAL_disk[d].info.long_name;
+	}
+	/* process rules in order of increasing error level */
+	if (GLOBAL_sderr[i].No_Device > 0) {
+	  explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+		dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].No_Device, "green Warning - No Device - cprboot spinup?");
+	  GLOBAL_sderr_state[i] = ST_GREEN;
+	}
+        if (GLOBAL_sderr[i].Recoverable > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Recoverable, "amber - Recoverable Error Retry");
+          GLOBAL_sderr_state[i] = ST_AMBER;
+        }
+        if (GLOBAL_sderr[i].Predictive_Failure_Analysis > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Predictive_Failure_Analysis, "red   - Predictive_Failure_Analysis - Replace Disk");
+          GLOBAL_sderr_state[i] = ST_RED;
+        }
+	// it's not uncommon for the CD to not be ready... richp
+        if (GLOBAL_sderr[i].Device_Not_Ready > 0 && dname != cdrom) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Device_Not_Ready, "black - Device Not Ready - disk offline?");
+          GLOBAL_sderr_state[i] = ST_BLACK;
+        }
+        if (GLOBAL_sderr[i].Media_Error > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Media_Error, "black - Media Error - replace disk");
+          GLOBAL_sderr_state[i] = ST_BLACK;
+        }
+        if (GLOBAL_sderr[i].Illegal_Request > 0) {
+          explanation = sprintf("%s\n\t%s\t%s\t%3d %s", explanation,
+                dname, GLOBAL_sderr[i].Product,
+		GLOBAL_sderr[i].Illegal_Request, "black - Illegal Request Error");
+          GLOBAL_sderr_state[i] = ST_BLACK;
+        }
+	/* update disk state */
+	if (d != -1) {
+	  if (states[d] < GLOBAL_sderr_state[i]) {
+	    states[d] = GLOBAL_sderr_state[i];
+	    if (state < states[d]) {
+	      state = states[d];
+	    }
+	    switch(GLOBAL_sderr_state[i]) {
+	      case ST_AMBER:
+		action = "Disk error warning - check disk";
+		break;
+	      case ST_RED:
+		action = "Disk error problem - replace disk";
+		break;
+	      case ST_BLACK:
+		action = "Disk failed - check cables or replace disk";
+	    }
+	  }
+	}
+      }
+    }
+
+    lasttime = timestamp;
+#ifdef LIVE_DISK_DEBUG 
+    debug_off();
+#endif
+  }
+};
+
+/* Network live rule - picks out ethernets only for now */
+/* reports anything else as green */
+
+class lr_net_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  int net_count;
+  int states[MAX_IF]; /* per-net state */
+  string names[MAX_IF];
+  int speeds[MAX_IF]; /* network speed in bytes/sec */
+  /* make snapshot of pure rule available */
+  pr_enet_t net_rule;
+
+  lr_net$() {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    int i;
+    int update;
+    char ifname[12];
+    int enet_count;
+    int net[MAX_IF];	/* index between ethernets and all nets */
+ 
+    if (timestamp == 0) {       /* reset defaults */
+      GLOBAL_net[0] = p_netstat$GLOBAL_net;
+      net_count = GLOBAL_net[0].net_count;
+      for(i=1; i < GLOBAL_net[0].net_count; i++){
+        p_netstat$GLOBAL_net.number$ = i;
+        GLOBAL_net[i] = p_netstat$GLOBAL_net;
+      }  
+      net_rule.enet_count = net_count;
+      net_rule.timestamp = 0;	/* force pure rule to reset */
+      refresh$(net_rule);
+      state = ST_GREEN;	/* non-ethernets should default to ST_GREEN */
+      for(i=0; i < MAX_IF; i++){
+        states[i] = ST_GREEN;
+      }  
+      action = uninit;
+      explanation = action;
+      timestamp = time(0);
+      lasttime = timestamp;
+      GLOBAL_net_update_time = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+
+    if (timestamp - GLOBAL_net_update_time >= NET_UPDATE_RATE) {
+      update = 1;
+    } else {
+      update = 0;
+    }
+    enet_count = 0;
+    for(i=0; i < GLOBAL_net[0].net_count; i++) {
+      if (update == 1) {
+        p_netstat$GLOBAL_net.number$ = i;
+        GLOBAL_net[i] = p_netstat$GLOBAL_net;
+        GLOBAL_net_update_time = timestamp;
+      }
+      names[i] = GLOBAL_net[i].name$;
+      ifname = GLOBAL_net[i].name$;
+      speeds[i] = GLOBAL_net[i].ifspeed;
+      if (GLOBAL_net[i].iftype == NT_CSMACD) {
+        net_rule.opackets[enet_count] = GLOBAL_net[i].opackets;
+        net_rule.collpercent[enet_count] = GLOBAL_net[i].collpercent;
+        net_rule.errors[i] = GLOBAL_net[i].ierrors + GLOBAL_net[i].oerrors;
+        net_rule.defer[i] = GLOBAL_net[i].defer;
+        net_rule.nocanput[i] = GLOBAL_net[i].nocanput;
+        net[enet_count++] = i;
+      } else {
+	/* XXX: add code to check FDDI, ATM, token ring here */
+        states[i] = ST_GREEN;	/* not an ethernet so assume its OK */
+      }
+    }  
+    net_rule.enet_count = enet_count;
+    net_rule.timestamp = timestamp;
+    refresh$(net_rule);
+    state = net_rule.state;
+    action = net_rule.action;
+    explanation = net_rule.explanation;
+    net_count = GLOBAL_net[0].net_count;
+    for(i=0; i < enet_count; i++){
+      states[net[i]] = net_rule.states[i];
+    }
+    lasttime = timestamp;
+  }
+};
+
+
+/* NFS client RPC live rule */
+
+class lr_rpcclient_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  double calls;		/* per second rates for info */
+  double timeouts;
+  double badxids;
+
+  lr_rpcclient$()
+  { 
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_rpcclient_t rpcc_rule;
+    double ttmp;
+    double dtmp;
+ 
+    if (timestamp == 0) {
+      rpcc_rule.timestamp = 0;
+      refresh$(rpcc_rule);
+      GLOBAL_last_rpcc = kstat$GLOBAL_ks_rpc_client;
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      calls = 0.0;
+      timeouts = 0.0;
+      badxids = 0.0;
+      timestamp = time(0);
+      lasttime = timestamp;
+      GLOBAL_ks_rpc_client_update_time = lasttime;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    if (timestamp - GLOBAL_ks_rpc_client_update_time >= 
+		KS_RPC_CLIENT_UPDATE_RATE) {
+      GLOBAL_this_rpcc = kstat$GLOBAL_ks_rpc_client;
+      GLOBAL_ks_rpc_client_update_time = lasttime; 
+    }
+    ttmp = timestamp - lasttime;       /* double temporaries */
+    dtmp = GLOBAL_this_rpcc.calls - GLOBAL_last_rpcc.calls;
+    calls = dtmp / ttmp;
+    rpcc_rule.calls = calls;
+    dtmp = GLOBAL_this_rpcc.timeouts - GLOBAL_last_rpcc.timeouts;
+    timeouts = dtmp / ttmp;
+    rpcc_rule.timeouts = timeouts;
+    dtmp = GLOBAL_this_rpcc.badxids - GLOBAL_last_rpcc.badxids;
+    badxids = dtmp / ttmp;
+    rpcc_rule.badxids = badxids;
+    rpcc_rule.timestamp = timestamp;
+    refresh$(rpcc_rule);
+    state = rpcc_rule.state;
+    action = rpcc_rule.action;
+    explanation = rpcc_rule.explanation;
+    lasttime = timestamp;
+    GLOBAL_last_rpcc = GLOBAL_this_rpcc;
+  }
+};
+
+
+/* shared function to update the global pvm data */
+pvm_update(ulong timestamp) {
+  int i;
+
+  if (timestamp == 0 || timestamp - GLOBAL_pvm_update_time >= PVM_UPDATE_RATE) {
+    GLOBAL_pvm_ncpus = sysconf(_SC_NPROCESSORS_ONLN);
+    for(i = 0; i < GLOBAL_pvm_ncpus; i++) {
+      p_vmstat$GLOBAL_pvm.number$ = i;
+      GLOBAL_pvm[i] = p_vmstat$GLOBAL_pvm;
+    }
+    GLOBAL_pvm_update_time = timestamp;
+  }
+}
+
+/* Virtual Memory - Swap Space - live rule */
+class lr_swapspace_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+ 
+  lr_swapspace$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_swapspace_t swap_rule;
+ 
+    if (timestamp == 0) {
+      timestamp = time(0);
+      pvm_update(timestamp);
+      swap_rule.swap_avail = GLOBAL_pvm[0].swap_avail;
+      swap_rule.timestamp = timestamp;
+      refresh$(swap_rule);
+      action = uninit;
+      explanation = uninit;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    swap_rule.swap_avail = GLOBAL_pvm[0].swap_avail;
+    swap_rule.timestamp = timestamp;
+    refresh$(swap_rule);
+    state = swap_rule.state;
+    action = swap_rule.action;
+    explanation = swap_rule.explanation;
+    lasttime = timestamp;
+  }
+};
+
+
+/* Real Memory - RAM page residency - live rule using improved pure_rule */
+class lr_ram_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  int restime;
+  ulong handspreadpages;	/* estimated on startup, can be set if known */
+
+  lr_ram$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_ram_t ram_rule;
+    ulong pages;
+ 
+    if (timestamp == 0) {
+      ram_rule.timestamp = 0;
+      /* default max handspread is 64MB worth of pages */
+      handspreadpages = 64 * 1048576 / sysconf(_SC_PAGESIZE);
+      pages = sysconf(_SC_PHYS_PAGES);
+      if (handspreadpages > pages / 4) {
+        handspreadpages = pages / 4;
+      }
+      ram_rule.handspread = handspreadpages;
+      refresh$(ram_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      timestamp = time(0);
+      lasttime = timestamp;
+      pvm_update(timestamp);
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    ram_rule.handspread = handspreadpages; /* allow it to be changed */
+    ram_rule.scan = GLOBAL_pvm[0].scan;
+    ram_rule.timestamp = timestamp;
+    refresh$(ram_rule);
+    state = ram_rule.state;
+    action = ram_rule.action;
+    explanation = ram_rule.explanation;
+    restime = ram_rule.restime;
+    lasttime = timestamp;
+  }
+};
+
+/* Kernel memory live rule */
+class lr_kmem_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  ulong kmem_errors;
+
+  lr_kmem$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+#if MINOR_VERSION < 80
+    ks_kmem_misc kmem;
+#else
+    ks_cache kmem;
+#endif
+    pr_kmem_t kmem_rule;
+    int pagesize = sysconf(_SC_PAGESIZE) / 1024;
+
+    if (timestamp == 0) {
+      kmem_rule.timestamp = 0;
+      kmem_rule.freemem = 0;
+      refresh$(kmem);
+#if MINOR_VERSION < 80
+      kmem_errors = kmem.huge_alloc_fail + kmem.perm_alloc_fail;
+#else
+      for(kmem_errors=0, kmem.number$=0, refresh$(kmem);
+          kmem.number$ != -1; kmem.number$++, refresh$(kmem)) {
+        if (kmem.name$ =~ "kmem_alloc.*") {
+          kmem_errors += kmem.alloc_fail;
+        }
+      }
+#endif
+      kmem_rule.kmem_errs = kmem_errors;
+      refresh$(kmem_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      timestamp = time(0);
+      lasttime = timestamp;
+      pvm_update(timestamp);
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    refresh$(kmem);
+#if MINOR_VERSION < 80
+    kmem_errors = kmem.huge_alloc_fail + kmem.perm_alloc_fail;
+#else
+    for(kmem_errors=0, kmem.number$=0, refresh$(kmem);
+        kmem.number$ != -1; kmem.number$++, refresh$(kmem)) {
+      if (kmem.name$ =~ "kmem_alloc.*") {
+        kmem_errors += kmem.alloc_fail;
+      }
+    }
+#endif
+    kmem_rule.kmem_errs = kmem_errors;
+    kmem_rule.freemem = GLOBAL_pvm[0].freemem / pagesize;
+    kmem_rule.timestamp = timestamp;
+    refresh$(kmem_rule);
+    state = kmem_rule.state;
+    action = kmem_rule.action;
+    explanation = kmem_rule.explanation;
+    lasttime = timestamp;
+  }
+};
+
+
+/* CPU power - live rule */
+class lr_cpu_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+
+  lr_cpu$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_cpu_t cpu_rule;
+
+    if (timestamp == 0) {
+      timestamp = time(0);
+      pvm_update(timestamp);
+      cpu_rule.ncpus = GLOBAL_pvm_ncpus;
+      cpu_rule.timestamp = 0;
+      refresh$(cpu_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);  
+    if (timestamp == lasttime) { 
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    pvm_update(timestamp);
+    cpu_rule.runque = GLOBAL_pvm[0].runque;
+    cpu_rule.timestamp = timestamp;  
+    refresh$(cpu_rule);
+    state = cpu_rule.state;
+    action = cpu_rule.action;
+    explanation = cpu_rule.explanation;
+    lasttime = timestamp;   
+  }
+};
+
+/* mutex contention - live rule */
+class lr_mutex_t {
+  /* output variables */
+  int state;
+  int states[MAX_CPU];
+  string action;
+  string explanation;
+  int smtx;  /* back compatible sum of p_vmstat.smtx for all cpus */
+  int ncpus;     /* i.e. sysconf(_SC_NPROCESSORS_ONLN) */
+ 
+  lr_mutex$()
+  { 
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_mutex_t mutex_rule;
+    int i;
+ 
+    if (timestamp == 0) {
+      timestamp = time(0);
+      pvm_update(timestamp);
+      ncpus = GLOBAL_pvm_ncpus;
+      mutex_rule.ncpus = ncpus;
+      mutex_rule.timestamp = 0;
+      refresh$(mutex_rule);
+      smtx = 0;
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    pvm_update(timestamp);
+    /* use the rule */
+    ncpus = GLOBAL_pvm_ncpus;
+    smtx = 0;
+    for(i = 0; i < ncpus; i++) {
+      smtx += GLOBAL_pvm[i].smtx;
+      mutex_rule.smtx[i] = GLOBAL_pvm[i].smtx;
+      mutex_rule.usr[i] = GLOBAL_pvm[i].user_time;
+      mutex_rule.sys[i] = GLOBAL_pvm[i].system_time;
+    }
+    mutex_rule.ncpus = ncpus;
+    mutex_rule.timestamp = timestamp;
+    refresh$(mutex_rule);
+    state = mutex_rule.state;
+    for(i = 0; i < ncpus; i++) {
+      states[i] = mutex_rule.states[i];
+    }
+    action = mutex_rule.action;
+    explanation = mutex_rule.explanation;
+    lasttime = timestamp;
+  }
+};
+
+/*  Directory Name Lookup Cache hit rate */
+class lr_dnlc_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  double refrate;               /* current DNLC reference rate */
+  double hitrate;               /* current DNLC hit rate */
+ 
+  lr_dnlc$()
+  { 
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_dnlc_t dnlc_rule;
+#if MINOR_VERSION > 70
+    ks_dnlcstats ncstats;
+#else
+    ks_ncstats ncstats;
+#endif
+    int i;
+ 
+    if (timestamp == 0) {
+      timestamp = time(0);
+      dnlc_rule.timestamp = 0;
+      refresh$(dnlc_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    refresh$(ncstats);
+    dnlc_rule.hits = ncstats.hits;
+    dnlc_rule.misses = ncstats.misses;
+    dnlc_rule.timestamp = timestamp;
+    refresh$(dnlc_rule);
+    state = dnlc_rule.state;
+    action = dnlc_rule.action;
+    explanation = dnlc_rule.explanation;
+    refrate = dnlc_rule.refrate;
+    hitrate = dnlc_rule.hitrate;
+    lasttime = timestamp;
+  }
+};
+
+/*  Inode Cache hit rate */
+class lr_inode_t {
+  /* output variables */
+  int state;
+  string action;
+  string explanation;
+  double refrate;               /* current inode cache reference rate */
+  double hitrate;               /* current inode cache hit rate */
+  double iprate;		/* current inode w/page steal rate */
+
+  lr_inode$()
+  {
+    ulong lasttime = 0;             /* previous timestamp */
+    ulong timestamp = 0;
+    pr_inode_t inode_rule;
+    ks_inode_cache inostats;
+    int i;
+
+    if (timestamp == 0) {
+      timestamp = time(0);
+      inode_rule.timestamp = 0;
+      refresh$(inode_rule);
+      action = uninit;
+      explanation = action;
+      state = ST_WHITE;
+      lasttime = timestamp;
+      return;
+    }
+    timestamp = time(0);
+    if (timestamp == lasttime) {
+      return;   /* wait at least a second between rule invocations */
+    }
+    /* use the rule */
+    refresh$(inostats);
+    inode_rule.hits = inostats.hits;
+    inode_rule.misses = inostats.misses;
+    inode_rule.timestamp = timestamp;
+    refresh$(inode_rule);
+    state = inode_rule.state;
+    action = inode_rule.action;
+    explanation = inode_rule.explanation;
+    refrate = inode_rule.refrate;
+    hitrate = inode_rule.hitrate;
+    lasttime = timestamp;
+  }
+};
+
+#endif



More information about the Orca-checkins mailing list