From dmberezin at hotmail.com Wed Feb 9 12:15:55 2005 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Wed, 9 Feb 2005 12:15:55 -0800 Subject: [Orca-checkins] r412 - trunk/orca/lib/SE/3.4 Message-ID: <200502092015.j19KFt4e001915@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Wed Feb 9 12:08:55 2005 New Revision: 412 Added: trunk/orca/lib/SE/3.4/ trunk/orca/lib/SE/3.4/live_rules.se trunk/orca/lib/SE/3.4/orca_p_netstat_class.se trunk/orca/lib/SE/3.4/orca_p_vmstat_class.se trunk/orca/lib/SE/3.4/orca_process_class.se trunk/orca/lib/SE/3.4/workinfo_class.se Log: Add support for SE 3.4 * lib/SE/3.4/live_rules.se * lib/SE/3.4/orca_p_netstat_class.se * lib/SE/3.4/workinfo_class.se * lib/SE/3.4/orca_p_vmstat_class.se * lib/SE/3.4/orca_process_class.se Copy all files from version 3.3.1 except for tapeinfo.se - it is now included with SE. Added: trunk/orca/lib/SE/3.4/live_rules.se ============================================================================== --- (empty file) +++ trunk/orca/lib/SE/3.4/live_rules.se Wed Feb 9 12:08:55 2005 @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +*/ + +/* 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 since boot, or only 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 Added: trunk/orca/lib/SE/3.4/orca_p_netstat_class.se ============================================================================== --- (empty file) +++ trunk/orca/lib/SE/3.4/orca_p_netstat_class.se Wed Feb 9 12:08:55 2005 @@ -0,0 +1,247 @@ +// +// Copyright (c) 1993-2001 by Richard Pettit. All rights reserved. +// +// Some of this work was derived from include files containing the following +// copyrights. +// +// Copyright (c) 1986-1994 by Sun Microsystems, Inc. +// Copyright (c) 1983-1989 by AT&T +// Copyright (c) 1980-1993 by The Regents of the University of California. +// +// The work as a whole represents unique intellectual property and is +// copyright by Richard Pettit as shown on the first line. +// + +#ifndef _P_NETSTAT_CLASS_SE_ +#define _P_NETSTAT_CLASS_SE_ + +#include +#include +#include +#include +#include +#include + +#define NANODOUBLE 0.000000001 /* converts gethrtime to seconds */ + +/* robust difference generator for wrapping 32bit counters */ +/* unsigned to double difference */ + +#define UD_DIFF(now, then) (((double) now) >= ((double) then) ? \ + (now - then) : \ + ((double) now) + 4294967296.0 - ((double) then)) + +// All this crap must be global 'cause I can't fix the interpreter bug. + +double pnetGLOB_net_ipackets[]; /* these are rates */ +double pnetGLOB_net_idtsize[]; +double pnetGLOB_net_ihdrovhd[]; +double pnetGLOB_net_ierrors[]; +double pnetGLOB_net_opackets[]; +double pnetGLOB_net_odtsize[]; +double pnetGLOB_net_ohdrovhd[]; +double pnetGLOB_net_oerrors[]; +double pnetGLOB_net_collisions[]; +double pnetGLOB_net_defer[]; +double pnetGLOB_net_nocanput[]; +double pnetGLOB_net_ioctets[]; +double pnetGLOB_net_ooctets[]; +netif pnetGLOB_save_nets[]; /* these are absolute values */ +double pnetGLOB_save_et[]; + +int pnetGLOB_net_size = MAX_IF; + +pnetGLOB_realloc() +{ + pnetGLOB_net_ipackets = renew pnetGLOB_net_ipackets[pnetGLOB_net_size]; + pnetGLOB_net_idtsize = renew pnetGLOB_net_idtsize[pnetGLOB_net_size]; + pnetGLOB_net_ihdrovhd = renew pnetGLOB_net_ihdrovhd[pnetGLOB_net_size]; + pnetGLOB_net_ierrors = renew pnetGLOB_net_ierrors[pnetGLOB_net_size]; + pnetGLOB_net_opackets = renew pnetGLOB_net_opackets[pnetGLOB_net_size]; + pnetGLOB_net_odtsize = renew pnetGLOB_net_odtsize[pnetGLOB_net_size]; + pnetGLOB_net_ohdrovhd = renew pnetGLOB_net_ohdrovhd[pnetGLOB_net_size]; + pnetGLOB_net_oerrors = renew pnetGLOB_net_oerrors[pnetGLOB_net_size]; + pnetGLOB_net_collisions = renew pnetGLOB_net_collisions[pnetGLOB_net_size]; + pnetGLOB_net_defer = renew pnetGLOB_net_defer[pnetGLOB_net_size]; + pnetGLOB_net_nocanput = renew pnetGLOB_net_nocanput[pnetGLOB_net_size]; + pnetGLOB_net_ioctets = renew pnetGLOB_net_ioctets[pnetGLOB_net_size]; + pnetGLOB_net_ooctets = renew pnetGLOB_net_ooctets[pnetGLOB_net_size]; + pnetGLOB_save_nets = renew pnetGLOB_save_nets[pnetGLOB_net_size]; + pnetGLOB_save_et = renew pnetGLOB_save_et[pnetGLOB_net_size]; +} + +class p_netstat { + + int number$; + char name$[12]; + + int net_count; + double ipackets; + double ierrors; + double idtsize; + double ihdrovhd; + double opackets; + double oerrors; + double odtsize; + double ohdrovhd; + double collisions; + double collpercent; + double nocanput; + double defer; + double ioctets; + double ooctets; + ulong_t ifspeed; + int iftype; + double utilization; + + p_netstat$() + { + int i; + int initialized = 0; + netif interface; + double et; + double now; + + /* do initialization code */ + if (initialized == 0) { + + pnetGLOB_net_ipackets = new double[pnetGLOB_net_size]; + pnetGLOB_net_idtsize = new double[pnetGLOB_net_size]; + pnetGLOB_net_ihdrovhd = new double[pnetGLOB_net_size]; + pnetGLOB_net_ierrors = new double[pnetGLOB_net_size]; + pnetGLOB_net_opackets = new double[pnetGLOB_net_size]; + pnetGLOB_net_odtsize = new double[pnetGLOB_net_size]; + pnetGLOB_net_ohdrovhd = new double[pnetGLOB_net_size]; + pnetGLOB_net_oerrors = new double[pnetGLOB_net_size]; + pnetGLOB_net_collisions = new double[pnetGLOB_net_size]; + pnetGLOB_net_defer = new double[pnetGLOB_net_size]; + pnetGLOB_net_nocanput = new double[pnetGLOB_net_size]; + pnetGLOB_net_ioctets = new double[pnetGLOB_net_size]; + pnetGLOB_net_ooctets = new double[pnetGLOB_net_size]; + pnetGLOB_save_nets = new netif[pnetGLOB_net_size]; + pnetGLOB_save_et = new double[pnetGLOB_net_size]; + + /* grab initial info from netif class */ + for(refresh$(interface), i=0; i= net_count)) { + number$ = -1; + return; + } + + /* find out how many seconds have elapsed */ + now = gethrtime() * NANODOUBLE; + et = (now - pnetGLOB_save_et[i]); + + /* do computes if at least a second has gone by */ + if (et > 1.0) { + /* save the time */ + pnetGLOB_save_et[i] = now; + + /* grab the info for this net */ + interface.number$ = i; + refresh$(interface); + + /* compute new values */ + pnetGLOB_net_ipackets[i] = + UD_DIFF(interface.ipackets, pnetGLOB_save_nets[i].ipackets) / et; + pnetGLOB_net_ierrors[i] = + UD_DIFF(interface.ierrors, pnetGLOB_save_nets[i].ierrors) / et; + pnetGLOB_net_opackets[i] = + UD_DIFF(interface.opackets, pnetGLOB_save_nets[i].opackets) / et; + pnetGLOB_net_oerrors[i] = + UD_DIFF(interface.oerrors, pnetGLOB_save_nets[i].oerrors) / et; + pnetGLOB_net_collisions[i] = + UD_DIFF(interface.collisions, pnetGLOB_save_nets[i].collisions) / et; + pnetGLOB_net_nocanput[i] = + UD_DIFF(interface.nocanput, pnetGLOB_save_nets[i].nocanput) / et; + pnetGLOB_net_defer[i] = + UD_DIFF(interface.defer, pnetGLOB_save_nets[i].defer) / et; + pnetGLOB_net_ioctets[i] = + UD_DIFF(interface.ioctets, pnetGLOB_save_nets[i].ioctets) / et; + pnetGLOB_net_ooctets[i] = + UD_DIFF(interface.ooctets, pnetGLOB_save_nets[i].ooctets) / et; + if ( pnetGLOB_net_ipackets[i] == 0.0 ) { + pnetGLOB_net_idtsize[i] = 0.0; + pnetGLOB_net_ihdrovhd[i] = 0.0; + } else { + pnetGLOB_net_idtsize[i] = pnetGLOB_net_ioctets[i] / pnetGLOB_net_ipackets[i]; + pnetGLOB_net_ihdrovhd[i] = 100 * (40 * pnetGLOB_net_ipackets[i] / ( 40 * pnetGLOB_net_ipackets[i] + pnetGLOB_net_ioctets[i] )); + } + if ( pnetGLOB_net_opackets[i] == 0.0 ) { + pnetGLOB_net_odtsize[i] = 0.0; + pnetGLOB_net_ohdrovhd[i] = 0.0; + } else { + pnetGLOB_net_odtsize[i] = pnetGLOB_net_ooctets[i] / pnetGLOB_net_opackets[i]; + pnetGLOB_net_ohdrovhd[i] = 100 * (40 * pnetGLOB_net_opackets[i] / ( 40 * pnetGLOB_net_opackets[i] + pnetGLOB_net_ooctets[i] )); + } + /* save old */ + pnetGLOB_save_nets[i] = interface; + } + + /* update and return */ + strncpy(name$, pnetGLOB_save_nets[i].name$, 12); + ipackets = pnetGLOB_net_ipackets[i]; + ierrors = pnetGLOB_net_ierrors[i]; + opackets = pnetGLOB_net_opackets[i]; + oerrors = pnetGLOB_net_oerrors[i]; + collisions = pnetGLOB_net_collisions[i]; + if (opackets > 0.0) { + collpercent = collisions * 100.0 / opackets; + } else { + collpercent = 0.0; + } + nocanput = pnetGLOB_net_nocanput[i]; + defer = pnetGLOB_net_defer[i]; + ioctets = pnetGLOB_net_ioctets[i]; + ooctets = pnetGLOB_net_ooctets[i]; + idtsize = pnetGLOB_net_idtsize[i]; + ihdrovhd = pnetGLOB_net_ihdrovhd[i]; + odtsize = pnetGLOB_net_odtsize[i]; + ohdrovhd = pnetGLOB_net_ohdrovhd[i]; + ifspeed = pnetGLOB_save_nets[i].ifspeed; + iftype = pnetGLOB_save_nets[i].iftype; + if (ifspeed != 0) { + utilization = (((ioctets + ooctets) * 8) * 100.0) / ifspeed; + } else { + utilization = 0.0; + } + } +}; + +#endif _P_NETSTAT_CLASS_SE_ Added: trunk/orca/lib/SE/3.4/orca_p_vmstat_class.se ============================================================================== --- (empty file) +++ trunk/orca/lib/SE/3.4/orca_p_vmstat_class.se Wed Feb 9 12:08:55 2005 @@ -0,0 +1,386 @@ +// +// Copyright (c) 1993-2001 by Richard Pettit. All rights reserved. +// +// Some of this work was derived from include files containing the following +// copyrights. +// +// Copyright (c) 1986-1994 by Sun Microsystems, Inc. +// Copyright (c) 1983-1989 by AT&T +// Copyright (c) 1980-1993 by The Regents of the University of California. +// +// The work as a whole represents unique intellectual property and is +// copyright by Richard Pettit as shown on the first line. +// + +#ifndef _P_VMSTAT_CLASS_SE_ +#define _P_VMSTAT_CLASS_SE_ + +#include +#include +#include + +/* for memory computation */ +#define PGTOK(n) (((n) * pagesize) / 1024) +#define DELTA(name) (new_vminfo.name - old_vminfo.name) +#define COMPUTE(name) PGTOK(DELTA(name) / updates) + +/* make the code easier on the eye */ +#define CSI_DIFF(name) \ + pvmGLOB_cpu_sysinfo[i].name = \ + (csi.name - pvmGLOB_old_cpu_sysinfo[i].name) +#define CSI_PCT(name) \ + pvmGLOB_cpu_sysinfo[i].name = (pvmGLOB_cpu_sysinfo[i].name / total) * 100.0 + +#define CSIPCT(name) (100.0 * name / (hz * pvmGLOB_etime[i])) + +#define CVI_DIFF(name) \ + pvmGLOB_cpu_vminfo[i].name = \ + (cvi.name - pvmGLOB_old_cpu_vminfo[i].name) + +double pvmGLOB_etime[]; +ulong pvmGLOB_old_time[]; +ks_cpu_sysinfo pvmGLOB_cpu_sysinfo[]; +ks_cpu_sysinfo pvmGLOB_old_cpu_sysinfo[]; +ks_cpu_vminfo pvmGLOB_cpu_vminfo[]; +ks_cpu_vminfo pvmGLOB_old_cpu_vminfo[]; + +int pvmGLOB_cpu_size; + +pvmGLOB_realloc() +{ + pvmGLOB_etime = renew pvmGLOB_etime [pvmGLOB_cpu_size]; + pvmGLOB_old_time = renew pvmGLOB_old_time [pvmGLOB_cpu_size]; + pvmGLOB_cpu_sysinfo = renew pvmGLOB_cpu_sysinfo [pvmGLOB_cpu_size]; + pvmGLOB_old_cpu_sysinfo = renew pvmGLOB_old_cpu_sysinfo [pvmGLOB_cpu_size]; + pvmGLOB_cpu_vminfo = renew pvmGLOB_cpu_vminfo [pvmGLOB_cpu_size]; + pvmGLOB_old_cpu_vminfo = renew pvmGLOB_old_cpu_vminfo [pvmGLOB_cpu_size]; +} + +class p_vmstat { + + /* which cpu */ + int number$; + int instance; /* instance number from the kernel */ + int ncpus; /* current total number of CPUs */ + + /* these values are numbers of procs */ + double runque; + double waiting; + double swpque; + + /* these values are in Kbytes */ + int swap_avail; + int freemem; + + double pgrec; /* page reclaims (include pageout) */ + double pgfrec; /* page reclaims from free list */ + double pgin; /* pageins */ + double pgout; /* pageouts */ + double pgswapin; /* pages swapped in */ + double pgswapout; /* pages swapped out */ + double dfree; /* pages freed by daemon or auto */ + + double hat_fault; /* minor page faults via hat_fault() */ + double as_fault; /* minor page faults via as_fault() */ + double maj_fault; /* major page faults */ + double prot_fault; /* protection faults */ + double cow_fault; /* copy-on-write faults */ + double zfod; /* pages zero filled on demand */ + + double sysfork; /* forks */ + double sysvfork; /* vforks */ + double sysexec; /* execs */ + + double namei; /* pathname lookups */ + double ufsiget; /* pathname lookups */ + double ufsdirblk; /* directory block read */ + + double ufsinopage; /* inodes taken with no attached pgs */ + + /* these values are per second */ + double pages_in; /* pages paged in */ + double pages_out; /* pages paged out */ + double swapins; /* swap-in occurrences */ + double swapouts; /* swap-out occurrences */ + double scan; /* pages scanned */ + double pgrrun; /* how many times did pageout run */ + + double smtx; /* sleeps on a mutex per sec - mutex adaptive enter */ + double interrupts; /* interrupts including clock */ + double intrthread; /* interrupts as threads (below clock) */ + double system_calls; + double context_switches; + double invol_switches; + double trap; + + /* these are percentages of total over the last period */ + double user_time; + double system_time; + double wait_time; + double idle_time; + + p_vmstat$() + { + int i; + int n; + double updates; + int initialized = 0; + int last_number; + double hz = sysconf(_SC_CLK_TCK); + long pagesize = sysconf(_SC_PAGESIZE); + double total; + ulong itime; + ulong new_time; + ks_cpu_sysinfo csi; + ks_cpu_vminfo cvi; + ks_system_misc kstat$misc; + ks_sysinfo kstat$info; + ks_sysinfo old_sysinfo; + ks_sysinfo new_sysinfo; + ks_vminfo kstat$vminfo; + ks_vminfo old_vminfo; + ks_vminfo new_vminfo; + + // allow this to change each time + ncpus = sysconf(_SC_NPROCESSORS_ONLN); + + /* grab initial values */ + if (initialized == 0) { + pvmGLOB_cpu_size = ncpus; + + pvmGLOB_etime = new double[pvmGLOB_cpu_size]; + pvmGLOB_old_time = new ulong[pvmGLOB_cpu_size]; + pvmGLOB_cpu_sysinfo = new ks_cpu_sysinfo[pvmGLOB_cpu_size]; + pvmGLOB_old_cpu_sysinfo = new ks_cpu_sysinfo[pvmGLOB_cpu_size]; + pvmGLOB_cpu_vminfo = new ks_cpu_vminfo[pvmGLOB_cpu_size]; + pvmGLOB_old_cpu_vminfo = new ks_cpu_vminfo[pvmGLOB_cpu_size]; + + n = kstat$misc.clk_intr; + for(i=0; i pvmGLOB_cpu_size) { + pvmGLOB_cpu_size = ncpus; + pvmGLOB_realloc(); + } + + /* select which cpu */ + i = number$; + if (i < 0 || i >= ncpus) { + number$ = -1; + return; + } + instance = pvmGLOB_old_cpu_sysinfo[i].instance$; + + /* how much time has gone by */ + new_time = kstat$misc.clk_intr; + itime = new_time - pvmGLOB_old_time[i]; + + /* no time has gone by, return */ + if (itime == 0) { + if (i != last_number) { + smtx = pvmGLOB_cpu_sysinfo[i].mutex_adenters/pvmGLOB_etime[i]; + interrupts = pvmGLOB_cpu_sysinfo[i].intr/pvmGLOB_etime[i]; + intrthread = pvmGLOB_cpu_sysinfo[i].intrthread/pvmGLOB_etime[i]; + system_calls = pvmGLOB_cpu_sysinfo[i].syscall/pvmGLOB_etime[i]; + trap = pvmGLOB_cpu_sysinfo[i].trap/pvmGLOB_etime[i]; + context_switches = pvmGLOB_cpu_sysinfo[i].pswitch/pvmGLOB_etime[i]; + invol_switches = pvmGLOB_cpu_sysinfo[i].inv_swtch/pvmGLOB_etime[i]; + user_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_USER]); + system_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_KERNEL]); + wait_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_WAIT]); + idle_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_IDLE]); + + sysfork = pvmGLOB_cpu_sysinfo[i].sysfork/pvmGLOB_etime[i]; + sysvfork = pvmGLOB_cpu_sysinfo[i].sysvfork/pvmGLOB_etime[i]; + sysexec = pvmGLOB_cpu_sysinfo[i].sysexec/pvmGLOB_etime[i]; + + namei = pvmGLOB_cpu_sysinfo[i].namei/pvmGLOB_etime[i]; + ufsiget = pvmGLOB_cpu_sysinfo[i].ufsiget/pvmGLOB_etime[i]; + ufsdirblk = pvmGLOB_cpu_sysinfo[i].ufsdirblk/pvmGLOB_etime[i]; + + ufsinopage = pvmGLOB_cpu_sysinfo[i].ufsinopage/pvmGLOB_etime[i]; + + pgrec = pvmGLOB_cpu_vminfo[i].pgrec/pvmGLOB_etime[i]; + pgfrec = pvmGLOB_cpu_vminfo[i].pgfrec/pvmGLOB_etime[i]; + pgin = pvmGLOB_cpu_vminfo[i].pgin/pvmGLOB_etime[i]; + pgout = pvmGLOB_cpu_vminfo[i].pgout/pvmGLOB_etime[i]; + dfree = pvmGLOB_cpu_vminfo[i].dfree/pvmGLOB_etime[i]; + + hat_fault = pvmGLOB_cpu_vminfo[i].hat_fault/pvmGLOB_etime[i]; + as_fault = pvmGLOB_cpu_vminfo[i].as_fault/pvmGLOB_etime[i]; + maj_fault = pvmGLOB_cpu_vminfo[i].maj_fault/pvmGLOB_etime[i]; + prot_fault = pvmGLOB_cpu_vminfo[i].prot_fault/pvmGLOB_etime[i]; + cow_fault = pvmGLOB_cpu_vminfo[i].cow_fault/pvmGLOB_etime[i]; + zfod = pvmGLOB_cpu_vminfo[i].zfod/pvmGLOB_etime[i]; + + pages_in = pvmGLOB_cpu_vminfo[i].pgpgin/pvmGLOB_etime[i]; + pages_out = pvmGLOB_cpu_vminfo[i].pgpgout/pvmGLOB_etime[i]; + swapins = pvmGLOB_cpu_vminfo[i].swapin/pvmGLOB_etime[i]; + swapouts = pvmGLOB_cpu_vminfo[i].swapout/pvmGLOB_etime[i]; + scan = pvmGLOB_cpu_vminfo[i].scan/pvmGLOB_etime[i]; + pgrrun = pvmGLOB_cpu_vminfo[i].pgrrun/pvmGLOB_etime[i]; + + last_number = i; + } + return; + } + pvmGLOB_etime[i] = itime / hz; + pvmGLOB_old_time[i] = new_time; + + csi.number$ = i; + refresh$(csi); + + cvi.number$ = i; + refresh$(cvi); + + new_sysinfo = kstat$info; + updates = new_sysinfo.updates - old_sysinfo.updates; + if (updates > 0.0) { + new_vminfo = kstat$vminfo; + } + + /* compute cpu sysinfo diffs */ + CSI_DIFF(mutex_adenters); + CSI_DIFF(intr); + CSI_DIFF(intrthread); + CSI_DIFF(syscall); + CSI_DIFF(pswitch); + CSI_DIFF(inv_swtch); + CSI_DIFF(trap); + CSI_DIFF(cpu[CPU_USER]); + CSI_DIFF(cpu[CPU_KERNEL]); + CSI_DIFF(cpu[CPU_WAIT]); + CSI_DIFF(cpu[CPU_IDLE]); + CSI_DIFF(wait[W_IO]); + CSI_DIFF(wait[W_SWAP]); + CSI_DIFF(wait[W_PIO]); + + CSI_DIFF(sysfork); + CSI_DIFF(sysvfork); + CSI_DIFF(sysexec); + + CSI_DIFF(namei); + CSI_DIFF(ufsiget); + CSI_DIFF(ufsdirblk); + + CSI_DIFF(ufsinopage); + + /* compute percentages + total = pvmGLOB_cpu_sysinfo[i].cpu[CPU_USER] + + pvmGLOB_cpu_sysinfo[i].cpu[CPU_KERNEL] + + pvmGLOB_cpu_sysinfo[i].cpu[CPU_WAIT] + + pvmGLOB_cpu_sysinfo[i].cpu[CPU_IDLE]; + CSI_PCT(cpu[CPU_USER]); + CSI_PCT(cpu[CPU_KERNEL]); + CSI_PCT(cpu[CPU_WAIT]); + CSI_PCT(cpu[CPU_IDLE]); + */ + + /* save new values */ + pvmGLOB_old_cpu_sysinfo[i] = csi; + + CVI_DIFF(pgrec); + CVI_DIFF(pgfrec); + CVI_DIFF(pgin); + CVI_DIFF(pgout); + CVI_DIFF(dfree); + + CVI_DIFF(hat_fault); + CVI_DIFF(as_fault); + CVI_DIFF(maj_fault); + CVI_DIFF(prot_fault); + CVI_DIFF(zfod); + CVI_DIFF(cow_fault); + + /* compute page/swap values */ + pvmGLOB_cpu_vminfo[i].pgpgin = + ((cvi.pgpgin - pvmGLOB_old_cpu_vminfo[i].pgpgin) * pagesize) / 1024; + pvmGLOB_cpu_vminfo[i].pgpgout = + ((cvi.pgpgout - pvmGLOB_old_cpu_vminfo[i].pgpgout) * pagesize) / 1024; + CVI_DIFF(swapin); + CVI_DIFF(swapout); + CVI_DIFF(scan); + CVI_DIFF(pgrrun); + + /* save new values */ + pvmGLOB_old_cpu_vminfo[i] = cvi; + + /* update and return */ + smtx = pvmGLOB_cpu_sysinfo[i].mutex_adenters/pvmGLOB_etime[i]; + interrupts = pvmGLOB_cpu_sysinfo[i].intr/pvmGLOB_etime[i]; + intrthread = pvmGLOB_cpu_sysinfo[i].intrthread/pvmGLOB_etime[i]; + system_calls = pvmGLOB_cpu_sysinfo[i].syscall/pvmGLOB_etime[i]; + context_switches = pvmGLOB_cpu_sysinfo[i].pswitch/pvmGLOB_etime[i]; + invol_switches = pvmGLOB_cpu_sysinfo[i].inv_swtch/pvmGLOB_etime[i]; + trap = pvmGLOB_cpu_sysinfo[i].trap/pvmGLOB_etime[i]; + user_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_USER]); + system_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_KERNEL]); + wait_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_WAIT]); + idle_time = CSIPCT(pvmGLOB_cpu_sysinfo[i].cpu[CPU_IDLE]); + + sysfork = pvmGLOB_cpu_sysinfo[i].sysfork/pvmGLOB_etime[i]; + sysvfork = pvmGLOB_cpu_sysinfo[i].sysvfork/pvmGLOB_etime[i]; + sysexec = pvmGLOB_cpu_sysinfo[i].sysexec/pvmGLOB_etime[i]; + + namei = pvmGLOB_cpu_sysinfo[i].namei/pvmGLOB_etime[i]; + ufsiget = pvmGLOB_cpu_sysinfo[i].ufsiget/pvmGLOB_etime[i]; + ufsdirblk = pvmGLOB_cpu_sysinfo[i].ufsdirblk/pvmGLOB_etime[i]; + + ufsinopage = pvmGLOB_cpu_sysinfo[i].ufsinopage/pvmGLOB_etime[i]; + + pgrec = pvmGLOB_cpu_vminfo[i].pgrec/pvmGLOB_etime[i]; + pgfrec = pvmGLOB_cpu_vminfo[i].pgfrec/pvmGLOB_etime[i]; + pgin = pvmGLOB_cpu_vminfo[i].pgin/pvmGLOB_etime[i]; + pgout = pvmGLOB_cpu_vminfo[i].pgout/pvmGLOB_etime[i]; + dfree = pvmGLOB_cpu_vminfo[i].dfree/pvmGLOB_etime[i]; + + hat_fault = pvmGLOB_cpu_vminfo[i].hat_fault/pvmGLOB_etime[i]; + as_fault = pvmGLOB_cpu_vminfo[i].as_fault/pvmGLOB_etime[i]; + maj_fault = pvmGLOB_cpu_vminfo[i].maj_fault/pvmGLOB_etime[i]; + prot_fault = pvmGLOB_cpu_vminfo[i].prot_fault/pvmGLOB_etime[i]; + cow_fault = pvmGLOB_cpu_vminfo[i].cow_fault/pvmGLOB_etime[i]; + zfod = pvmGLOB_cpu_vminfo[i].zfod/pvmGLOB_etime[i]; + + pages_in = pvmGLOB_cpu_vminfo[i].pgpgin/pvmGLOB_etime[i]; + pages_out = pvmGLOB_cpu_vminfo[i].pgpgout/pvmGLOB_etime[i]; + swapins = pvmGLOB_cpu_vminfo[i].swapin/pvmGLOB_etime[i]; + swapouts = pvmGLOB_cpu_vminfo[i].swapout/pvmGLOB_etime[i]; + scan = pvmGLOB_cpu_vminfo[i].scan/pvmGLOB_etime[i]; + pgrrun = pvmGLOB_cpu_vminfo[i].pgrrun/pvmGLOB_etime[i]; + + if (updates > 0.0) { + freemem = COMPUTE(freemem); + swap_avail = COMPUTE(swap_avail); + + runque = (new_sysinfo.runque - old_sysinfo.runque) / updates; + waiting = (new_sysinfo.waiting - old_sysinfo.waiting) / updates; + swpque = (new_sysinfo.swpque - old_sysinfo.swpque) / updates; + + /* save old memory values */ + old_sysinfo = new_sysinfo; + old_vminfo = new_vminfo; + } + } +}; + +#endif /* _P_VMSTAT_CLASS_SE_ */ Added: trunk/orca/lib/SE/3.4/orca_process_class.se ============================================================================== --- (empty file) +++ trunk/orca/lib/SE/3.4/orca_process_class.se Wed Feb 9 12:08:55 2005 @@ -0,0 +1,912 @@ +// +// Copyright (c) 1995-1998, by Sun Microsystems, Inc. +// All Rights Reserved +// + +#ifndef _PROCESS_CLASS_SE_ +#define _PROCESS_CLASS_SE_ + +// 16 Oct 01 richp - more clean ups, some fields not being computed +// 19 Sep 01 richp - replaced struct_fill and changed long to pointer_t +// process class 19 Feb 98 Adrian - 2.6 extras added +// measured and sampled cpu comparison version 18/5/98 +// vmem_delta added for process_rules 27 Nov 98 +// added processor set info 16 Apr 99 +// merged rules version 22 Apri 99 +// added lwp info 5-27-99 Rick Weisner +// added PCUNSET 11-05-99 Rick Weisner +// added se_trees 08-2000 Rick Weisner +// patched linked list login Jul 2001 Rick Weisner + +// Obtain data averaged over the interval between updates +// return one process at a time, snapshot all good stuff +// in one update then provide index$, pid$ methods to extract groups +// of processes. +// Store data in raw form taken from psinfo and pusage ioctls, and +// process it when called up by class. Feeds data to workload_class.se + + +#if MINOR_VERSION < 60 +# error "process_class only works on 2.6 or newer" +#endif + +#include + +long msaccton[2] = { PCSET, PR_MSACCT | PR_MSFORK }; +long msacctoff[2] = { PCUNSET, PR_MSACCT }; + +// codes for action$ +#define PROC_ACTION_INIT 0 // starting point -> next index +#define PROC_ACTION_PID 1 // get the specified pid + // do not sample all PIDS +#define PROC_ACTION_NEXT_INDEX 2 // index order is based on /proc +#define PROC_ACTION_NEXT_PID 3 // search for pid and return data + // do sample all PIDS +#define PROC_ACTION_NEXT_LWP 4 // search for lwp and return data + +// index$ returns -1 if no more data +// proc data updates if index$ is -1 + +struct pr_header_t { + long number_lwps; + size_t size_of_entries; +}; + +struct lwp_prusage { + prusage_t lwp_pru; + long next_lwp_pru; +}; + +struct raw_proc_info_t { // all the per process info + pointer_t orp; // old prusage_t pointer + pointer_t nrp; // new prusage_t pointer + long nextpid; // next pid in list + long gencnt; // update generation counter + // stuff from prpsinfo_t + long pr_flag; // process flags + long pr_size; // size of process image in pages + long pr_oldsize; // previous size of process image + long pr_rssize; // resident set size in pages + long pr_pri; // priority, high value is high priority + char pr_nice; // nice for cpu usage + char pr_sname; // printable character representing pr_state + timestruc_t o_pr_time; // old sampled user+system CPU time + timestruc_t n_pr_time; // sampled user+system CPU time + timestruc_t o_pr_ctime; // old usr+sys cpu time for reaped children + timestruc_t n_pr_ctime; // new usr+sys cpu time for reaped children + long pr_uid; // real user id + long pr_ppid; // process id of parent + int pr_bindpset; // processor set binding +#define PRCLSZ 8 + char pr_clname[PRCLSZ]; // scheduling class name +#define PRFNSZ 16 + char pr_fname[PRFNSZ]; // last component of execed pathname +#define PRARGSZ 80 + char pr_psargs[PRARGSZ];// initial characters of arg list + int lwp_count; + pointer_t olwp; // pointers to prev. lwp prusage linked list + pointer_t nlwp; // pointers to current lwp prusage linked list +}; + +struct lwp_pr_info { + int lwp_id; // always contains lwp_id + double timestamp; // last time lwp was measured + double creation; // lwp start time + double termination; // lwp termination time stamp + double user_time; // user time in this interval + double system_time; // system call time in this interval + double trap_time; // system trap time in interval + double text_pf_time; // text page fault wait in interval + double data_pf_time; // data page fault wait in interval + double kernel_pf_time; // kernel page fault wait in interval + double user_lock_time; // user lock wait in interval + double sleep_time; // all other sleep time + double cpu_wait_time; // time on runqueue waiting for CPU + double stoptime; // time stopped from ^Z + ulong syscalls; // syscall/interval for this process + ulong maj_faults; // majf/interval + ulong min_faults; // minf/interval + ulong total_swaps; // swapout count + ulong inblocks; // input blocks/interval + ulong outblocks; // output blocks/interval + ulong messages; // msgin+msgout/interval + ulong signals; // signals/interval + ulong vcontexts; // voluntary context switches/interval + ulong icontexts; // in-ditto + ulong charios; // characters in and out/interval + ulong next_class; +}; +// the process class that does all the real work + +// get both types of hires timestamp into a common more useful form +#define timestruc(t) (t.tv_sec + (t.tv_nsec / 1000000000.0)) +#define timeval(t) (t.tv_sec + (t.tv_usec / 1000000.0)) +#define hr_min_sec(t) sprintf("%.3f", timestruc(t)) + +// double timestruc(timestruc_t ts_time) { +// return ts_time.tv_sec + (ts_time.tv_nsec / 1000000000.0); +// } + +// double timeval(timeval_t tv_time) { +// return tv_time.tv_sec + (tv_time.tv_usec / 1000000.0); +// } + +// string hr_min_sec(timestruc_t ts) { +// char buf[80]; +// double tmp; +// tmp = timestruc(ts); +// buf = sprintf("%.3f", tmp); +// return buf; +// } + +msprint(prusage_t pru, int pid, string cmd, string arg) { + puts("\n--------------- BEGIN ----------------"); + printf("%d %s %s\n", pid, cmd, arg); + printf("Elapsed time %12s ", hr_min_sec(pru.pr_rtime)); + printf("Create time %s Timestamp %s\n", hr_min_sec(pru.pr_create), + hr_min_sec(pru.pr_tstamp)); + printf("User CPU time %12s ", hr_min_sec(pru.pr_utime)); + printf("System call time %12s\n", hr_min_sec(pru.pr_stime)); + printf("System trap time %12s ", hr_min_sec(pru.pr_ttime)); + printf("Text pfault sleep %12s\n", hr_min_sec(pru.pr_tftime)); + printf("Data pfault sleep %12s ", hr_min_sec(pru.pr_dftime)); + printf("Kernel pfault sleep %12s\n", hr_min_sec(pru.pr_kftime)); + printf("User lock sleep %12s ", hr_min_sec(pru.pr_ltime)); + printf("Other sleep time %12s\n", hr_min_sec(pru.pr_slptime)); + printf("Wait for CPU time %12s ", hr_min_sec(pru.pr_wtime)); + printf("Stopped time %12s\n", hr_min_sec(pru.pr_stoptime)); + printf("pf %d mf %d sw %d inb %d oub %d ms %d mr %d\n", + pru.pr_minf, pru.pr_majf, pru.pr_nswap, pru.pr_inblk, pru.pr_oublk, + pru.pr_msnd, pru.pr_mrcv); + printf("sig %d vctx %d ictx %d sysc %d ioch %d\n", + pru.pr_sigs, pru.pr_vctx, pru.pr_ictx, pru.pr_sysc, pru.pr_ioch); + puts("---------------- END -----------------"); +} + +class proc_class_t { + // input controls + int index$; // always contains current index or -1 + int pid$; // always contains current pid + // for ACTION_PID mode set pid$ and set index$ to -1 to get new data + int action$; + int off$; + int wantlwp$; // 0 = do not want lwps, 1 = want lsps + // summary totals + double lasttime; // timestamp for the end of the last update + int nproc; // current number of processes + int newproc; + int deadproc; + int missedproc; // number of fork+vfork - newproc + // output data for specified process + long flags; // latest pr_flag for the process + double interval; // measured time interval for averages + double timestamp; // last time process was measured + double creation; // process start time + double termination; // process termination time stamp + double elapsed; // elapsed time for all lwps in process + double total_user; // current totals in seconds + double total_system; + double total_sampled_cpu; + double total_child; + double user_time; // user time in this interval + double system_time; // system call time in this interval + double sampled_cpu; // total sampled cpu time + double trap_time; // system trap time in interval + double child_time; // child CPU in this interval + double text_pf_time; // text page fault wait in interval + double data_pf_time; // data page fault wait in interval + double kernel_pf_time; // kernel page fault wait in interval + double user_lock_time; // user lock wait in interval + double sleep_time; // all other sleep time + double cpu_wait_time; // time on runqueue waiting for CPU + double stoptime; // time stopped from ^Z + ulong syscalls; // syscall/interval for this process + ulong inblocks; // input blocks/interval + ulong outblocks; // output blocks/interval + ulong vmem_size; // size in KB + long vmem_delta; // size change in KB + ulong rmem_size; // RSS in KB +#ifdef XMAP + ulong pmem_size; // private mem in KB + ulong smem_size; // shared mem in KB +#endif + ulong maj_faults; // majf/interval + ulong min_faults; // minf/interval + ulong total_swaps; // swapout count + long priority; // current sched priority + long niceness; // current nice value + char sched_class[PRCLSZ]; // name of class + ulong messages; // msgin+msgout/interval + ulong signals; // signals/interval + ulong vcontexts; // voluntary context switches/interval + ulong icontexts; // in-ditto + ulong charios; // characters in and out/interval + ulong lwp_count; // number of lwps for the process + ulong lwp_max; // number of contributing lwps for the process + int uid; // current uid + long ppid; // parent pid + int bindpset; // processor set binding + char fname[PRFNSZ]; // last components of exec'd pathname + char args[PRARGSZ]; // initial part of arg list + ulong lwp_class_ptr; // head of linked list of lwp_class_ptrs + + proc$() { + ulong_t MAX_PID; + ulong_t pp; // pointer to malloc for raw proc info + ulong_t pp_tmp; // temp pointer to malloc for raw proc info + ulong_t pp_ret; // temp pointer to malloc for raw proc info + // chained using nextpid + ulong_t pp_tree; + raw_proc_info_t rpi; + raw_proc_info_t t_rpi; + prusage_t ou; // old and new usage data +#define NU nu[0] + prusage_t nu[1]; // array of one for read and ioctl +#define PS ps[0] + psinfo_t ps[1]; // format changes when read used + pr_header_t prh; + prusage_t plwp; + ulong pnu; + ulong pps; + int i; + dirent_t directory_data; + ulong directory_pointer; + ulong directory_entry; + ulong_t tag; + int process_number; // current link in chain + int first_process; // fixed first link in search chain + int previous_process; // last one used to build chain + int next_process; // next pid + int broken_chain; // flag that chain changed this time + int cleaning_chain; // flag that we are in cleanup mode + int pfd; + int lfd; // file descriptor for /prod/PID/lusage + char procname[64]; + char lwpname[64]; // String for /prod/PID/lusage + long gen; // number of generations of update + int err; + int new_entry; + ulong tmp; + double dtmp; + timeval_t tmp_tval[1]; + int pg_to_kb; + + // lwp working storage + prusage_t lwp_info; + pointer_t lwp_t_ptr; + pointer_t olwp_t_ptr; + lwp_prusage lwp_t_struct; + lwp_prusage olwp_t_struct; + lwp_pr_info lwp_t_class; + long lwp_t_class_ptr; + int ircw; + +// ********************************************************** + + if (action$ == PROC_ACTION_INIT) { + action$ = PROC_ACTION_NEXT_INDEX; + // open the directory containing the process data + directory_pointer = opendir("/proc"); + index$ = -1; + off$ = 0 ; + gen = -1; + wantlwp$ = 0; + first_process=-1; + gettimeofday(tmp_tval,0); + lasttime = timeval(tmp_tval[0]); + pg_to_kb = sysconf(_SC_PAGESIZE) / 1024; + pp_tree= int2int_init(); + if (pnu == 0 || pps == 0) { + pnu = malloc(sizeof(nu)); + pps = malloc(sizeof(ps)); + } + return; + } + + if (index$ == -1) { // update the data from /proc + // read the first entry in the directory + rewinddir(directory_pointer); + directory_entry = readdir(directory_pointer); // read . + directory_entry = readdir(directory_pointer); // read .. + directory_entry = readdir(directory_pointer); + MAX_PID=0; + nproc = 0; + newproc = 0; + deadproc = 0; + gen++; + previous_process = -1; + broken_chain = 0; + cleaning_chain = 0; + while(directory_entry != NULL) { + directory_data = *((dirent_t *) directory_entry); + // get the process number and open the data file + // only look at specified process + if (action$ == PROC_ACTION_PID) { + process_number = pid$; + directory_entry = NULL; + } else { + process_number = atoi(directory_data.d_name); + } + procname = sprintf("/proc/%d/usage", process_number); + pfd = open(procname, O_RDONLY, 0); + // file cannot be accessed if pfd = -1; ignore this process + // may be that there is no permission or just died + if (pfd != -1) { // start of good pfd + if ( process_number > MAX_PID ) { + MAX_PID = process_number ; + } + tag = process_number; + pp_tmp = NULL ; + pp_ret = int2int_get(pp_tree, tag); + if ( pp_ret != NULL) { + pp_tmp = ((ulong_t) *((ulong_t *) pp_ret)); + // Process Found + } + if (pp_tmp == NULL) { + // load the tree , new process + pp = malloc(sizeof(rpi)); + memset(pp, 0, sizeof(rpi)); + new_entry = 1; + broken_chain = 1; + pp_ret= int2int_put(pp_tree, tag, pp); + if ( pp_ret < 0 ) { + printf(" Error unable to insert into tree %d, %d , %x\n", + pp_ret, tag, pp); + exit(1); + } + pp_ret = int2int_get(pp_tree, tag); + pp_tmp = ((ulong_t) *((ulong_t *) pp_ret)); + if ( pp != pp_tmp) { + printf(" Error pointers do not match %x, %x \n", + pp, pp_tmp); + exit(1); + } + } else { + new_entry = 0; + // Process Found + } + + // get the existing or blank data + tag = process_number; + pp_ret = int2int_get(pp_tree, tag); + if ( pp_ret== NULL) { + printf(" Error pointer not found for process_number %d\n", + tag); + exit(1); + } + pp = ((ulong_t) *((ulong_t *) pp_ret)); + if ( pp == NULL) { + printf("process_number %d invalid2 \n", process_number); + exit(1); + } + rpi = *((raw_proc_info_t *) pp); + + // read usage info directly + // 2.6 specific, can read usage and psinfo without needing + // ownership or permissions on /proc entry but can't read + // directly into SE structure so go via malloc buffers + + err = read(pfd, pnu, sizeof(nu)); + close(pfd); + + // turn on msacct + + procname = sprintf("/proc/%d/ctl", process_number); + pfd = open(procname, O_WRONLY, 0); + if (pfd != -1) { + if ( off$ == 0 ) { + write(pfd, &msaccton, sizeof(msaccton)); + } else { + printf("%d ms accounting off \n", process_number ); + write(pfd, &msacctoff, sizeof(msaccton)); + } + close(pfd); + } + + // get usage + procname = sprintf("/proc/%d/psinfo", process_number); + pfd = open(procname, O_RDONLY, 0); + err += read(pfd, pps, sizeof(ps)); + NU = *((prusage_t *) pnu); + PS = *((psinfo_t *) pps); + close(pfd); + if (err == 0) { + // process went away since directory was opened + // unlikely but still need to tidy up mallocs + // when it is a new entry + if ( new_entry == 1 ) { + deadproc++; + free(pp); + tag = process_number; + pp_ret=int2int_put(pp_tree, tag, NULL); + if ( pp_ret < 0 ) { + printf("unable to free tag = %d \n",tag); + exit(1); + } + } + if (action$ == PROC_ACTION_PID) { + directory_entry = NULL; + } else { + directory_entry = readdir(directory_pointer); + } + continue; + } else { // good pfd + +// *************************************************************** + + if ( wantlwp$ == 1 ) { + // read the lwp info + lwpname = sprintf("/proc/%d/lusage", process_number); + lfd = open(lwpname, O_RDONLY, 0); + if ( lfd > 0 ) { + lwp_t_ptr = malloc(sizeof(prh)); + err = read(lfd, lwp_t_ptr, sizeof(prh)); + prh = *((pr_header_t *) lwp_t_ptr); + free(lwp_t_ptr); + if (err <= 0) { + printf("Error reading pr_header %s error code = %d \n", + lwpname, err); + } else { // good read of pr_head + // if there is an old lwp linked list free it + lwp_t_ptr = rpi.olwp ; + while ( lwp_t_ptr != NULL ) { + lwp_t_struct = *((lwp_prusage *) lwp_t_ptr); + free(lwp_t_ptr); + lwp_t_ptr = lwp_t_struct.next_lwp_pru ; + } + rpi.olwp = rpi.nlwp; + rpi.nlwp = NULL; + // create new lwp linked list + for (ircw=0; ircw lasttime) { + newproc++; + if (new_entry == 0) { + // leftover from an old process at same pid + if (rpi.orp != NULL) { + free(rpi.orp); + rpi.orp = NULL; // dump old rp, and overwrite new + } +// ***************** delete old lwp info ********************* + if ( wantlwp$ == 1 ) { + lwp_t_ptr = rpi.olwp ; + rpi.olwp = NULL; + while ( lwp_t_ptr != NULL ) { + lwp_t_struct = *((lwp_prusage *) lwp_t_ptr); + free(lwp_t_ptr); + lwp_t_ptr = lwp_t_struct.next_lwp_pru ; + } + } +// ***************** end delete old lwp info ********************* + } + // static psinfo needs updating + rpi.pr_uid = PS.pr_uid; + rpi.pr_ppid = PS.pr_ppid; + rpi.pr_bindpset = PS.pr_lwp.pr_bindpset; + rpi.pr_clname = PS.pr_lwp.pr_clname; + rpi.pr_fname = PS.pr_fname; + rpi.pr_psargs = PS.pr_psargs; + } + // update usage data + tmp = rpi.orp; // hang on to malloced data + rpi.orp = rpi.nrp; // switch new to old + if (tmp == NULL) { + rpi.nrp = malloc(sizeof(ou)); + } else { + rpi.nrp = tmp; + } + struct_empty(NU, rpi.nrp); // save whole block + // update dynamic psinfo data + rpi.pr_oldsize = rpi.pr_size; + rpi.pr_size = PS.pr_size; + rpi.pr_rssize = PS.pr_rssize; + rpi.pr_pri = PS.pr_lwp.pr_pri; + rpi.pr_nice = PS.pr_lwp.pr_nice; + rpi.pr_sname = PS.pr_lwp.pr_sname; + rpi.pr_flag = PS.pr_flag; + rpi.o_pr_time = rpi.n_pr_time; + rpi.n_pr_time = PS.pr_time; + rpi.o_pr_ctime = rpi.n_pr_ctime; + rpi.n_pr_ctime = PS.pr_ctime; + rpi.lwp_count = PS.pr_nlwp; + rpi.gencnt = gen; + struct_empty(rpi, pp); + nproc++; + // printf("processed %d \n" , process_number ); + } // end of good pfd + // step through the files in the directory ... + if (action$ == PROC_ACTION_PID) { + directory_entry = NULL; + } else { + directory_entry = readdir(directory_pointer); + } + } // end of directory +// ************************************************************** + // go through list and remove deadwood + // printf("first process_number %d \n",first_process); + process_number = first_process; + next_process = -1; + previous_process = -1; + while ( process_number > 0 ) { + // printf("processing %d \n",process_number); + if (process_number > 0 ) { + pp_ret = int2int_get(pp_tree, process_number); + if ( pp_ret == NULL) { + printf("unable to get process_number %d \n", process_number); + exit(1); + } + pp = ((ulong_t) *((ulong_t *) pp_ret)); + if ( pp == NULL) { + printf("process_number %d invalid4 \n",process_number); + exit(1); + } + rpi = *((raw_proc_info_t *) pp); // rpi <- pp + next_process = rpi.nextpid; + // printf("next process %d \n",next_process); + // unhook dead processes + if (rpi.gencnt != gen) { + deadproc++; + if (rpi.orp != NULL) { + free(rpi.orp); + rpi.orp = NULL; + } + if (rpi.nrp != NULL) { + free(rpi.nrp); + rpi.nrp = NULL; + } + if ( wantlwp$ == 1 ) { + lwp_t_ptr = rpi.olwp ; + while ( lwp_t_ptr != NULL ) { + lwp_t_struct = *((lwp_prusage *) lwp_t_ptr); + free(lwp_t_ptr); + lwp_t_ptr = lwp_t_struct.next_lwp_pru ; + } + lwp_t_ptr = t_rpi.nlwp ; + while ( lwp_t_ptr != NULL ) { + lwp_t_struct = *((lwp_prusage *) lwp_t_ptr); + free(lwp_t_ptr); + lwp_t_ptr = lwp_t_struct.next_lwp_pru ; + } + } + free(pp); + pp_ret = int2int_put(pp_tree, process_number , NULL); + if ( pp_ret < 0 ) { + printf("unable to free process_number \n"); + exit(1); + } + if ( previous_process > 0 ) { // there was a previous process + pp_tmp = int2int_get(pp_tree, previous_process); + if ( pp_tmp == NULL) { + printf("unable to get process_number %d \n", + previous_process); + exit(1); + } + pp = ((ulong_t) *((ulong_t *) pp_tmp)); + if ( pp == NULL) { + printf("process_number %d invalid5 \n", + previous_process); + exit(1); + } + rpi = *((raw_proc_info_t *) pp); // rpi <- pp + // printf("previous process %d \n",previous_process); + rpi.nextpid = next_process; + struct_empty(rpi, pp); + } else { + first_process = next_process; + } + } else { + // update previous process ptr + previous_process = process_number; + } + } + process_number = next_process; + } + // printf(" end of deadwood removal \n"); + gettimeofday(tmp_tval,0); + lasttime = timeval(tmp_tval[0]); + process_number = first_process; + index$ = -1; + } + // printf("done updating \n"); + // printf("MAX_PID = %d \n", MAX_PID); +// ****************************** end of update section ******************* + + if (action$ == PROC_ACTION_NEXT_INDEX ) { + // printf("PROC_ACTION_NEXT_INDEX \n"); + if (index$ == -1) { + process_number = first_process; + } else { + process_number = rpi.nextpid; + } + if (process_number < 0 || process_number > MAX_PID) { + // ran out of data + process_number = -1; + index$ = -1; + pid$ = -1; + // printf(" thats all there is \n"); + return; + } + index$++; + } + + if (action$ == PROC_ACTION_NEXT_PID) { + // printf("PROC_ACTION_NEXT_PID \n"); + if (index$ == -1) { + process_number = 0; + } else { + process_number++; + } + index$++; + // look for the next data + pp = NULL; + pp_ret=int2int_get(pp_tree,process_number); + if ( pp_ret != NULL ) { + pp = ((ulong_t) *((ulong_t *) pp_ret)); + } + while (process_number < MAX_PID && pp == NULL) { + process_number++; + pp = NULL; + pp_ret=int2int_get(pp_tree,process_number); + if ( pp_ret != NULL ) { + pp = ((ulong_t) *((ulong_t *) pp_ret)); + } + } + if (process_number < 0 || process_number > MAX_PID) { + // ran out of data + process_number = -1; + index$ = -1; + pid$ = -1; + // printf(" ran out of data NEXT PID \n"); + return; + } + } + + if (action$ == PROC_ACTION_PID) { + process_number = pid$; + index$ = 0; + } + + // common code to update class once process has been chosen + + pp_ret=int2int_get(pp_tree,process_number); + pp = NULL; + if (pp_ret != NULL) { + pp = ((ulong_t) *((ulong_t *) pp_ret)); + } + if ( pp != NULL) { + rpi = *((raw_proc_info_t *) pp); + // make sure that all class data is updated + // index$ is already set + pid$ = process_number; + uid = rpi.pr_uid; + // nproc, , are already set + missedproc = rpi.nextpid; // for debug until fork counting + + // nrp will always be set + NU = *((prusage_t *) rpi.nrp); + creation = timestruc(NU.pr_create); + timestamp = timestruc(NU.pr_tstamp); + termination = 0.0; // set later if process is dead + elapsed = timestruc(NU.pr_rtime); + total_user = timestruc(NU.pr_utime); + total_system = timestruc(NU.pr_stime); + total_child = timestruc(rpi.n_pr_ctime); + total_sampled_cpu = timestruc(rpi.n_pr_time); + flags = rpi.pr_flag; +#ifdef PDEBUG + msprint(NU, pid$, rpi.pr_fname, rpi.pr_psargs); +#endif + if (rpi.orp != NULL) { + ou = *((prusage_t *) rpi.orp); + interval = timestamp - timestruc(ou.pr_tstamp); + // interval should never be zero + if (interval == 0.0) { + printf("zero interval on pid %d state %c\n", pid$, rpi.pr_sname); + msprint(ou, pid$, fname, args); + interval = 1.0; + } + user_time = total_user - timestruc(ou.pr_utime); + system_time = total_system - timestruc(ou.pr_stime); + sampled_cpu = total_sampled_cpu - timestruc(rpi.o_pr_time); + trap_time = timestruc(NU.pr_ttime) - timestruc(ou.pr_ttime); + child_time = total_child - timestruc(rpi.o_pr_ctime); + text_pf_time = timestruc(NU.pr_tftime) - timestruc(ou.pr_tftime); + data_pf_time = timestruc(NU.pr_dftime) - timestruc(ou.pr_dftime); + kernel_pf_time = timestruc(NU.pr_kftime) - timestruc(ou.pr_kftime); + user_lock_time = timestruc(NU.pr_ltime) - timestruc(ou.pr_ltime); + sleep_time = timestruc(NU.pr_slptime) - timestruc(ou.pr_slptime); + cpu_wait_time = timestruc(NU.pr_wtime) - timestruc(ou.pr_wtime); + stoptime = timestruc(NU.pr_stoptime) - timestruc(ou.pr_stoptime); + syscalls = NU.pr_sysc - ou.pr_sysc; + inblocks = NU.pr_inblk - ou.pr_inblk; + outblocks = NU.pr_oublk - ou.pr_oublk; + maj_faults = NU.pr_majf - ou.pr_majf; + min_faults = NU.pr_minf - ou.pr_minf; + messages = (NU.pr_msnd + NU.pr_mrcv) - (ou.pr_msnd + ou.pr_mrcv); + signals = NU.pr_sigs - ou.pr_sigs; + vcontexts = NU.pr_vctx - ou.pr_vctx; + icontexts = NU.pr_ictx - ou.pr_ictx; + charios = NU.pr_ioch - ou.pr_ioch; + } else { + // new process will only have rpi.nrp set + interval = timestamp - creation; // elapsed time so far + if (interval == 0.0) { + printf("zero interval on pid %d state %c\n", pid$, rpi.pr_sname); + msprint(NU, pid$, fname, args); + interval = 1.0; + } + user_time = total_user; + system_time = total_system; + sampled_cpu = total_sampled_cpu; + trap_time = timestruc(NU.pr_ttime); + child_time = total_child; + text_pf_time = timestruc(NU.pr_tftime); + data_pf_time = timestruc(NU.pr_dftime); + kernel_pf_time = timestruc(NU.pr_kftime); + user_lock_time = timestruc(NU.pr_ltime); + sleep_time = timestruc(NU.pr_slptime); + cpu_wait_time = timestruc(NU.pr_wtime); + stoptime = timestruc(NU.pr_stoptime); + syscalls = NU.pr_sysc; + inblocks = NU.pr_inblk; + outblocks = NU.pr_oublk; + maj_faults = NU.pr_majf; + min_faults = NU.pr_minf; + messages = NU.pr_msnd + NU.pr_mrcv; + signals = NU.pr_sigs; + vcontexts = NU.pr_vctx; + icontexts = NU.pr_ictx; + charios = NU.pr_ioch; + } + vmem_size = rpi.pr_size; + vmem_delta = rpi.pr_size - rpi.pr_oldsize; + rmem_size = rpi.pr_rssize; + total_swaps = NU.pr_nswap; + priority = rpi.pr_pri; + niceness = rpi.pr_nice; + sched_class = rpi.pr_clname; + lwp_max = NU.pr_count; + lwp_count = rpi.lwp_count; + ppid = rpi.pr_ppid; + bindpset = rpi.pr_bindpset; + fname = rpi.pr_fname; + if (fname == "" && rpi.pr_sname == 'Z') { + fname = "Zombie"; + bindpset = -1; // no pset, but Zomb defaults to 0 + } + args = rpi.pr_psargs; + // bug in sched pid 0 gives 100% system time + if (pid$ == 0) { + total_system = 0.0; + system_time = 0.0; + } +#ifdef PDEBUG + printf("interval %.5f\n", interval); +#endif +// ******************************************************* + if ( wantlwp$ == 1 ) { + // process lwp info + lwp_t_ptr = lwp_class_ptr; + lwp_class_ptr = NULL; + // if there is an old lwp class linked list free it + while ( lwp_t_ptr != NULL ) { + lwp_t_class = *((lwp_pr_info *) lwp_t_ptr); + free(lwp_t_ptr); + lwp_t_ptr = lwp_t_class.next_class ; + } + // Process lwp information + if ( rpi.nlwp != NULL ) { + lwp_t_ptr = rpi.nlwp ; + while ( lwp_t_ptr != NULL) { + lwp_t_struct = *((lwp_prusage *) lwp_t_ptr); + lwp_t_class.lwp_id = lwp_t_struct.lwp_pru.pr_lwpid; + lwp_t_class.timestamp = timestruc(lwp_t_struct.lwp_pru.pr_tstamp); + lwp_t_class.creation = timestruc(lwp_t_struct.lwp_pru.pr_create); + lwp_t_class.termination = timestruc(lwp_t_struct.lwp_pru.pr_term); + lwp_t_class.user_time = timestruc(lwp_t_struct.lwp_pru.pr_utime); + lwp_t_class.system_time = timestruc(lwp_t_struct.lwp_pru.pr_stime) + timestruc(lwp_t_struct.lwp_pru.pr_ttime); + lwp_t_class.text_pf_time = timestruc(lwp_t_struct.lwp_pru.pr_tftime) ; + lwp_t_class.data_pf_time = timestruc(lwp_t_struct.lwp_pru.pr_dftime) ; + lwp_t_class.kernel_pf_time = timestruc(lwp_t_struct.lwp_pru.pr_kftime) ; + lwp_t_class.user_lock_time = timestruc(lwp_t_struct.lwp_pru.pr_ltime) ; + lwp_t_class.sleep_time = timestruc(lwp_t_struct.lwp_pru.pr_slptime) ; + lwp_t_class.cpu_wait_time = timestruc(lwp_t_struct.lwp_pru.pr_wtime) ; + lwp_t_class.stoptime = timestruc(lwp_t_struct.lwp_pru.pr_stoptime) ; + lwp_t_class.min_faults = lwp_t_struct.lwp_pru.pr_minf ; + lwp_t_class.maj_faults = lwp_t_struct.lwp_pru.pr_majf ; + lwp_t_class.total_swaps = lwp_t_struct.lwp_pru.pr_nswap; + lwp_t_class.inblocks = lwp_t_struct.lwp_pru.pr_inblk ; + lwp_t_class.outblocks = lwp_t_struct.lwp_pru.pr_oublk ; + lwp_t_class.messages = lwp_t_struct.lwp_pru.pr_msnd + lwp_t_struct.lwp_pru.pr_mrcv; + lwp_t_class.signals = lwp_t_struct.lwp_pru.pr_sigs; + lwp_t_class.vcontexts = lwp_t_struct.lwp_pru.pr_vctx; + lwp_t_class.icontexts = lwp_t_struct.lwp_pru.pr_ictx; + lwp_t_class.syscalls = lwp_t_struct.lwp_pru.pr_sysc; + lwp_t_class.charios = lwp_t_struct.lwp_pru.pr_ioch; + + olwp_t_ptr = rpi.olwp; + while ( olwp_t_ptr != NULL ) { + olwp_t_struct = *((lwp_prusage *) olwp_t_ptr); + if ( olwp_t_struct.lwp_pru.pr_lwpid == + lwp_t_struct.lwp_pru.pr_lwpid) { + break; + } + olwp_t_ptr = olwp_t_struct.next_lwp_pru ; + } + if ( olwp_t_ptr != NULL) { + lwp_t_class.user_time = lwp_t_class.user_time - timestruc(olwp_t_struct.lwp_pru.pr_utime); + lwp_t_class.system_time = lwp_t_class.system_time - timestruc(olwp_t_struct.lwp_pru.pr_stime) - timestruc(olwp_t_struct.lwp_pru.pr_ttime); + lwp_t_class.text_pf_time = lwp_t_class.text_pf_time - timestruc(olwp_t_struct.lwp_pru.pr_tftime) ; + lwp_t_class.data_pf_time = lwp_t_class.data_pf_time - timestruc(olwp_t_struct.lwp_pru.pr_dftime) ; + lwp_t_class.kernel_pf_time = lwp_t_class.kernel_pf_time - timestruc(olwp_t_struct.lwp_pru.pr_kftime) ; + lwp_t_class.user_lock_time = lwp_t_class.user_lock_time - timestruc(olwp_t_struct.lwp_pru.pr_ltime) ; + lwp_t_class.sleep_time = lwp_t_class.sleep_time - timestruc(olwp_t_struct.lwp_pru.pr_slptime) ; + lwp_t_class.cpu_wait_time = lwp_t_class.cpu_wait_time - timestruc(olwp_t_struct.lwp_pru.pr_wtime) ; + lwp_t_class.stoptime = lwp_t_class.stoptime - timestruc(olwp_t_struct.lwp_pru.pr_stoptime) ; + lwp_t_class.min_faults = lwp_t_class.min_faults - olwp_t_struct.lwp_pru.pr_minf ; + lwp_t_class.maj_faults = lwp_t_class.maj_faults - olwp_t_struct.lwp_pru.pr_majf ; + lwp_t_class.total_swaps = lwp_t_class.total_swaps - olwp_t_struct.lwp_pru.pr_nswap; + lwp_t_class.inblocks = lwp_t_class.inblocks - olwp_t_struct.lwp_pru.pr_inblk ; + lwp_t_class.outblocks = lwp_t_class.outblocks - olwp_t_struct.lwp_pru.pr_oublk ; + lwp_t_class.messages = lwp_t_class.messages - olwp_t_struct.lwp_pru.pr_msnd + lwp_t_struct.lwp_pru.pr_mrcv; + lwp_t_class.signals = lwp_t_class.signals - olwp_t_struct.lwp_pru.pr_sigs; + lwp_t_class.vcontexts = lwp_t_class.vcontexts - olwp_t_struct.lwp_pru.pr_vctx; + lwp_t_class.icontexts = lwp_t_class.icontexts - olwp_t_struct.lwp_pru.pr_ictx; + lwp_t_class.syscalls = lwp_t_class.syscalls - olwp_t_struct.lwp_pru.pr_sysc; + lwp_t_class.charios = lwp_t_class.charios - olwp_t_struct.lwp_pru.pr_ioch; + + } // end of if old pointer + lwp_t_class_ptr = malloc(sizeof(lwp_t_class)); + memset(lwp_t_class_ptr, NULL, sizeof(lwp_t_class)); + lwp_t_class.next_class = lwp_class_ptr; + lwp_class_ptr = lwp_t_class_ptr; + struct_empty(lwp_t_class, lwp_t_class_ptr); + lwp_t_ptr = lwp_t_struct.next_lwp_pru ; + } // end of while + } // end of if we have lwps + } // end of we want lwps + } else { // End if valid pp + process_number = -1; + index$ = -1; + pid$ = -1; + } + } +}; + +#endif Added: trunk/orca/lib/SE/3.4/workinfo_class.se ============================================================================== --- (empty file) +++ trunk/orca/lib/SE/3.4/workinfo_class.se Wed Feb 9 12:08:55 2005 @@ -0,0 +1,342 @@ +#ifndef _WORKINFO_CLASS_SE_ +#define _WORKINFO_CLASS_SE_ + +/*********************************************************** +* * +* Workinfo class is based on Adrian's workload class * +* * +***********************************************************/ + +/************************************************************************** +Usage notes - +This class is designed to collect process statistics for any group of +processes defined by executed command, command arguments, executing user, +and processor set binding. +This class looks for WORKLOAD_INFO environment variable to initialize. + +To initialize workload information set WORKLOAD_INFO in the environment +in the following way: +WORKLOAD_INFO=name,command,args,user,exact,cnt,pset;...;... +export WORKLOAD_INFO + +DO NOT use quotes ("") around string values (name,command,args,user). +To skip one of the parameters use a SINGLE space. Missing or skipped +parameters are ignored during process matching. +Missing name defaults to WorkloadN, where N is workload number. +Missing command, args, or user are skipped. +By default pset is set to -1, cnt and exact are set to 0; + +Set pset to -1 to unset matching on processor set. +Set exact to non-zero for exact matching, or 0 for pattern matching. +Set cnt to non-zero to only count the number of processes and threads +in a given workload. Other data is neither collected nor printed. + +If there is not enough process parameters defined in a set, workload +parameters initialized in order with supplied data and the rest of the +parameters are set to their default values. + +Set WORKLOAD_FIRSTMATCH=0 in the environment to match each process +for all workloads. +Set WORKLOAD_FIRSTMATCH=1 in the environment to match each process +for one workload only. + +If WORKINFO_PRINT is defined, workload information is printed after +initialization to allow for verification of workload data. + +Examples: +export WORKLOAD_INFO='SE,se.sparc' +Defines one workload with the name SE, command se.sparc, args and user +empty string, exact 0 (match patterns), and no processor set. + +export WORKLOAD_INFO='SE,se.sparc, , ,1' +The same as the above except matching is exact + +export WORKLOAD_INFO='SE,se.sparc;Ora, , ,oracle,1,1' +Defines two workloads. In addition to SE workload, defines a workload named Ora +that counts all processes owned by user oracle. + +Class usage example: +######################################## + +#include + +measure_workload() +{ + work_info_class_t ww; + + ww.number = -1; +#ifdef WORKLOAD_NO_TOTAL + refresh$(ww); +#endif // WORKLOAD_NO_TOTAL + for (refresh$(ww); ww.number != -1; refresh$(ww)) { + printf("Wrkld=%s, number of procs=%d\n",ww.w.name,ww.w.count); + printf("Wrkld=%s, number of threads=%d\n",ww.w.name,ww.w.info.lwp_count); + // Get other data if not just counting processes + if (ww.w.cnt == 0) { + printf("Wrkld=%s, cpu_usr=%d\n",ww.w.name,100.0*ww.w.info.user_time); + printf("Wrkld=%s, cpu_sys=%d\n",ww.w.name,100.0*(ww.w.info.system_time+ + ww.w.info.trap_time)); + printf("Wrkld=%s, cpu_wait=%d\n",ww.w.name,100.0*ww.w.info.cpu_wait_time); + <...> + } + } +<...> +} +######################################## + +**************************************************************************/ + +#include +#include +#include +#include +#include +#include + +struct work_info_t { + string name; // Used by orcallator for header names for this workload + string command; // String to match against command name + string args; // String to match against command args + string user; // String to match against user name + int exact; // Set to match exact names instead of patterns + int cnt; // Set to count processes and threads only + int pset; // Processor set to match against + int count; // Number of processes that matched + proc_class_t info; // Use same data type to accumulate data +}; + +int match_proc(proc_class_t p, work_info_t w) { + passwd_t pw; + pointer_t ppw; + + if (w.command != "") { // If command is defined and... + if(w.exact == 0) { // pattern matching and... + if(!(p.fname =~ w.command)) { // pattern does not match - + return 0; // exit and signal no match + } + } else { // exact command matching and... + if(p.fname != w.command) { // command does not match - + return 0; // exit and signal no match + } + } + } + + if (w.args != "") { // If args is defined and... + if(w.exact == 0) { // pattern matching and... + if(!(p.args =~ w.args)) { // pattern does not match - + return 0; // exit and signal no match + } + } else { // exact args matching and... + if(p.args != w.args) { // args does not match - + return 0; // exit and signal no match + } + } + } + + if (w.user != "") { // If user name is defined and... + ppw = getpwuid(p.uid); // Get user information for this process + if (ppw == 0) { // If unsuccessful... + return 0; // return no match + } + pw = *((passwd_t *) ppw); + if(w.exact == 0) { // pattern matching and... + if(!(pw.pw_name =~ w.user)) { // pattern does not match - + return 0; // exit and signal no match + } + } else { // exact user name matching and... + if(pw.pw_name != w.user) { // user name does not match - + return 0; // exit and signal no match + } + } + } + + if ((w.pset != -1) && (p.bindpset != w.pset)) { + return 0; + } + + return 1; +} + +class work_info_class_t { + int number; // Current workload + work_info_t w; // Data for current workload + + work_info$() { + work_info_t wi[]; // Workload data dynamic array + int wc = 0; // Number of workloads + int firstmatch; // Set to use first workload that matches only + string fmstring; + proc_class_t pp; // Underlying process class data (snapshot) + proc_class_t ppzero; // Used to zero out by copying + double iv; + int i; + string wstring; + string wstr; + string dstr; + ulong pwstring; + ulong pwstr; + int initialized = 0; + + if (initialized == 0) { // Initialize class + refresh$(pp); // Setup proc_class + fmstring = getenv("WORKLOAD_FIRSTMATCH"); // Load user defined matching policy + wstring = getenv("WORKLOAD_INFO"); // Load user defined data for matching + + // Set matching policy + if (fmstring != nil) { + firstmatch = atoi(fmstring); + } else { + // Default to each process in one workload only + firstmatch = 1; + } + + // Allocate memory for collecting totals + wi = new work_info_t[1]; + wi[wc].name = "Total"; + wi[wc].command = ""; + wi[wc].args = ""; + wi[wc].user = ""; + wi[wc].pset = -1; + + // Parse wstring into individual workloads + for (wstr = strtok_r(wstring, ";", &pwstring); wstr != nil; wstr = strtok_r(nil, ";", &pwstring)) { + // Allocate memory for this workload + wi = renew wi[++wc+1]; + wi[wc].name = strtok_r(wstr, ",", &pwstr); // Get name + if (wi[wc].name == nil || wi[wc].name == " ") { + wi[wc].name = sprintf("Workload%d", wc); + } + wi[wc].command = strtok_r(nil, ",", &pwstr); // Get command + if (wi[wc].command == nil || wi[wc].command == " ") { + wi[wc].command = ""; + } + wi[wc].args = strtok_r(nil, ",", &pwstr); // Get args + if (wi[wc].args == nil || wi[wc].args == " ") { + wi[wc].args = ""; + } + wi[wc].user = strtok_r(nil, ",", &pwstr); // Get user + if (wi[wc].user == nil || wi[wc].user == " ") { + wi[wc].user = ""; + } + dstr = strtok_r(nil, ",", &pwstr); // Get exact + if (dstr != nil) { + wi[wc].exact = atoi(dstr); + } + dstr = strtok_r(nil, ",", &pwstr); // Get cnt + if (dstr != nil) { + wi[wc].cnt = atoi(dstr); + } + dstr = strtok_r(nil, ",", &pwstr); // Get pset + if (dstr == nil || dstr == " ") { + wi[wc].pset = -1; + } else { + wi[wc].pset = atoi(dstr); + } + } + +#ifdef WORKINFO_PRINT + printf("\nWorkinfo class is initialized with the following data\n"); + printf("Number of workloads = %d, firstmatch = %d (%s)\n", + wc, firstmatch, (firstmatch == 0 ? "Match all workloads" : "Match each process only once")); + for(i=1; i <= wc; i++) { + printf("Workload number %3d\n-------------------\n", i); + printf("name .................... %s\n", wi[i].name); + printf("command ................. %s\n", wi[i].command); + printf("args .................... %s\n", wi[i].args); + printf("user .................... %s\n", wi[i].user); + printf("exact ................... %d\n", wi[i].exact); + printf("pset .................... %d\n", wi[i].pset); + printf("Only count the number of\nprocesses and threads ... %s\n\n", + (wi[i].cnt == 0 ? "No" : "Yes")); + } +#endif // WORKINFO_PRINT + + number = -1; + initialized = 1; + return; + } + + if (number != -1) { // Data is available + if (number > -1 && number < wc) { + w = wi[++number]; // Return next workload data + } else { + w = wi[0]; // Set w to Total data + number = -1; // Signal end of data + } + return; + } + + for(i=0; i <= wc; i++) { // Reset counters + wi[i].count = 0; + wi[i].info = ppzero; // Not easy to use memset instead + } + refresh$(pp); // Get the snapshot + while (pp.index$ != -1) { + if (pp.termination != 0.0) { + continue; // Don't add in dead processes + } + for(i=0; i <= wc; i++) { + if (i == 0 || // Accumulate totals + (match_proc(pp, wi[i]) != 0)) { + wi[i].info.interval = pp.interval; // Take the last interval seen + iv = pp.interval; + if (iv == 0.0) { iv = 1.0; } // Safety net + if (pp.creation < wi[i].info.creation) { // Take the earliest creation + wi[i].info.creation = pp.creation; + } + if (wi[i].cnt == 0) { + // Track individual times + wi[i].info.lasttime = pp.lasttime; + wi[i].info.total_user += pp.total_user; + wi[i].info.total_system += pp.total_system; + wi[i].info.total_child += pp.total_child; + // Intervals vary, so accumulate here + wi[i].info.user_time += pp.user_time/iv; + wi[i].info.system_time += pp.system_time/iv; + wi[i].info.trap_time += pp.trap_time/iv; + wi[i].info.child_time += pp.child_time/iv; + wi[i].info.text_pf_time += pp.text_pf_time/iv; + wi[i].info.data_pf_time += pp.data_pf_time/iv; + wi[i].info.kernel_pf_time += pp.kernel_pf_time/iv; + wi[i].info.user_lock_time += pp.user_lock_time/iv; + wi[i].info.sleep_time += pp.sleep_time/iv; + wi[i].info.cpu_wait_time += pp.cpu_wait_time/iv; + wi[i].info.stoptime += pp.stoptime/iv; + wi[i].info.syscalls += pp.syscalls/iv; + wi[i].info.inblocks += pp.inblocks/iv; + wi[i].info.outblocks += pp.outblocks/iv; + // Next four are sizes not rates + wi[i].info.vmem_size += pp.vmem_size; + wi[i].info.rmem_size += pp.rmem_size; +#ifdef XMAP + wi[i].info.pmem_size += pp.pmem_size; + wi[i].info.smem_size += pp.smem_size; +#endif + wi[i].info.maj_faults += pp.maj_faults/iv; + wi[i].info.min_faults += pp.min_faults/iv; + wi[i].info.total_swaps += pp.total_swaps/iv; + wi[i].info.messages += pp.messages/iv; + wi[i].info.signals += pp.signals/iv; + wi[i].info.vcontexts += pp.vcontexts/iv; + wi[i].info.icontexts += pp.icontexts/iv; + wi[i].info.charios += pp.charios/iv; + // Divide these three by wi[i].count + wi[i].info.priority += pp.priority; + wi[i].info.niceness += pp.niceness; + } + wi[i].info.lwp_max += pp.lwp_max; + wi[i].info.lwp_count += pp.lwp_count; + wi[i].count++; + if (firstmatch == 1 && i > 0) { // First match only counts + break; + } + } + } + refresh$(pp); // Next process + } + number = 0; + w = wi[number]; + } +}; + +#endif From blair at orcaware.com Sun Feb 13 19:37:07 2005 From: blair at orcaware.com (Blair Zajac) Date: Sun, 13 Feb 2005 19:37:07 -0800 Subject: [Orca-checkins] r413 - trunk/orca/lib Message-ID: <200502140337.j1E3b7jo031966@gw.orcaware.com> Author: blair Date: Sun Feb 13 19:33:49 2005 New Revision: 413 Modified: trunk/orca/lib/Makefile.in Log: * lib/Makefile.in (install): Make the directory $(libdir)/SE/3.4 when installing, otherwise the files in lib/SE/3.4 do not get installed correctly. Modified: trunk/orca/lib/Makefile.in ============================================================================== --- trunk/orca/lib/Makefile.in (original) +++ trunk/orca/lib/Makefile.in Sun Feb 13 19:33:49 2005 @@ -32,6 +32,7 @@ $(MKDIR) $(libdir)/SE/3.2.1 $(MKDIR) $(libdir)/SE/3.3 $(MKDIR) $(libdir)/SE/3.3.1 + $(MKDIR) $(libdir)/SE/3.4 @for f in Orca/*.pm; do \ echo $(INSTALL) -m 0644 $$f $(libdir)/Orca; \ $(INSTALL) -m 0644 $$f $(libdir)/Orca; \ From blair at orcaware.com Tue Feb 15 20:42:10 2005 From: blair at orcaware.com (Blair Zajac) Date: Tue, 15 Feb 2005 20:42:10 -0800 Subject: [Orca-checkins] r414 - trunk/orca/data_gatherers/orcallator Message-ID: <200502160442.j1G4gAfl008097@gw.orcaware.com> Author: blair Date: Tue Feb 15 20:40:13 2005 New Revision: 414 Modified: trunk/orca/data_gatherers/orcallator/orcallator.cfg.in Log: * data_gatherers/orcallator/orcallator.cfg.in: Add the SUNW,bge Gigabit Ethernet driver for the Broadcom BCM5703C or Broadcom BCM5704 controllers to the list of devices matched in the Gigabit Interface Bits Per Second plots. Modified: trunk/orca/data_gatherers/orcallator/orcallator.cfg.in ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.cfg.in (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.cfg.in Tue Feb 15 20:40:13 2005 @@ -356,7 +356,7 @@ plot { title %g Interface Bits Per Second: $1 source orcallator -data 1024 * 8 * ((?:(?:ce)|(?:fjge)|(?:v?ge)|(?:skge))\d+)InKB/s +data 1024 * 8 * ((?:(?:bge)|(?:ce)|(?:fjge)|(?:v?ge)|(?:skge))\d+)InKB/s data 1024 * 8 * $1OuKB/s line_type area line_type line1 From blair at orcaware.com Tue Feb 15 22:24:34 2005 From: blair at orcaware.com (Blair Zajac) Date: Tue, 15 Feb 2005 22:24:34 -0800 Subject: [Orca-checkins] r415 - in trunk/orca: . packages/Time-HiRes-1.65 packages/Time-HiRes-1.66 packages/Time-HiRes-1.66/t Message-ID: <200502160624.j1G6OYa7009780@gw.orcaware.com> Author: blair Date: Tue Feb 15 22:22:46 2005 New Revision: 415 Added: trunk/orca/packages/Time-HiRes-1.66/ - copied from r414, trunk/orca/packages/Time-HiRes-1.65/ Removed: trunk/orca/packages/Time-HiRes-1.65/ Modified: trunk/orca/INSTALL trunk/orca/configure.in trunk/orca/packages/Time-HiRes-1.66/Changes trunk/orca/packages/Time-HiRes-1.66/HiRes.pm trunk/orca/packages/Time-HiRes-1.66/HiRes.xs trunk/orca/packages/Time-HiRes-1.66/META.yml trunk/orca/packages/Time-HiRes-1.66/Makefile.PL trunk/orca/packages/Time-HiRes-1.66/t/HiRes.t Log: Upgrade Time::HiRes from 1.65 to 1.66. * INSTALL (Determine which Perl modules need compiling and installing): Update all references to Time::HiRes's version number from 1.65 to 1.66. * configure.in: Bump Time::HiRes's version number to 1.66. * packages/Time-HiRes-1.66: Renamed from packages/Time-HiRes-1.65. Directory contents updated from Time-HiRes-1.66.tar.gz. Modified: trunk/orca/INSTALL ============================================================================== --- trunk/orca/INSTALL (original) +++ trunk/orca/INSTALL Tue Feb 15 22:22:46 2005 @@ -177,7 +177,7 @@ Math::IntervalSearch >= 1.05 >= 1.05 1.05 RRDs >= 1.000491 >= 1.0.49 1.0.49 Storable >= 2.13 >= 2.13 2.13 - Time::HiRes Not required by Orca 1.65 + Time::HiRes Not required by Orca 1.66 version >= 0.42 >= 0.42 0.42 All seven of these modules are included with the Orca distribution @@ -279,10 +279,10 @@ Time::HiRes - http://www.perl.com/CPAN/authors/id/J/JH/JHI/Time-HiRes-1.65.tar.gz + http://www.perl.com/CPAN/authors/id/J/JH/JHI/Time-HiRes-1.66.tar.gz - % gunzip -c Time-HiRes-1.65.tar.gz | tar xvf - - % cd Time-HiRes-1.65 + % gunzip -c Time-HiRes-1.66.tar.gz | tar xvf - + % cd Time-HiRes-1.66 % perl Makefile.PL % make % make test Modified: trunk/orca/configure.in ============================================================================== --- trunk/orca/configure.in (original) +++ trunk/orca/configure.in Tue Feb 15 22:22:46 2005 @@ -41,8 +41,8 @@ RRDTOOL_VER=1.000491 STORABLE_DIR=Storable-2.13 STORABLE_VER=2.13 -TIME_HIRES_DIR=Time-HiRes-1.65 -TIME_HIRES_VER=1.65 +TIME_HIRES_DIR=Time-HiRes-1.66 +TIME_HIRES_VER=1.66 VERSION_DIR=version-0.42 VERSION_VER=0.42 Modified: trunk/orca/packages/Time-HiRes-1.66/Changes ============================================================================== --- trunk/orca/packages/Time-HiRes-1.65/Changes (original) +++ trunk/orca/packages/Time-HiRes-1.66/Changes Tue Feb 15 22:22:46 2005 @@ -1,5 +1,13 @@ Revision history for Perl extension Time::HiRes. +1.66 + - add nanosleep() + - fix the 'hierachy' typo in Makefile.PL [rt.cpan.org #8492] + - should now build in Solaris [rt.cpan.org #7165] (since 1.64) + - should now build in Cygwin [rt.cpan.org #7535] (since 1.64) + - close also [rt.cpan.org #5933] "Time::HiRes::time does not pick up time adjustments like ntp" since ever reproducing it in the same environment + has become rather unlikely + 1.65 - one should not mix u?alarm and sleep (the tests modified by 1.65, #12 and #13, hung in Solaris), now we just busy Modified: trunk/orca/packages/Time-HiRes-1.66/HiRes.pm ============================================================================== --- trunk/orca/packages/Time-HiRes-1.65/HiRes.pm (original) +++ trunk/orca/packages/Time-HiRes-1.66/HiRes.pm Tue Feb 15 22:22:46 2005 @@ -10,12 +10,12 @@ @EXPORT = qw( ); @EXPORT_OK = qw (usleep sleep ualarm alarm gettimeofday time tv_interval - getitimer setitimer + getitimer setitimer nanosleep ITIMER_REAL ITIMER_VIRTUAL ITIMER_PROF ITIMER_REALPROF d_usleep d_ualarm d_gettimeofday d_getitimer d_setitimer d_nanosleep); -$VERSION = '1.65'; +$VERSION = '1.66'; $XS_VERSION = $VERSION; $VERSION = eval $VERSION; @@ -54,9 +54,10 @@ =head1 SYNOPSIS - use Time::HiRes qw( usleep ualarm gettimeofday tv_interval ); + use Time::HiRes qw( usleep ualarm gettimeofday tv_interval nanosleep ); usleep ($microseconds); + nanosleep ($nanoseconds); ualarm ($microseconds); ualarm ($microseconds, $interval_microseconds); @@ -84,20 +85,20 @@ =head1 DESCRIPTION The C module implements a Perl interface to the -C, C, C, and C/C -system calls, in other words, high resolution time and timers. See the -L section below and the test scripts for usage; see your -system documentation for the description of the underlying -C or C, C, C, and -C/C calls. +C, C, C, C, and +C/C system calls, in other words, high +resolution time and timers. See the L section below and the +test scripts for usage; see your system documentation for the +description of the underlying C or C, C, +C, and C/C calls. If your system lacks C or an emulation of it you don't get C or the one-argument form of C. If your system lacks all of C, C, and -C, you don't get C or -C. If your system lacks both C and -C you don't get C or -C. +C, you don't get C, +C, or C. If your +system lacks both C and C you don't get +C or C. If you try to import an unimplemented function in the C statement it will fail at compile time. @@ -108,9 +109,7 @@ and you should first check for the truth value of C<&Time::HiRes::d_nanosleep> to see whether you have nanosleep, and then carefully read your C C API documentation for any -peculiarities. (There is no separate interface to call -C; just use C or -C with small enough values.) +peculiarities. Unless using C for mixing sleeping with signals, give some thought to whether Perl is the tool you should be using for @@ -129,9 +128,23 @@ =item usleep ( $useconds ) -Sleeps for the number of microseconds specified. Returns the number -of microseconds actually slept. Can sleep for more than one second, -unlike the C system call. See also C below. +Sleeps for the number of microseconds (millionths of a second) +specified. Returns the number of microseconds actually slept. Can +sleep for more than one second, unlike the C system call. See +also C and C. + +Do not expect usleep() to be exact down to one microsecond. + +=item nanosleep ( $nanoseconds ) + +Sleeps for the number of nanoseconds (1e9ths of a second) specified. +Returns the number of nanoseconds actually slept (accurate only to +microseconds, the nearest thousand of them). Can sleep for more than +one second. See also C and +C. + +Do not expect nanosleep() to be exact down to one nanosecond. +Getting even accuracy of one thousand nanoseconds is good. =item ualarm ( $useconds [, $interval_useconds ] ) Modified: trunk/orca/packages/Time-HiRes-1.66/HiRes.xs ============================================================================== --- trunk/orca/packages/Time-HiRes-1.65/HiRes.xs (original) +++ trunk/orca/packages/Time-HiRes-1.66/HiRes.xs Tue Feb 15 22:22:46 2005 @@ -351,18 +351,18 @@ * The TIME_HIRES_NANOSLEEP is set by Makefile.PL. */ #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) #define HAS_USLEEP -#define usleep hrt_nanosleep /* could conflict with ncurses for static build */ +#define usleep hrt_unanosleep /* could conflict with ncurses for static build */ void -hrt_nanosleep(unsigned long usec) +hrt_unanosleep(unsigned long usec) /* This is used to emulate usleep. */ { struct timespec res; res.tv_sec = usec/1000/1000; res.tv_nsec = ( usec - res.tv_sec*1000*1000 ) * 1000; nanosleep(&res, NULL); } -#endif +#endif /* #if !defined(HAS_USLEEP) && defined(TIME_HIRES_NANOSLEEP) */ #if !defined(HAS_USLEEP) && defined(HAS_SELECT) #ifndef SELECT_IS_BROKEN @@ -379,7 +379,7 @@ (Select_fd_set_t)NULL, &tv); } #endif -#endif +#endif /* #if !defined(HAS_USLEEP) && defined(HAS_SELECT) */ #if !defined(HAS_USLEEP) && defined(WIN32) #define HAS_USLEEP @@ -392,7 +392,7 @@ msec = usec / 1000; Sleep (msec); } -#endif +#endif /* #if !defined(HAS_USLEEP) && defined(WIN32) */ #if !defined(HAS_UALARM) && defined(HAS_SETITIMER) @@ -409,7 +409,7 @@ itv.it_interval.tv_usec = interval % 1000000; return setitimer(ITIMER_REAL, &itv, 0); } -#endif +#endif /* #if !defined(HAS_UALARM) && defined(HAS_SETITIMER) */ #if !defined(HAS_UALARM) && defined(VMS) #define HAS_UALARM @@ -606,7 +606,7 @@ } } -#endif /* !HAS_UALARM && VMS */ +#endif /* #if !defined(HAS_UALARM) && defined(VMS) */ #ifdef HAS_GETTIMEOFDAY @@ -633,7 +633,7 @@ return status == 0 ? Tp.tv_sec + (Tp.tv_usec / 1000000.) : -1.0; } -#endif +#endif /* #ifdef HAS_GETTIMEOFDAY */ MODULE = Time::HiRes PACKAGE = Time::HiRes @@ -700,6 +700,38 @@ OUTPUT: RETVAL +#if defined(TIME_HIRES_NANOSLEEP) + +NV +nanosleep(nseconds) + NV nseconds + PREINIT: + struct timeval Ta, Tb; + CODE: + gettimeofday(&Ta, NULL); + if (items > 0) { + struct timespec tsa; + if (nseconds > 1E9) { + IV seconds = (IV) (nseconds / 1E9); + if (seconds) { + sleep(seconds); + nseconds -= 1E9 * seconds; + } + } else if (nseconds < 0.0) + croak("Time::HiRes::nanosleep(%"NVgf"): negative time not invented yet", nseconds); + tsa.tv_sec = (IV) (nseconds / 1E9); + tsa.tv_nsec = (IV) nseconds - tsa.tv_sec * 1E9; + nanosleep(&tsa, NULL); + } else + PerlProc_pause(); + gettimeofday(&Tb, NULL); + RETVAL = 1E3*(1E6*(Tb.tv_sec-Ta.tv_sec)+(NV)((IV)Tb.tv_usec-(IV)Ta.tv_usec)); + + OUTPUT: + RETVAL + +#endif /* #if defined(TIME_HIRES_NANOSLEEP) */ + NV sleep(...) PREINIT: @@ -719,7 +751,7 @@ * circumstances (if the double is cast to UV more * than once?) evaluate to -0.5, instead of 0.5. */ useconds = -(IV)useconds; -#endif +#endif /* #if defined(__sparc64__) && defined(__GNUC__) */ if ((IV)useconds < 0) croak("Time::HiRes::sleep(%"NVgf"): internal error: useconds < 0 (unsigned %"UVuf" signed %"IVdf")", seconds, useconds, (IV)useconds); } @@ -737,7 +769,7 @@ OUTPUT: RETVAL -#endif +#endif /* #if defined(HAS_USLEEP) && defined(HAS_GETTIMEOFDAY) */ #ifdef HAS_UALARM @@ -766,7 +798,7 @@ OUTPUT: RETVAL -#endif +#endif /* #ifdef HAS_UALARM */ #ifdef HAS_GETTIMEOFDAY # ifdef MACOS_TRADITIONAL /* fix epoch TZ and use unsigned time_t */ @@ -832,7 +864,7 @@ RETVAL # endif /* MACOS_TRADITIONAL */ -#endif +#endif /* #ifdef HAS_GETTIMEOFDAY */ #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER) @@ -879,5 +911,6 @@ } } -#endif +#endif /* #if defined(HAS_GETITIMER) && defined(HAS_SETITIMER) */ + Modified: trunk/orca/packages/Time-HiRes-1.66/META.yml ============================================================================== --- trunk/orca/packages/Time-HiRes-1.65/META.yml (original) +++ trunk/orca/packages/Time-HiRes-1.66/META.yml Tue Feb 15 22:22:46 2005 @@ -1,7 +1,7 @@ # http://module-build.sourceforge.net/META-spec.html #XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX# name: Time-HiRes -version: 1.65 +version: 1.66 version_from: HiRes.pm installdirs: perl requires: Modified: trunk/orca/packages/Time-HiRes-1.66/Makefile.PL ============================================================================== --- trunk/orca/packages/Time-HiRes-1.65/Makefile.PL (original) +++ trunk/orca/packages/Time-HiRes-1.66/Makefile.PL Tue Feb 15 22:22:46 2005 @@ -98,7 +98,7 @@ if ($^O eq 'VMS') { if ($ENV{PERL_CORE}) { - # Fragile if the extensions change hierachy within + # Fragile if the extensions change hierarchy within # the Perl core but this should do for now. $cccmd = "$Config{'cc'} /include=([---]) $tmp.c"; } else { Modified: trunk/orca/packages/Time-HiRes-1.66/t/HiRes.t ============================================================================== --- trunk/orca/packages/Time-HiRes-1.65/t/HiRes.t (original) +++ trunk/orca/packages/Time-HiRes-1.66/t/HiRes.t Tue Feb 15 22:22:46 2005 @@ -12,7 +12,7 @@ } } -BEGIN { $| = 1; print "1..25\n"; } +BEGIN { $| = 1; print "1..28\n"; } END {print "not ok 1\n" unless $loaded;} @@ -26,11 +26,13 @@ my $have_gettimeofday = defined &Time::HiRes::gettimeofday; my $have_usleep = defined &Time::HiRes::usleep; +my $have_nanosleep = defined &Time::HiRes::nanosleep; my $have_ualarm = defined &Time::HiRes::ualarm; my $have_time = defined &Time::HiRes::time; import Time::HiRes 'gettimeofday' if $have_gettimeofday; import Time::HiRes 'usleep' if $have_usleep; +import Time::HiRes 'nanosleep' if $have_nanosleep; import Time::HiRes 'ualarm' if $have_ualarm; use Config; @@ -41,11 +43,10 @@ my $pid; if ($have_fork) { - print "# Testing process $$\n"; - print "# Starting the timer process\n"; + print "# I am process $$, starting the timer process\n"; if (defined ($pid = fork())) { if ($pid == 0) { # We are the kid, set up the timer. - print "# Timer process $$\n"; + print "# I am timer process $$\n"; sleep($waitfor); warn "\n$0: overall time allowed for tests (${waitfor}s) exceeded\n"; print "# Terminating the testing process\n"; @@ -349,29 +350,60 @@ } } +if (!$have_nanosleep) { + skip 22..23; +} +else { + my $one = CORE::time; + nanosleep(10_000_000); + my $two = CORE::time; + nanosleep(10_000_000); + my $three = CORE::time; + ok 22, $one == $two || $two == $three, "slept too long, $one $two $three"; + + if (!$have_gettimeofday) { + skip 23; + } + else { + my $f = Time::HiRes::time(); + nanosleep(500_000_000); + my $f2 = Time::HiRes::time(); + my $d = $f2 - $f; + ok 23, $d > 0.4 && $d < 0.9, "slept $d secs $f to $f2"; + } +} + eval { sleep(-1) }; print $@ =~ /::sleep\(-1\): negative time not invented yet/ ? - "ok 22\n" : "not ok 22\n"; + "ok 24\n" : "not ok 24\n"; eval { usleep(-2) }; print $@ =~ /::usleep\(-2\): negative time not invented yet/ ? - "ok 23\n" : "not ok 23\n"; + "ok 25\n" : "not ok 25\n"; if ($have_ualarm) { eval { alarm(-3) }; print $@ =~ /::alarm\(-3, 0\): negative time not invented yet/ ? - "ok 24\n" : "not ok 24\n"; + "ok 26\n" : "not ok 26\n"; eval { ualarm(-4) }; print $@ =~ /::ualarm\(-4, 0\): negative time not invented yet/ ? - "ok 25\n" : "not ok 25\n"; + "ok 27\n" : "not ok 27\n"; +} else { + skip 26; + skip 27; +} + +if ($have_nanosleep) { + eval { nanosleep(-5) }; + print $@ =~ /::nanosleep\(-5\): negative time not invented yet/ ? + "ok 28\n" : "not ok 28\n"; } else { - skip 24; - skip 25; + skip 28; } if (defined $pid) { - print "# Terminating the timer process $pid\n"; + print "# I am process $$, terminating the timer process $pid\n"; kill('TERM', $pid); # We are done, the timer can go. unlink("ktrace.out"); }