From dmberezin at hotmail.com Fri Sep 10 09:03:11 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Fri, 10 Sep 2004 09:03:11 -0700 Subject: [Orca-checkins] r386 - in trunk/orca: data_gatherers/orcallator lib/SE/3.3.1 Message-ID: <200409101603.i8AG3BLd025039@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Fri Sep 10 08:54:27 2004 New Revision: 386 Added: trunk/orca/lib/SE/3.3.1/tapeinfo.se Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: This is the first update to the disk/tape data collection. More changes are in the works, but I?d like to ?version? it now, so that it is easier to track what is changed. Naming conventions are changed from RAW_disk to KSTAT_IO Static RAW_disk array is replaced by dynamic ORCA_io_dev_info array Short and Long device names are now ?strings?, thus dynamic raw_disk_map and name compare functions are removed and replaced by the simple name lookup using find_inst Removed some unused variables Added tape ?long? name mapping (stxxx is being mapped to rmt/xx) support. Requires tapeinfo.se (modified version of diskinfo.se) Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Fri Sep 10 08:54:27 2004 @@ -1,2320 +1,2210 @@ -// -// Orcallator.se, a log generating performance monitor. -// -// This program logs many different system quantities to a log file -// for later processing. -// -// Author: Blair Zajac . -// -// Portions copied from percollator.se written by Adrian Cockroft. -// -// $HeadURL$ -// $LastChangedDate$ -// $LastChangedBy$ -// $LastChangedRevision$ -// -// Revision history for this file can be retrieved by running svn log -// on the HeadURL listed above. -// - -// The default sampling interval in seconds. -#define SAMPLE_INTERVAL 300 - -// The maximum number of columns of data. -#define MAX_COLUMNS 2048 - -// Enable the raw disk measuring code. -#define USE_RAWDISK 1 - -// If WATCH_OS is defined, then measure every part of the operating -// system. -#ifdef WATCH_OS -#define WATCH_CPU 1 -#define WATCH_MUTEX 1 -#define WATCH_NET 1 -#define WATCH_TCP 1 -#define WATCH_NFS_CLIENT 1 -#define WATCH_NFS_SERVER 1 -#define WATCH_MOUNTS 1 -#define WATCH_DISK 1 -#define WATCH_DNLC 1 -#define WATCH_INODE 1 -#define WATCH_RAM 1 -#define WATCH_PAGES 1 -#endif - -// Keep backwards compatibility with WATCH_HTTPD. -#ifdef WATCH_HTTPD -#define WATCH_WEB 1 -#endif - -// Keep backwards compatibility with WATCH_NFS. -#ifdef WATCH_NFS -#ifndef WATCH_NFS_CLIENT -#define WATCH_NFS_CLIENT 1 -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -//#include -#include -//#include -#include -#include -#include -#include -#include -#include - -#ifdef WATCH_MOUNTS -#include -#include -#endif - -#if WATCH_CPU || WATCH_WEB -#include - -#ifdef WATCH_CPU -// This is the maximum pid on Solaris hosts. -#define DEFAULT_MAXPID 30000 -#include -#endif - -#ifdef WATCH_WEB - -// Define this macro which returns the size index for a file of a -// particular size. This saves the overhead of a function call. -#define WWW_SIZE_INDEX(size, size_index) \ - if (size < 1024) { \ - size_index=0; /* Under 1KB */ \ - } else { \ - if (size < 10240) { \ - size_index=1; /* Under 10K */ \ - } else { \ - if (size < 102400) { \ - size_index=2; /* Under 100KB */ \ - } else { \ - if (size < 1048576) { \ - size_index=3; /* Under 1MB */ \ - } else { \ - size_index=4; /* Over 1MB */ \ - } \ - } \ - } \ - } \ - dwnld_size[size_index]++; - -// Handle the reply code from the server. -#define WWW_REPLY_CODE(word) \ - if (word == "304") { \ - httpop_condgets++; \ - } \ - else { \ - first_byte = word; \ - if (first_byte[0] == '4' || first_byte[0] == '5') { \ - httpop_errors++; \ - } \ - } \ - -// Handle the method of the object served. This define only works -// with non-proxy servers. -#define WWW_METHOD1(word) \ - switch (word) { \ - case "get": \ - case "GET": \ - httpop_gets++; \ - break; \ - case "post": \ - case "POST": \ - httpop_posts++; \ - break; \ - case "head": \ - case "HEAD": \ - ishead = 1; \ - httpop_condgets++; \ - break; - -#ifdef WATCH_SQUID -#define WWW_METHOD2 \ - case "icp_query": \ - case "ICP_QUERY": \ - squid_icp_queries++; \ - break; -#else -#define WWW_METHOD2 -#endif - -#define WWW_METHOD_END \ - default: \ - break; \ - } -#define WWW_METHOD(word) WWW_METHOD1(word) WWW_METHOD2 WWW_METHOD_END -#endif -#endif - -// Put all rules here so they can be accessed by the handle functions. -lr_cpu_t lr_cpu$cpu; -lr_cpu_t tmp_lr_cpu; -lr_mutex_t lr_mutex$m; -lr_mutex_t tmp_lr_mutex; -lr_net_t lr_net$nr; -lr_net_t tmp_lr_net; -lr_tcp_t lr_tcp$tcp; -lr_tcp_t tmp_lr_tcp; -lr_rpcclient_t lr_rpcclient$r; -lr_rpcclient_t tmp_lr_rpcclient; -lr_disk_t lr_disk$dr; -lr_disk_t tmp_lr_disk; -lr_dnlc_t lr_dnlc$dnlc; -lr_dnlc_t tmp_lr_dnlc; -lr_inode_t lr_inode$inode; -lr_inode_t tmp_lr_inode; -lr_ram_t lr_ram$ram; -lr_ram_t tmp_lr_ram; -lr_swapspace_t lr_swapspace$s; -lr_swapspace_t tmp_lr_swapspace; -lr_kmem_t lr_kmem$kmem; -lr_kmem_t tmp_lr_kmem; - -ks_system_misc kstat$misc; -ks_system_misc tmp_kstat_misc; -#ifdef WATCH_TCP -tcp tcp$tcp; -tcp tmp_tcp; -#endif -#ifdef WATCH_PAGES -ks_system_pages kstat$pages; -ks_system_pages tmp_kstat_pages; -#endif - -// Put application globals here. -string nodename; // Name of this machine. -string program_name; // Name of this program. -int hz; // Clock tick rate. -int page_size; // Page size in bytes. -long boot_time; // Boot time of the system. -long interval = SAMPLE_INTERVAL; // Sampling interval. - -#ifdef WATCH_CPU -int can_read_kernel = 0; // If the kernel can be read. -int kvm$mpid; // The last created PID. - -// These variables store the mpid before and after the standard interval. -int mpid_previous; -int mpid_current; -ulonglong mpid_then; -ulonglong mpid_now; - -// These variables store the mpid before and after 5 second intervals. -int mpid5_previous; -int mpid5_current; -ulonglong mpid5_then; -ulonglong mpid5_now; -double mpid5_rate; -#endif - -#ifdef WATCH_MOUNTS -mnttab_t mnt$mnt; -mnttab_t tmp_mnt; -#endif - -#ifdef WATCH_NFS_SERVER -ks_nfs_server kstat$nfs; -ks_nfs_server tmp_nfs; -ks_rfs_proc_v2 kstat$rfsproccnt_v2; -ks_rfs_proc_v2 tmp_rfsproccnt_v2; -ks_rfs_proc_v3 kstat$rfsproccnt_v3; -ks_rfs_proc_v3 tmp_rfsproccnt_v3; -#endif - -// Variables for handling the httpd access log. -#ifdef WATCH_WEB -string www_search_url = getenv("SEARCHURL"); -string www_server_proc_name = getenv("WEB_SERVER"); -string www_server_secure_proc_name = getenv("WEB_SERVER_SECURE"); -string www_log_filename = getenv("WEB_LOG"); -string www_gateway = getenv("GATEWAY"); -ulong www_log_fp; -uint www_gatelen; -stat_t www_log_stat[1]; -ulong www_log_ino; -long www_log_size; - -double www_interval; // Hi-res interval time. -ulonglong www_then; -ulonglong www_now; - -double www5_interval; // Actual hi-res 5 second interval. -ulonglong www5_then; -ulonglong www5_now; - -double httpops; -double httpops5; -double gateops; -double dtmp; - -long httpop_gets; -long httpop_condgets; // HEAD or code = 304 conditional get no data. -long httpop_posts; -long httpop_cgi_bins; -long httpop_searches; -long httpop_errors; -long dwnld_size[5]; // [0] < 1K, [1] < 10K, [2] < 100K, [3] < 1M, [4] >= 1M -long dwnld_totalz; // Total size counted from log. - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO -// If we're watching a Yahoo log, then take the transfer time to be the -// processing time. -double www_dwnld_time_sum; // Transfer time. -double www_dwnld_time_by_size[5]; // Mean transfer time by size bin. -#endif -#if WATCH_PROXY || WATCH_SQUID -long prxy_squid_indirect; // # hits that go via PROXY,SOCKS,parent -long prxy_squid_cache_hits; // # hits returned from cache. -#endif - -#ifdef WATCH_PROXY -long prxy_cache_writes; // Number of writes and updates to cache. -long prxy_uncacheable; // Number of explicitly uncacheable httpops. - // Any extra is errors or incomplete ops. -#endif - -#ifdef WATCH_SQUID -long squid_cache_misses; -long squid_icp_requests; -long squid_icp_queries; -long squid_client_http; -#endif - -#endif - -#ifdef USE_RAWDISK -#include -// This code was developed so that the performance of virtual disks -// originating from a Sun A1000 raid controller could be monitored. -// These disks do not show up in the GLOBAL_disk[] io structure of SE. -// -// This extension accesses the sys_kstat.se interface to the kstat IO -// queues to extract info on drives not available in the kstat.se -// kstat$disk interface. Global data shared between function calls. -struct RawDisk { - // Exposed interface that matches kstat. - char long_name[48]; - char short_name[8]; - double reads; - double kreads; - double writes; - double kwrites; - double avg_wait; - double avg_serv; - double service; - double wait_percent; - double run_percent; - - // Hidden internal registers to track sys_kstats counters. - int _number; // kstat disk # - ulonglong _nread; // Number of bytes read - ulonglong _nwritten; // Number of bytes written - uint _reads; // Number of read operations - uint _writes; // Number of write operations - longlong _wtime; // Cumulative wait (pre-service) time - longlong _wlentime; // Cumulative wait length*time product - longlong _wlastupdate; // Last time wait queue changed - longlong _rtime; // Cumulative run (service) time - longlong _rlentime; // Cumulative run length*time product - longlong _rlastupdate; // Last time run queue changed - uint _wcnt; // Count of elements in wait state - uint _rcnt; // Count of elements in run state -}; - -// Define global for tracking raw disk data. -#ifndef MAX_RAWDISKS -#define MAX_RAWDISKS 1024 -#endif - -RawDisk RAW_disk[MAX_RAWDISKS]; -int RAW_disk_map=0; -int RAW_disk_count=0; -double RAW_disk_lastupdate; - -// Compare two short disk names and return if they have on the same -// physical device name, ignoring slice info. -int raw_disk_short_name_cmp(char disk1[], - int disk1_length, - char disk2[], - int disk2_length) -{ - int i; - - // Handle dad disks first since they do not have commas. - if (strncmp("dad", disk1, 3) == 0) { - return strncmp(disk1, disk2, disk1_length); - } - - // Extract the physical disk name from disk slices. This only works - // with SCSI disks where slices have commma separators. - for (i=0; i 1) { - strcpy(second_name, GLOBAL_disk_info[1].short_name); - second_name_length = strlen(second_name); - } - for (i=0; i 0) { - short_name_length = strlen(short_name); - if (raw_disk_short_name_cmp(first_name, - first_name_length, - short_name, - short_name_length) == 0) { - break; - } - if (j > 1) { - if (raw_disk_short_name_cmp(second_name, - second_name_length, - short_name, - short_name_length) == 0) { - break; - } - } - } - if (strcmp(RAW_disk[i].short_name, short_name) == 0) { - strcpy(long_name, GLOBAL_disk_info[j].long_name); - strcpy(RAW_disk[i].long_name, long_name); - break; - } - } - } - } - RAW_disk_map = 0; -} - -raw_disk_update() { - int rdisk; - ulong ul; - kstat_ctl_t kc[1]; - kstat_t kp[1]; - kstat_t nkp[1]; - kstat_io_t kio; - ulonglong _nread; - ulonglong _nwritten; - uint _reads; - uint _writes; - longlong _wtime; - longlong _wlentime; - longlong _wlastupdate; - longlong _rtime; - longlong _rlentime; - longlong _rlastupdate; - longlong _wcnt; - longlong _rcnt; - - double read_writes; - double big_etime; - double elapsed_etime; - double hz_etime; - double nanosecond = NANOSEC; - double update; - double delta; - timeval_t time_update[1]; - ulong time_void; - char short_name[8]; - - gettimeofday(time_update, time_void); - update = time_update[0].tv_sec + (time_update[0].tv_usec / 1000000.0); - delta = update - RAW_disk_lastupdate; - RAW_disk_lastupdate = update; - - kc[0] = kstat_open(); - // Read them. - if (kstat_read(kc, kp, 0) == -1) { - perror("raw_disk_update:kstat_read"); - exit(1); - } - - // Traverse the chain looking for IO events. - for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { - struct_fill(nkp[0], ul); - if (nkp[0].ks_type == KSTAT_TYPE_IO) { - strcpy(short_name, nkp[0].ks_name); - if (short_name[0] != 'm' && - short_name[0] != 'n' && - strchr(short_name,',') == nil) { - // Try to locate device. - for (rdisk=0; rdisk _nread) { - _nread = RAW_disk[rdisk]._nread; - } - _reads = kio.reads; - if (RAW_disk[rdisk]._reads > _reads) { - _reads = RAW_disk[rdisk]._reads; - } - _rlentime = kio.rlentime; - _rtime = kio.rtime; - _rlastupdate = kio.wlastupdate; - _rcnt = kio.rcnt; - _nwritten = kio.nwritten; - if (RAW_disk[rdisk]._nwritten > _nwritten) { - _nwritten = RAW_disk[rdisk]._nwritten; - } - _writes = kio.writes; - if (RAW_disk[rdisk]._writes > _writes) { - _writes = RAW_disk[rdisk]._nwritten; - } - _wlentime = kio.wlentime; - _wtime = kio.wtime; - _wlastupdate = kio.wlastupdate; - _wcnt = kio.wcnt; - - elapsed_etime = (_wlastupdate - RAW_disk[rdisk]._wlastupdate); - if (elapsed_etime > 0) { - hz_etime = elapsed_etime / nanosecond; - big_etime = 1024.0 * hz_etime; - } else { - elapsed_etime = nanosecond; - hz_etime = 1.0; - big_etime = 1024.0; - } - RAW_disk[rdisk].reads =(_reads-RAW_disk[rdisk]._reads) /hz_etime; - RAW_disk[rdisk].kreads =(_nread-RAW_disk[rdisk]._nread) /big_etime; - RAW_disk[rdisk].writes =(_writes-RAW_disk[rdisk]._writes)/hz_etime; - RAW_disk[rdisk].kwrites=(_nwritten-RAW_disk[rdisk]._nwritten) / big_etime; - - read_writes = elapsed_etime * (RAW_disk[rdisk].reads + RAW_disk[rdisk].writes) / 1024.0; - if (read_writes > 0) { - RAW_disk[rdisk].avg_wait = (_wlentime - RAW_disk[rdisk]._wlentime) / read_writes; - RAW_disk[rdisk].avg_serv = (_rlentime - RAW_disk[rdisk]._rlentime) / read_writes; - RAW_disk[rdisk].service = RAW_disk[rdisk].avg_wait + RAW_disk[rdisk].avg_serv; - } else { - RAW_disk[rdisk].avg_wait = 0.0; - RAW_disk[rdisk].avg_serv = 0.0; - RAW_disk[rdisk].service = 0.0; - } - - // Update the counters. - RAW_disk[rdisk].run_percent = 100.0 * (_rtime - RAW_disk[rdisk]._rtime) / elapsed_etime; - RAW_disk[rdisk].wait_percent = 100.0 * (_wtime - RAW_disk[rdisk]._wtime) / elapsed_etime; - RAW_disk[rdisk]._writes = _writes; - RAW_disk[rdisk]._nwritten = _nwritten; - RAW_disk[rdisk]._wlastupdate = _wlastupdate; - RAW_disk[rdisk]._wlentime = _wlentime; - RAW_disk[rdisk]._wtime = _wtime; - RAW_disk[rdisk]._wcnt = _wcnt; - RAW_disk[rdisk]._reads = _reads; - RAW_disk[rdisk]._nread = _nread; - RAW_disk[rdisk]._rlastupdate = _rlastupdate; - RAW_disk[rdisk]._rlentime = _rlentime; - RAW_disk[rdisk]._rtime = _rtime; - RAW_disk[rdisk]._rcnt = _rcnt; - } - } - } - } - kstat_close(kc); - - // Map long device names for any drives that we just discovered. - if (RAW_disk_map == 1) { - raw_disk_map(); - } -} -#endif -// RAWDISK - -// Variables for handling output. -string compress = getenv("COMPRESSOR"); // How to compress logs. -ulong out_log_fp; // File pointer to the logging file. -string col_comment[MAX_COLUMNS]; // Comments for each column. -string col_data[MAX_COLUMNS]; // Data for each column. -string col_previous_comment[MAX_COLUMNS]; // Previous comments. -int current_column = 0; // The current column. -int previous_number_columns = -1; // Number columns printed last. -int print_header = 1; // Flag to flush header. - -// This is a list of the extensions the compress programs add to the -// compress filename. -#define NUMBER_COMPRESS_SUFFIXES 3 -string compression_suffixes[NUMBER_COMPRESS_SUFFIXES] = {".Z", - ".gz", - ".bz2"}; - -// Add one column of comments and data to the buffers. -put_output(string comment, string data) -{ - if (current_column >= MAX_COLUMNS) { - fprintf(stderr, "%s: too many columns (%d). Increase MAX_COLUMNS.\n", - program_name, current_column); - exit(1); - } - - col_comment[current_column] = comment; - col_data[current_column] = data; - current_column++; -} - -// Send the stored columns of information to the output. -print_columns(string data[]) -{ - int i; - for (i=0; i 0) { - usleep(1000000*time_to_sleep - now[0].tv_usec); - gettimeofday(now, 0); - time_to_sleep = sleep_till - now[0].tv_sec; - } -} - -sleep_till_and_count_new_processes(long sleep_till) -{ - long now; -#ifdef WATCH_CPU - int mpid5_diff; - double mpid5_interval; - double rate; -#endif - - now = time(0); - while (now < sleep_till) { -#ifdef WATCH_CPU - if (can_read_kernel != 0) { - // Sleep for 5 seconds to make a measurement or less to stay - // within the sleep_till limit. - if (now + 5 < sleep_till) { - orca_sleep_till(now + 5); - } else { - orca_sleep_till(sleep_till); - } - - // Measure the 5 second process creation rate. - mpid5_current = kvm$mpid; - mpid5_now = gethrtime(); - mpid5_interval = (mpid5_now - mpid5_then) * 0.000000001; - mpid5_then = mpid5_now; - if (mpid5_current >= mpid5_previous) { - mpid5_diff = mpid5_current - mpid5_previous; - } - else { - mpid5_diff = mpid5_current + DEFAULT_MAXPID - mpid5_previous; - } - rate = mpid5_diff/mpid5_interval; - if (rate > mpid5_rate) { - mpid5_rate = rate; - } - mpid5_previous = mpid5_current; - - // Now take these results to measure the long interval rate. - // Because the mpid may flip over DEFAULT_MAXPID more than once - // in the long interval time span, use the difference between - // the previous and current mpid over a 5 second interval to - // calculate the long interval difference. - mpid_current += mpid5_diff; - mpid_now = mpid5_now; - } - else { - orca_sleep_till(sleep_till); - } -#else - orca_sleep_till(sleep_till); -#endif - now = time(0); - } -} - -#ifdef WATCH_CPU -measure_cpu() -{ - p_vmstat pvm; - double mpid_interval; - double mpid_rate; - - pvm = vmglobal_total(); - - // In SE 3.0 and below user_time and system_time are int and in SE - // 3.1 and above they are double, so cast everything to double using - // + 0.0. - put_output(" usr%", sprintf("%5.1f", pvm.user_time + 0.0)); - put_output(" sys%", sprintf("%5.1f", pvm.system_time + 0.0)); - put_output(" wio%", sprintf("%5.1f", pvm.wait_time + 0.0)); - put_output("idle%", sprintf("%5.1f", pvm.idle_time + 0.0)); - put_output(" 1runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_1min/256.0)); - put_output(" 5runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_5min/256.0)); - put_output("15runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_15min/256.0)); - put_output("#proc", sprintf("%5lu", tmp_kstat_misc.nproc)); - put_output(" #runque", sprintf("%8.2f", pvm.runque + 0.0)); - put_output("#waiting", sprintf("%8.2f", pvm.waiting + 0.0)); - put_output(" #swpque", sprintf("%8.2f", pvm.swpque + 0.0)); - put_output("scanrate", sprintf("%8.3f", pvm.scan + 0.0)); - put_output("pgrec/s", sprintf("%8.3f", pvm.pgrec + 0.0)); - put_output("pgfrec/s", sprintf("%8.3f", pvm.pgfrec + 0.0)); - put_output("pgin/s", sprintf("%8.3f", pvm.pgin + 0.0)); - put_output("pages_in/s", sprintf("%8.3f", pvm.pages_in + 0.0)); - put_output("pgout/s", sprintf("%8.3f", pvm.pgout + 0.0)); - put_output("pages_out/s", sprintf("%8.3f", pvm.pages_out + 0.0)); - put_output("dfree/s", sprintf("%8.3f", pvm.dfree + 0.0)); - put_output("min_fault/s", sprintf("%8.3f", pvm.hat_fault + pvm.as_fault + 0.0)) -; - put_output("maj_fault/s", sprintf("%8.3f", pvm.maj_fault + 0.0)); - put_output("prot_fault/s", sprintf("%8.3f", pvm.prot_fault + 0.0)); - put_output("cow_fault/s", sprintf("%8.3f", pvm.cow_fault + 0.0)); - put_output("zfod/s", sprintf("%8.3f", pvm.zfod + 0.0)); - put_output("interrupts/s", sprintf("%8.3f", pvm.interrupts + 0.0)); - put_output("intrthread/s", sprintf("%8.3f", pvm.intrthread + 0.0)); - put_output("system_calls/s", sprintf("%8.3f", pvm.system_calls + 0.0)); - put_output("context_switches/s", sprintf("%8.3f", pvm.context_switches + 0.0)); - put_output("invol_switches/s", sprintf("%8.3f", pvm.invol_switches + 0.0)); - put_output("traps/s", sprintf("%8.3f", pvm.trap + 0.0)); - put_output("forks/s", sprintf("%8.3f", pvm.sysfork + 0.0)); - put_output("vforks/s", sprintf("%8.3f", pvm.sysvfork + 0.0)); - put_output("execs/s", sprintf("%8.3f", pvm.sysexec + 0.0)); - put_output("namei/s", sprintf("%8.3f", pvm.namei + 0.0)); - put_output("ufsiget/s", sprintf("%8.3f", pvm.ufsiget + 0.0)); - put_output("ufsdirblk/s", sprintf("%8.3f", pvm.ufsdirblk + 0.0)); - - // Calculate the rate of new process spawning. - if (can_read_kernel != 0) { - mpid_interval = (mpid_now - mpid_then) * 0.000000001; - mpid_rate = (mpid_current - mpid_previous) / mpid_interval; - put_output("#proc/s", sprintf("%7.3f", mpid_rate)); - put_output("#proc/p5s", sprintf("%9.4f", mpid5_rate)); - - // Reset counters. - mpid_then = mpid_now; - mpid_previous = mpid_current; - mpid5_rate = 0; - } -} -#endif - -#ifdef WATCH_MUTEX -measure_mutex() -{ - put_output(" smtx", sprintf("%5d", tmp_lr_mutex.smtx)); - put_output("smtx/cpu", sprintf("%8d", tmp_lr_mutex.smtx/GLOBAL_pvm_ncpus)); -} -#endif - -#ifdef WATCH_NET -measure_net() -{ - int previous_count = -1; - int current_count; - int i; - - current_count = 0; - for (i=0; i. Check - // [wr]lentime to see if an EMC is using a fake disk for control. - // EMC disks have a fake disk which commands are run over to - // configure the disk array or to get stats from; they are not - // real data transfers. They cause 1000 MB/sec writes to appear - // in the stats. I still get them but not as often with this bit - // of code in. If the I/O which occurred in the last five minutes - // is not greater than 1/100sec then it is not a valid measurement - // anyway. What happens is that we can have a small I/O, say 1024 - // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making - // it wlentime+rlentime>2 since I am still getting fake write - // spikes. -#ifdef HAVE_EMC_DISK_CONTROL - if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { -#endif - total_disk_reads += RAW_disk[i].reads; - total_disk_writes += RAW_disk[i].writes; - total_disk_readk += RAW_disk[i].kreads; - total_disk_writek += RAW_disk[i].kwrites; - mean_disk_busy += RAW_disk[i].run_percent; - if (RAW_disk[i].run_percent > peak_disk_busy) { - peak_disk_busy = RAW_disk[i].run_percent; - } -#ifdef HAVE_EMC_DISK_CONTROL - } -#endif - } -#else - for (i=0; i. Check - // [wr]lentime to see if an EMC is using a fake disk for control. - // EMC disks have a fake disk which commands are run over to - // configure the disk array or to get stats from; they are not - // real data transfers. They cause 1000 MB/sec writes to appear - // in the stats. I still get them but not as often with this bit - // of code in. If the I/O which occurred in the last five minutes - // is not greater than 1/100sec then it is not a valid measurement - // anyway. What happens is that we can have a small I/O, say 1024 - // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making - // it wlentime+rlentime>2 since I am still getting fake write - // spikes. -#ifdef HAVE_EMC_DISK_CONTROL - if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { -#endif - total_disk_reads += GLOBAL_disk[i].reads; - total_disk_writes += GLOBAL_disk[i].writes; - total_disk_readk += GLOBAL_disk[i].kreads; - total_disk_writek += GLOBAL_disk[i].kwrites; - mean_disk_busy += GLOBAL_disk[i].run_percent; - if (GLOBAL_disk[i].run_percent > peak_disk_busy) { - peak_disk_busy = GLOBAL_disk[i].run_percent; - } -#ifdef HAVE_EMC_DISK_CONTROL - } -#endif - } -#endif - - if (disk_count != 0) { - mean_disk_busy = mean_disk_busy/disk_count; - } - - put_output("disk_peak", sprintf("%9.3f", peak_disk_busy)); - put_output("disk_mean", sprintf("%9.3f", mean_disk_busy)); - put_output("disk_rd/s", sprintf("%9.1f", total_disk_reads)); - put_output("disk_wr/s", sprintf("%9.1f", total_disk_writes)); - put_output("disk_rK/s", sprintf("%9.1f", total_disk_readk)); - put_output("disk_wK/s", sprintf("%9.1f", total_disk_writek)); - - put_output("tape_rd/s", sprintf("%9.1f", total_tape_reads)); - put_output("tape_wr/s", sprintf("%9.1f", total_tape_writes)); - put_output("tape_rK/s", sprintf("%9.1f", total_tape_readk)); - put_output("tape_wK/s", sprintf("%9.1f", total_tape_writek)); - - // If the number of disks and/or tapes has changed, say due to a - // add_drv, then print new headers. - if (previous_disk_count != disk_count) { - print_header = 1; - previous_disk_count = disk_count; - } - if (previous_tape_count != tape_count) { - print_header = 1; - previous_tape_count = tape_count; - } -} -#endif - -#ifdef WATCH_DNLC -measure_dnlc() -{ - put_output("dnlc_ref/s", sprintf("%10.3f", tmp_lr_dnlc.refrate)); - put_output("dnlc_hit%", sprintf("%9.3f", tmp_lr_dnlc.hitrate)); -} -#endif - -#ifdef WATCH_INODE -measure_inode() -{ - p_vmstat pvm; - - put_output("inod_ref/s", sprintf("%10.3f", tmp_lr_inode.refrate)); - put_output("inod_hit%", sprintf("%9.3f", tmp_lr_inode.hitrate)); - put_output("inod_stl/s", sprintf("%10.3f", tmp_lr_inode.iprate)); - put_output("ufsinopage/s", sprintf("%8.3f", pvm.ufsinopage + 0.0)); - -} -#endif - -#ifdef WATCH_RAM -measure_ram() -{ - put_output("swap_avail", sprintf("%10ld", GLOBAL_pvm[0].swap_avail)); - put_output("page_rstim", sprintf("%10d", tmp_lr_ram.restime)); - put_output(" freememK", sprintf("%10d", GLOBAL_pvm[0].freemem)); - put_output("free_pages", sprintf("%10d", (GLOBAL_pvm[0].freemem*1024)/page_size)); -} -#endif - -#ifdef WATCH_PAGES -measure_pages() -{ - put_output("pp_kernel", sprintf("%9lu", tmp_kstat_pages.pp_kernel)); - put_output("pagesfree", sprintf("%9lu", tmp_kstat_pages.pagesfree)); - put_output("pageslock", sprintf("%9lu", tmp_kstat_pages.pageslocked)); -#if MINOR_VERSION < 80 - put_output("pagesio", sprintf("%7lu", tmp_kstat_pages.pagesio)); -#endif - put_output("pagestotl", sprintf("%9lu", tmp_kstat_pages.pagestotal)); -} -#endif - -#ifdef WATCH_WEB -/* - * Breakdown access log format. - */ -accesslog(string buf) { - int z; - int size_index; - int ishead; - string word; - char first_byte[1]; - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - double xf; -#ifdef WATCH_SQUID - string logtag; - string request; -#endif -#ifdef WATCH_YAHOO - string arg; - ulong ptr; - ulong tmp; - ulong ulong_xf; -#endif -#endif - - ishead = 0; -#ifdef WATCH_YAHOO - /* - * Make sure that the input line has at least 32 bytes of data plus a new - * line, for a total length of 33. - */ - if (strlen(buf) < 33) { - return; - } - word = strtok(buf, "\05"); -#else - word = strtok(buf, " "); -#endif - if (word == nil) { - return; - } - -#ifdef WATCH_SQUID - /* - * Word contains unix time in seconds.milliseconds. - */ - word = strtok(nil, " "); - if (word == nil) { - return; - } - xf = atof(word)/1000.0; - www_dwnld_time_sum += xf; -#ifdef DINKY - printf("time: %s %f total %f\n", word, xf, xfer_sum); -#endif - word = strtok(nil, " "); /* Client IP address. */ - logtag = strtok(nil, "/"); /* Log tag. */ - if (logtag == nil) { - return; - } - if (logtag =~ "TCP") { - squid_client_http++; - } - if (logtag =~ "UDP") { - squid_icp_requests++; - } - if (logtag =~ "HIT") { - prxy_squid_cache_hits++; - } - if (logtag =~ "MISS") { - squid_cache_misses++; - } - - word = strtok(nil, " "); /* Reply code. */ - if (word == nil) { - return; - } - WWW_REPLY_CODE(word) - word = strtok(nil, " "); /* Size sent to client. */ - if (word == nil) { - return; - } - z = atoi(word); - WWW_SIZE_INDEX(z, size_index) - www_dwnld_time_by_size[size_index] += xf; - - request = strtok(nil, " "); /* Request method. */ - if (request == nil) { - return; - } - WWW_METHOD(request) - /* Do not add the size if it is a HEAD. */ - if (ishead == 0) { - dwnld_totalz += z; - } - - word = strtok(nil, " "); /* URL. */ - if (word == nil) { - return; - } - if (word =~ "cgi-bin") { - httpop_cgi_bins++; - } - if (word =~ www_search_url) { - httpop_searches++; - } - strtok(nil, " "); /* Optional user identity. */ - word = strtok(nil, "/"); /* Hierarchy. */ - if (word == nil) { - return; - } - if (word =~ "DIRECT") { - prxy_squid_indirect++; - } -#if 0 - word = strtok(nil, " "); /* Hostname. */ - if (word == nil) { - return; - } - word = strtok(nil, " "); /* Content-type. */ - if (word == nil) { - return; - } -#endif - -#elif WATCH_YAHOO - /* - * Yahoo log format. Fields in square brackets will only appear in the - * log file if the data actually exists (i.e. you will never see a null - * Referrer field). Further, fields labeled here with "(CONFIG)" will - * only appear if they are enabled via the YahooLogOptions configuration - * directive. - * - * IP Address (8 hex digits) - * Timestamp (time_t as 8 hex digits) - * Processing Time (in microseconds, as 8 hex digits) - * Bytes Sent (8 hex digits) - * URL - * [^Er referrer] (CONFIG) - * [^Em method] (CONFIG) - * [^Es status_code] - * ^Ed signature - * \n - */ - - /* - * Ignore the IP address and timestamp. Get the processing time, the - * number of bytes sent and the URL. For each portion of the line, split - * it up into separate pieces. - */ - if (sscanf(word, "%8lx%8lx%8x%8x", &tmp, &tmp, &ulong_xf, &z) != 4) { - return; - } - - xf = ulong_xf/1000000.0; - WWW_SIZE_INDEX(z, size_index) - www_dwnld_time_sum += xf; - www_dwnld_time_by_size[size_index] += xf; - - if (word =~ "cgi-bin") { - httpop_cgi_bins++; - } - if (word =~ www_search_url) { - httpop_searches++; - } - - for (;;) { - word = strtok(nil, "\05"); - if (word == nil) { - break; - } - first_byte = word; - ptr = &word + 1; - arg = ((string) ptr); - ptr = 0; - switch (first_byte[0]) { - case 'm': - WWW_METHOD(arg) - ptr = 1; - break; - case 's': - WWW_REPLY_CODE(arg) - break; - default: - break; - } - } - - /* If no method was seen, then assume it was a GET. */ - if (ptr == 0) { - httpop_gets++; - } - - /* Do not add the size if it is a HEAD. */ - if (ishead == 0) { - dwnld_totalz += z; - } - -#else /* common or Netscape proxy formats */ - strtok(nil, " "); /* -. */ - strtok(nil, " "); /* -. */ - strtok(nil, " ["); /* date. */ - strtok(nil, " "); /* zone]. */ - strtok(nil, " \""); /* GET or POST. */ - if (word == nil) { - return; - } - WWW_METHOD(word) - word = strtok(nil, " "); /* URL. */ - if (word == nil) { - return; - } - if (word =~ "cgi-bin") { - httpop_cgi_bins++; - } - if (word =~ www_search_url) { - httpop_searches++; - } - /* - * Sometimes HTTP/1.x is not listed in the access log. Skip it - * if it does exist. Load the error/success code. - */ - word = strtok(nil, " "); - if (word == nil) { - return; - } - if (word =~ "HTTP" || word =~ "http") { - word = strtok(nil, " "); - if (word == nil) { - return; - } - } - WWW_REPLY_CODE(word) - word = strtok(nil, " "); /* Bytes transferred. */ - if (word == nil) { - return; - } - z = atoi(word); - /* Do not add the size if it is a HEAD. */ - if (ishead == 0) { - dwnld_totalz += z; - } - WWW_SIZE_INDEX(z, size_index) -#ifdef WATCH_PROXY - strtok(nil, " "); /* Status from server. */ - strtok(nil, " "); /* Length from server. */ - strtok(nil, " "); /* Length from client POST. */ - strtok(nil, " "); /* Length POSTed to remote. */ - strtok(nil, " "); /* Client header request. */ - strtok(nil, " "); /* Proxy header response. */ - strtok(nil, " "); /* Proxy header request. */ - strtok(nil, " "); /* Server header response. */ - strtok(nil, " "); /* Transfer total seconds. */ - word = strtok(nil, " "); /* Route. */ - if (word == nil) { - return; - } - - /* - DIRECT PROXY(host.domain:port) SOCKS. */ - if (strncmp(word, "PROXY", 5) == 0 || - strncmp(word, "SOCKS", 5) == 0) { - prxy_squid_indirect++; - } - strtok(nil, " "); /* Client finish status. */ - strtok(nil, " "); /* Server finish status. */ - word = strtok(nil, " "); /* Cache finish status. */ - if (word == nil) { - return; - } - /* - * ERROR HOST-NOT-AVAILABLE = error or incomplete op - * WRITTEN REFRESHED CL-MISMATCH(content length mismatch) = cache_writes - * NO-CHECK UP-TO-DATE = cache_hits - * DO-NOT-CACHE NON-CACHEABLE = uncacheable - */ - switch(word) { - case "WRITTEN": - case "REFRESHED": - case "CL-MISMATCH": - prxy_cache_writes++; - break; - case "NO-CHECK": - case "UP-TO-DATE": - prxy_squid_cache_hits++; - break; - case "DO-NOT-CACHE": - case "NON-CACHEABLE": - prxy_uncacheable++; - break; - default: - break; - } - word = strtok(nil, " ["); /* [transfer total time x.xxx. */ - if (word == nil) { - return; - } - xf = atof(word); - www_dwnld_time_sum += xf; - www_dwnld_time_by_size[size_index] += xf; -#endif -#endif -} - -measure_web(long sleep_till) -{ - double lastops = 0.0; - char buf[BUFSIZ]; - int i; - long now; - long sleep_till_tmp; - - httpops = 0.0; - httpops5 = 0.0; - gateops = 0.0; - httpop_gets = 0; - httpop_condgets = 0; - httpop_posts = 0; - httpop_cgi_bins = 0; - httpop_errors = 0; - httpop_searches = 0; - - for (i=0; i<5; ++i) { - dwnld_size[i] = 0; -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - www_dwnld_time_by_size[i] = 0.0; -#endif - } - dwnld_totalz = 0; - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - www_dwnld_time_sum = 0.0; -#endif -#if WATCH_PROXY || WATCH_SQUID - prxy_squid_indirect = 0; - prxy_squid_cache_hits = 0; -#ifdef WATCH_PROXY - prxy_cache_writes = 0; - prxy_uncacheable = 0; -#else - squid_cache_misses = 0; - squid_icp_requests = 0; - squid_icp_queries = 0; - squid_client_http = 0; -#endif -#endif - - if (www_log_filename != nil) { - now = time(0); - while (now < sleep_till) { - if (now + 5 < sleep_till) { - sleep_till_tmp = now + 5; - } else { - sleep_till_tmp = sleep_till; - } -#ifdef WATCH_CPU - sleep_till_and_count_new_processes(sleep_till_tmp); -#else - orca_sleep_till(sleep_till_tmp); -#endif - - now = time(0); - if (www_log_fp != 0) { - buf[BUFSIZ-1] = 127; - while (fgets(buf, BUFSIZ, www_log_fp) != nil) { - httpops += 1.0; - if (www_gatelen > 0) { - if (strncmp(buf, www_gateway, www_gatelen) == 0) { - gateops += 1.0; - } - } - accesslog(buf); - - /* - * If the line is longer than the buffer, then ignore the rest - * of the line. - */ - while (buf[BUFSIZ-1] == 0 && - buf[BUFSIZ-2] != '\n') { - buf[BUFSIZ-1] = 127; - if (fgets(buf, BUFSIZ, www_log_fp) == nil) { - break; - } - } - } - } - - /* - * See if the file has been switched or truncated. - */ - if (stat(www_log_filename, www_log_stat) == 0) { - if (www_log_ino != www_log_stat[0].st_ino || - www_log_size > www_log_stat[0].st_size) { - /* - * Close the old log file and open the new one. - */ - if (www_log_fp != 0) { - fclose(www_log_fp); - } - - www_log_fp = fopen(www_log_filename, "r"); - if (www_log_fp != 0) { - fstat(fileno(www_log_fp), www_log_stat); - www_log_ino = www_log_stat[0].st_ino; - www_log_size = www_log_stat[0].st_size; - buf[BUFSIZ-1] = 127; - while(fgets(buf, BUFSIZ, www_log_fp) != nil) { - httpops += 1.0; - if (www_gatelen > 0) { - if (strncmp(buf, www_gateway, www_gatelen) == 0) { - gateops += 1.0; - } - } - accesslog(buf); - - /* - * If the line is longer than the buffer, then ignore - * the rest of the line. - */ - while (buf[BUFSIZ-1] == 0 && - buf[BUFSIZ-2] != '\n') { - buf[BUFSIZ-1] = 127; - if (fgets(buf, BUFSIZ, www_log_fp) == nil) { - break; - } - } - } - } else { - www_log_ino = 0; - www_log_size = 0; - } - } else { - /* - * Remember size for next time. - */ - www_log_size = www_log_stat[0].st_size; - } - } - - www5_now = gethrtime(); - www5_interval = (www5_now - www5_then) * 0.000000001; - www5_then = www5_now; - dtmp = (httpops - lastops)/www5_interval; - if (dtmp > httpops5) { - httpops5 = dtmp; - } - lastops = httpops; - } - } - else { - sleep_till_and_count_new_processes(sleep_till); - www5_now = gethrtime(); - } - - www_now = www5_now; - www_interval = (www_now - www_then) * 0.000000001; - www_then = www_now; - - /* - * Use dtmp to get percentages. - */ - if (httpops == 0.0) { - dtmp = 0.0; - } - else { - dtmp = 100.0 / httpops; - } - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - for (i=0; i<5; ++i) { - if (dwnld_size[i] == 0) { - www_dwnld_time_by_size[i] = 0.0; - } - else { - www_dwnld_time_by_size[i] = www_dwnld_time_by_size[i]/dwnld_size[i]; - } - } -#endif -} - -// Functions in SE cannot return an array, so to work around this, have -// count_procs place it's results in a global array. -#define MAX_COUNT_PROC_REGEXS 2 -int count_procs_results[MAX_COUNT_PROC_REGEXS]; -count_procs(int number_regexs, string regexs[]) -{ - psinfo_t p; - int i; - - if (number_regexs > MAX_COUNT_PROC_REGEXS) { - fprintf(stderr, "%s: too many regular expressions (%d). Increase MAX_COUNT_PROC_REGEXS.\n", - program_name, number_regexs); - exit(1); - } - - for (i=0; i. +// +// Portions copied from percollator.se written by Adrian Cockroft. +// +// $HeadURL$ +// $LastChangedDate$ +// $LastChangedBy$ +// $LastChangedRevision$ +// +// Revision history for this file can be retrieved by running svn log +// on the HeadURL listed above. +// + +// The default sampling interval in seconds. +#define SAMPLE_INTERVAL 300 + +// The maximum number of columns of data. +#define MAX_COLUMNS 2048 + +// Enable kstat io measuring code. +#define USE_KSTAT_IO 1 + +// If WATCH_OS is defined, then measure every part of the operating +// system. +#ifdef WATCH_OS +#define WATCH_CPU 1 +#define WATCH_MUTEX 1 +#define WATCH_NET 1 +#define WATCH_TCP 1 +#define WATCH_NFS_CLIENT 1 +#define WATCH_NFS_SERVER 1 +#define WATCH_MOUNTS 1 +#define WATCH_DISK 1 +#define WATCH_DNLC 1 +#define WATCH_INODE 1 +#define WATCH_RAM 1 +#define WATCH_PAGES 1 +#endif + +// Keep backwards compatibility with WATCH_HTTPD. +#ifdef WATCH_HTTPD +#define WATCH_WEB 1 +#endif + +// Keep backwards compatibility with WATCH_NFS. +#ifdef WATCH_NFS +#ifndef WATCH_NFS_CLIENT +#define WATCH_NFS_CLIENT 1 +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#ifdef WATCH_MOUNTS +#include +#include +#endif + +#if WATCH_CPU || WATCH_WEB +#include + +#ifdef WATCH_CPU +// This is the maximum pid on Solaris hosts. +#define DEFAULT_MAXPID 30000 +#include +#endif + +#ifdef WATCH_WEB + +// Define this macro which returns the size index for a file of a +// particular size. This saves the overhead of a function call. +#define WWW_SIZE_INDEX(size, size_index) \ + if (size < 1024) { \ + size_index=0; /* Under 1KB */ \ + } else { \ + if (size < 10240) { \ + size_index=1; /* Under 10K */ \ + } else { \ + if (size < 102400) { \ + size_index=2; /* Under 100KB */ \ + } else { \ + if (size < 1048576) { \ + size_index=3; /* Under 1MB */ \ + } else { \ + size_index=4; /* Over 1MB */ \ + } \ + } \ + } \ + } \ + dwnld_size[size_index]++; + +// Handle the reply code from the server. +#define WWW_REPLY_CODE(word) \ + if (word == "304") { \ + httpop_condgets++; \ + } \ + else { \ + first_byte = word; \ + if (first_byte[0] == '4' || first_byte[0] == '5') { \ + httpop_errors++; \ + } \ + } \ + +// Handle the method of the object served. This define only works +// with non-proxy servers. +#define WWW_METHOD1(word) \ + switch (word) { \ + case "get": \ + case "GET": \ + httpop_gets++; \ + break; \ + case "post": \ + case "POST": \ + httpop_posts++; \ + break; \ + case "head": \ + case "HEAD": \ + ishead = 1; \ + httpop_condgets++; \ + break; + +#ifdef WATCH_SQUID +#define WWW_METHOD2 \ + case "icp_query": \ + case "ICP_QUERY": \ + squid_icp_queries++; \ + break; +#else +#define WWW_METHOD2 +#endif + +#define WWW_METHOD_END \ + default: \ + break; \ + } +#define WWW_METHOD(word) WWW_METHOD1(word) WWW_METHOD2 WWW_METHOD_END +#endif +#endif + +// Put all rules here so they can be accessed by the handle functions. +lr_cpu_t lr_cpu$cpu; +lr_cpu_t tmp_lr_cpu; +lr_mutex_t lr_mutex$m; +lr_mutex_t tmp_lr_mutex; +lr_net_t lr_net$nr; +lr_net_t tmp_lr_net; +lr_tcp_t lr_tcp$tcp; +lr_tcp_t tmp_lr_tcp; +lr_rpcclient_t lr_rpcclient$r; +lr_rpcclient_t tmp_lr_rpcclient; +lr_disk_t lr_disk$dr; +lr_disk_t tmp_lr_disk; +lr_dnlc_t lr_dnlc$dnlc; +lr_dnlc_t tmp_lr_dnlc; +lr_inode_t lr_inode$inode; +lr_inode_t tmp_lr_inode; +lr_ram_t lr_ram$ram; +lr_ram_t tmp_lr_ram; +lr_swapspace_t lr_swapspace$s; +lr_swapspace_t tmp_lr_swapspace; +lr_kmem_t lr_kmem$kmem; +lr_kmem_t tmp_lr_kmem; + +ks_system_misc kstat$misc; +ks_system_misc tmp_kstat_misc; +#ifdef WATCH_TCP +tcp tcp$tcp; +tcp tmp_tcp; +#endif +#ifdef WATCH_PAGES +ks_system_pages kstat$pages; +ks_system_pages tmp_kstat_pages; +#endif + +// Put application globals here. +string nodename; // Name of this machine. +string program_name; // Name of this program. +int hz; // Clock tick rate. +int page_size; // Page size in bytes. +long boot_time; // Boot time of the system. +long interval = SAMPLE_INTERVAL; // Sampling interval. + +#ifdef WATCH_CPU +int can_read_kernel = 0; // If the kernel can be read. +int kvm$mpid; // The last created PID. + +// These variables store the mpid before and after the standard interval. +int mpid_previous; +int mpid_current; +ulonglong mpid_then; +ulonglong mpid_now; + +// These variables store the mpid before and after 5 second intervals. +int mpid5_previous; +int mpid5_current; +ulonglong mpid5_then; +ulonglong mpid5_now; +double mpid5_rate; +#endif + +#ifdef WATCH_MOUNTS +mnttab_t mnt$mnt; +mnttab_t tmp_mnt; +#endif + +#ifdef WATCH_NFS_SERVER +ks_nfs_server kstat$nfs; +ks_nfs_server tmp_nfs; +ks_rfs_proc_v2 kstat$rfsproccnt_v2; +ks_rfs_proc_v2 tmp_rfsproccnt_v2; +ks_rfs_proc_v3 kstat$rfsproccnt_v3; +ks_rfs_proc_v3 tmp_rfsproccnt_v3; +#endif + +// Variables for handling the httpd access log. +#ifdef WATCH_WEB +string www_search_url = getenv("SEARCHURL"); +string www_server_proc_name = getenv("WEB_SERVER"); +string www_server_secure_proc_name = getenv("WEB_SERVER_SECURE"); +string www_log_filename = getenv("WEB_LOG"); +string www_gateway = getenv("GATEWAY"); +ulong www_log_fp; +uint www_gatelen; +stat_t www_log_stat[1]; +ulong www_log_ino; +long www_log_size; + +double www_interval; // Hi-res interval time. +ulonglong www_then; +ulonglong www_now; + +double www5_interval; // Actual hi-res 5 second interval. +ulonglong www5_then; +ulonglong www5_now; + +double httpops; +double httpops5; +double gateops; +double dtmp; + +long httpop_gets; +long httpop_condgets; // HEAD or code = 304 conditional get no data. +long httpop_posts; +long httpop_cgi_bins; +long httpop_searches; +long httpop_errors; +long dwnld_size[5]; // [0] < 1K, [1] < 10K, [2] < 100K, [3] < 1M, [4] >= 1M +long dwnld_totalz; // Total size counted from log. + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO +// If we're watching a Yahoo log, then take the transfer time to be the +// processing time. +double www_dwnld_time_sum; // Transfer time. +double www_dwnld_time_by_size[5]; // Mean transfer time by size bin. +#endif +#if WATCH_PROXY || WATCH_SQUID +long prxy_squid_indirect; // # hits that go via PROXY,SOCKS,parent +long prxy_squid_cache_hits; // # hits returned from cache. +#endif + +#ifdef WATCH_PROXY +long prxy_cache_writes; // Number of writes and updates to cache. +long prxy_uncacheable; // Number of explicitly uncacheable httpops. + // Any extra is errors or incomplete ops. +#endif + +#ifdef WATCH_SQUID +long squid_cache_misses; +long squid_icp_requests; +long squid_icp_queries; +long squid_client_http; +#endif + +#endif + +#ifdef USE_KSTAT_IO +#include +#include +// This code was developed so that the performance of virtual disks +// originating from a Sun A1000 raid controller could be monitored. +// These disks do not show up in the GLOBAL_disk[] io structure of SE. +// +// This extension accesses the sys_kstat.se interface to the kstat IO +// queues to extract info on drives not available in the kstat.se +// kstat$disk interface. Global data shared between function calls. +struct io_dev_info_t { + // Exposed interface that matches kstat. + string long_name; + string short_name; + double reads; + double kreads; + double writes; + double kwrites; + double avg_wait; + double avg_serv; + double service; + double wait_percent; + double run_percent; + + // Hidden internal registers to track sys_kstats counters. + int _number; // kstat disk # + ulonglong _nread; // Number of bytes read + ulonglong _nwritten; // Number of bytes written + uint _reads; // Number of read operations + uint _writes; // Number of write operations + longlong _wtime; // Cumulative wait (pre-service) time + longlong _wlentime; // Cumulative wait length*time product + longlong _wlastupdate; // Last time wait queue changed + longlong _rtime; // Cumulative run (service) time + longlong _rlentime; // Cumulative run length*time product + longlong _rlastupdate; // Last time run queue changed + uint _wcnt; // Count of elements in wait state + uint _rcnt; // Count of elements in run state +}; + +// Define global for tracking raw disk data. +io_dev_info_t ORCA_io_dev_info[]; +int ORCA_io_dev_count=0; +int ORCA_max_io_dev_count=0; + +orca_io_info_update() { + int iodev; + int index; + ulong ul; + kstat_ctl_t kc[1]; + kstat_t kp[1]; + kstat_t nkp[1]; + kstat_io_t kio; + ulonglong _nread; + ulonglong _nwritten; + uint _reads; + uint _writes; + longlong _wtime; + longlong _wlentime; + longlong _wlastupdate; + longlong _rtime; + longlong _rlentime; + longlong _rlastupdate; + longlong _wcnt; + longlong _rcnt; + + double read_writes; + double big_etime; + double elapsed_etime; + double hz_etime; + double nanosecond = NANOSEC; + + kc[0] = kstat_open(); + // Read them. + if (kstat_read(kc, kp, 0) == -1) { + perror("orca_io_info_update:kstat_read"); + exit(1); + } + + // Traverse the chain looking for IO events. + for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { + struct_fill(nkp[0], ul); + if (nkp[0].ks_type == KSTAT_TYPE_IO) { + // Look for disk or tape statistics + if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { + // Try to locate device. + for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { + if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { + break; + } + } + + // It must be new. Add it! + if (iodev == ORCA_io_dev_count) { + // Grow the device array if needed + if (ORCA_io_dev_count == ORCA_max_io_dev_count) { + ORCA_max_io_dev_count += 10; + ORCA_io_dev_info = renew ORCA_io_dev_info[ORCA_max_io_dev_count]; + } + + if (nkp[0].ks_class == "tape") { + index = find_tape_inst(nkp[0].ks_name); + } else { + index = find_inst(nkp[0].ks_name); + } + if (index != -1) { + if (nkp[0].ks_class == "tape") { + ORCA_io_dev_info[iodev].long_name = GLOBAL_tape_info[index].long_name; + } else { + ORCA_io_dev_info[iodev].long_name = GLOBAL_disk_info[index].long_name; + } + } else { + ORCA_io_dev_info[iodev].long_name = nkp[0].ks_name; + } + ORCA_io_dev_info[iodev].short_name = nkp[0].ks_name; + + ORCA_io_dev_info[iodev]._reads = 0; + ORCA_io_dev_info[iodev]._nread = 0; + ORCA_io_dev_info[iodev]._rlentime = 0; + ORCA_io_dev_info[iodev]._rlastupdate = boot_time; + ORCA_io_dev_info[iodev]._rcnt = 0; + ORCA_io_dev_info[iodev]._writes = 0; + ORCA_io_dev_info[iodev]._nwritten = 0; + ORCA_io_dev_info[iodev]._wlentime = 0; + ORCA_io_dev_info[iodev]._wlastupdate = boot_time; + ORCA_io_dev_info[iodev]._wcnt = 0; + ORCA_io_dev_count++; + } + + // Update the device registers. + if (kstat_read(kc, nkp, 0) == -1) { + perror("orca_io_info_update:kstat_read error"); + exit(1); + } else { + // Read sys_kstat device IO queue to find out about recent + // activity. We validate data that is returned. Solaris + // 2.6 has occasional glitches when updating certain disks + // (c0t0d0) so we cover up the glitches by using data from + // the previous cycle. Eventually, we will get a good + // update. Fixing the data is not necessarily the best + // choice. Currently only kio.nread glitches. Correcting + // the error forces the IOs to get attributed to the next IO + // cycle. + struct_fill(kio, nkp[0].ks_data); + + _nread = kio.nread; + if (ORCA_io_dev_info[iodev]._nread > _nread) { + _nread = ORCA_io_dev_info[iodev]._nread; + } + _reads = kio.reads; + if (ORCA_io_dev_info[iodev]._reads > _reads) { + _reads = ORCA_io_dev_info[iodev]._reads; + } + _rlentime = kio.rlentime; + _rtime = kio.rtime; + _rlastupdate = kio.wlastupdate; + _rcnt = kio.rcnt; + _nwritten = kio.nwritten; + if (ORCA_io_dev_info[iodev]._nwritten > _nwritten) { + _nwritten = ORCA_io_dev_info[iodev]._nwritten; + } + _writes = kio.writes; + if (ORCA_io_dev_info[iodev]._writes > _writes) { + _writes = ORCA_io_dev_info[iodev]._nwritten; + } + _wlentime = kio.wlentime; + _wtime = kio.wtime; + _wlastupdate = kio.wlastupdate; + _wcnt = kio.wcnt; + + elapsed_etime = (_wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); + if (elapsed_etime > 0) { + hz_etime = elapsed_etime / nanosecond; + big_etime = 1024.0 * hz_etime; + } else { + elapsed_etime = nanosecond; + hz_etime = 1.0; + big_etime = 1024.0; + } + ORCA_io_dev_info[iodev].reads =(_reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; + ORCA_io_dev_info[iodev].kreads =(_nread-ORCA_io_dev_info[iodev]._nread) /big_etime; + ORCA_io_dev_info[iodev].writes =(_writes-ORCA_io_dev_info[iodev]._writes)/hz_etime; + ORCA_io_dev_info[iodev].kwrites=(_nwritten-ORCA_io_dev_info[iodev]._nwritten) / big_etime; + + read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; + if (read_writes > 0) { + ORCA_io_dev_info[iodev].avg_wait = (_wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; + ORCA_io_dev_info[iodev].avg_serv = (_rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; + ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; + } else { + ORCA_io_dev_info[iodev].avg_wait = 0.0; + ORCA_io_dev_info[iodev].avg_serv = 0.0; + ORCA_io_dev_info[iodev].service = 0.0; + } + + // Update the counters. + ORCA_io_dev_info[iodev].run_percent = 100.0 * (_rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; + ORCA_io_dev_info[iodev].wait_percent = 100.0 * (_wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; + ORCA_io_dev_info[iodev]._writes = _writes; + ORCA_io_dev_info[iodev]._nwritten = _nwritten; + ORCA_io_dev_info[iodev]._wlastupdate = _wlastupdate; + ORCA_io_dev_info[iodev]._wlentime = _wlentime; + ORCA_io_dev_info[iodev]._wtime = _wtime; + ORCA_io_dev_info[iodev]._wcnt = _wcnt; + ORCA_io_dev_info[iodev]._reads = _reads; + ORCA_io_dev_info[iodev]._nread = _nread; + ORCA_io_dev_info[iodev]._rlastupdate = _rlastupdate; + ORCA_io_dev_info[iodev]._rlentime = _rlentime; + ORCA_io_dev_info[iodev]._rtime = _rtime; + ORCA_io_dev_info[iodev]._rcnt = _rcnt; + } + } + } + } + kstat_close(kc); +} +#endif // USE_KSTAT_IO + +// Variables for handling output. +string compress = getenv("COMPRESSOR"); // How to compress logs. +ulong out_log_fp; // File pointer to the logging file. +string col_comment[MAX_COLUMNS]; // Comments for each column. +string col_data[MAX_COLUMNS]; // Data for each column. +string col_previous_comment[MAX_COLUMNS]; // Previous comments. +int current_column = 0; // The current column. +int previous_number_columns = -1; // Number columns printed last. +int print_header = 1; // Flag to flush header. + +// This is a list of the extensions the compress programs add to the +// compress filename. +#define NUMBER_COMPRESS_SUFFIXES 3 +string compression_suffixes[NUMBER_COMPRESS_SUFFIXES] = {".Z", + ".gz", + ".bz2"}; + +// Add one column of comments and data to the buffers. +put_output(string comment, string data) +{ + if (current_column >= MAX_COLUMNS) { + fprintf(stderr, "%s: too many columns (%d). Increase MAX_COLUMNS.\n", + program_name, current_column); + exit(1); + } + + col_comment[current_column] = comment; + col_data[current_column] = data; + current_column++; +} + +// Send the stored columns of information to the output. +print_columns(string data[]) +{ + int i; + for (i=0; i 0) { + usleep(1000000*time_to_sleep - now[0].tv_usec); + gettimeofday(now, 0); + time_to_sleep = sleep_till - now[0].tv_sec; + } +} + +sleep_till_and_count_new_processes(long sleep_till) +{ + long now; +#ifdef WATCH_CPU + int mpid5_diff; + double mpid5_interval; + double rate; +#endif + + now = time(0); + while (now < sleep_till) { +#ifdef WATCH_CPU + if (can_read_kernel != 0) { + // Sleep for 5 seconds to make a measurement or less to stay + // within the sleep_till limit. + if (now + 5 < sleep_till) { + orca_sleep_till(now + 5); + } else { + orca_sleep_till(sleep_till); + } + + // Measure the 5 second process creation rate. + mpid5_current = kvm$mpid; + mpid5_now = gethrtime(); + mpid5_interval = (mpid5_now - mpid5_then) * 0.000000001; + mpid5_then = mpid5_now; + if (mpid5_current >= mpid5_previous) { + mpid5_diff = mpid5_current - mpid5_previous; + } + else { + mpid5_diff = mpid5_current + DEFAULT_MAXPID - mpid5_previous; + } + rate = mpid5_diff/mpid5_interval; + if (rate > mpid5_rate) { + mpid5_rate = rate; + } + mpid5_previous = mpid5_current; + + // Now take these results to measure the long interval rate. + // Because the mpid may flip over DEFAULT_MAXPID more than once + // in the long interval time span, use the difference between + // the previous and current mpid over a 5 second interval to + // calculate the long interval difference. + mpid_current += mpid5_diff; + mpid_now = mpid5_now; + } + else { + orca_sleep_till(sleep_till); + } +#else + orca_sleep_till(sleep_till); +#endif + now = time(0); + } +} + +#ifdef WATCH_CPU +measure_cpu() +{ + p_vmstat pvm; + double mpid_interval; + double mpid_rate; + + pvm = vmglobal_total(); + + // In SE 3.0 and below user_time and system_time are int and in SE + // 3.1 and above they are double, so cast everything to double using + // + 0.0. + put_output(" usr%", sprintf("%5.1f", pvm.user_time + 0.0)); + put_output(" sys%", sprintf("%5.1f", pvm.system_time + 0.0)); + put_output(" wio%", sprintf("%5.1f", pvm.wait_time + 0.0)); + put_output("idle%", sprintf("%5.1f", pvm.idle_time + 0.0)); + put_output(" 1runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_1min/256.0)); + put_output(" 5runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_5min/256.0)); + put_output("15runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_15min/256.0)); + put_output("#proc", sprintf("%5lu", tmp_kstat_misc.nproc)); + put_output(" #runque", sprintf("%8.2f", pvm.runque + 0.0)); + put_output("#waiting", sprintf("%8.2f", pvm.waiting + 0.0)); + put_output(" #swpque", sprintf("%8.2f", pvm.swpque + 0.0)); + put_output("scanrate", sprintf("%8.3f", pvm.scan + 0.0)); + put_output("pgrec/s", sprintf("%8.3f", pvm.pgrec + 0.0)); + put_output("pgfrec/s", sprintf("%8.3f", pvm.pgfrec + 0.0)); + put_output("pgin/s", sprintf("%8.3f", pvm.pgin + 0.0)); + put_output("pages_in/s", sprintf("%8.3f", pvm.pages_in + 0.0)); + put_output("pgout/s", sprintf("%8.3f", pvm.pgout + 0.0)); + put_output("pages_out/s", sprintf("%8.3f", pvm.pages_out + 0.0)); + put_output("dfree/s", sprintf("%8.3f", pvm.dfree + 0.0)); + put_output("min_fault/s", sprintf("%8.3f", pvm.hat_fault + pvm.as_fault + 0.0)) +; + put_output("maj_fault/s", sprintf("%8.3f", pvm.maj_fault + 0.0)); + put_output("prot_fault/s", sprintf("%8.3f", pvm.prot_fault + 0.0)); + put_output("cow_fault/s", sprintf("%8.3f", pvm.cow_fault + 0.0)); + put_output("zfod/s", sprintf("%8.3f", pvm.zfod + 0.0)); + put_output("interrupts/s", sprintf("%8.3f", pvm.interrupts + 0.0)); + put_output("intrthread/s", sprintf("%8.3f", pvm.intrthread + 0.0)); + put_output("system_calls/s", sprintf("%8.3f", pvm.system_calls + 0.0)); + put_output("context_switches/s", sprintf("%8.3f", pvm.context_switches + 0.0)); + put_output("invol_switches/s", sprintf("%8.3f", pvm.invol_switches + 0.0)); + put_output("traps/s", sprintf("%8.3f", pvm.trap + 0.0)); + put_output("forks/s", sprintf("%8.3f", pvm.sysfork + 0.0)); + put_output("vforks/s", sprintf("%8.3f", pvm.sysvfork + 0.0)); + put_output("execs/s", sprintf("%8.3f", pvm.sysexec + 0.0)); + put_output("namei/s", sprintf("%8.3f", pvm.namei + 0.0)); + put_output("ufsiget/s", sprintf("%8.3f", pvm.ufsiget + 0.0)); + put_output("ufsdirblk/s", sprintf("%8.3f", pvm.ufsdirblk + 0.0)); + + // Calculate the rate of new process spawning. + if (can_read_kernel != 0) { + mpid_interval = (mpid_now - mpid_then) * 0.000000001; + mpid_rate = (mpid_current - mpid_previous) / mpid_interval; + put_output("#proc/s", sprintf("%7.3f", mpid_rate)); + put_output("#proc/p5s", sprintf("%9.4f", mpid5_rate)); + + // Reset counters. + mpid_then = mpid_now; + mpid_previous = mpid_current; + mpid5_rate = 0; + } +} +#endif + +#ifdef WATCH_MUTEX +measure_mutex() +{ + put_output(" smtx", sprintf("%5d", tmp_lr_mutex.smtx)); + put_output("smtx/cpu", sprintf("%8d", tmp_lr_mutex.smtx/GLOBAL_pvm_ncpus)); +} +#endif + +#ifdef WATCH_NET +measure_net() +{ + int previous_count = -1; + int current_count; + int i; + + current_count = 0; + for (i=0; i. Check + // [wr]lentime to see if an EMC is using a fake disk for control. + // EMC disks have a fake disk which commands are run over to + // configure the disk array or to get stats from; they are not + // real data transfers. They cause 1000 MB/sec writes to appear + // in the stats. I still get them but not as often with this bit + // of code in. If the I/O which occurred in the last five minutes + // is not greater than 1/100sec then it is not a valid measurement + // anyway. What happens is that we can have a small I/O, say 1024 + // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making + // it wlentime+rlentime>2 since I am still getting fake write + // spikes. +#ifdef HAVE_EMC_DISK_CONTROL + if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { +#endif + total_disk_reads += ORCA_io_dev_info[i].reads; + total_disk_writes += ORCA_io_dev_info[i].writes; + total_disk_readk += ORCA_io_dev_info[i].kreads; + total_disk_writek += ORCA_io_dev_info[i].kwrites; + mean_disk_busy += ORCA_io_dev_info[i].run_percent; + if (ORCA_io_dev_info[i].run_percent > peak_disk_busy) { + peak_disk_busy = ORCA_io_dev_info[i].run_percent; + } +#ifdef HAVE_EMC_DISK_CONTROL + } +#endif + } +#else + for (i=0; i. Check + // [wr]lentime to see if an EMC is using a fake disk for control. + // EMC disks have a fake disk which commands are run over to + // configure the disk array or to get stats from; they are not + // real data transfers. They cause 1000 MB/sec writes to appear + // in the stats. I still get them but not as often with this bit + // of code in. If the I/O which occurred in the last five minutes + // is not greater than 1/100sec then it is not a valid measurement + // anyway. What happens is that we can have a small I/O, say 1024 + // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making + // it wlentime+rlentime>2 since I am still getting fake write + // spikes. +#ifdef HAVE_EMC_DISK_CONTROL + if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { +#endif + total_disk_reads += GLOBAL_disk[i].reads; + total_disk_writes += GLOBAL_disk[i].writes; + total_disk_readk += GLOBAL_disk[i].kreads; + total_disk_writek += GLOBAL_disk[i].kwrites; + mean_disk_busy += GLOBAL_disk[i].run_percent; + if (GLOBAL_disk[i].run_percent > peak_disk_busy) { + peak_disk_busy = GLOBAL_disk[i].run_percent; + } +#ifdef HAVE_EMC_DISK_CONTROL + } +#endif + } +#endif + + if (disk_count != 0) { + mean_disk_busy = mean_disk_busy/disk_count; + } + + put_output("disk_peak", sprintf("%9.3f", peak_disk_busy)); + put_output("disk_mean", sprintf("%9.3f", mean_disk_busy)); + put_output("disk_rd/s", sprintf("%9.1f", total_disk_reads)); + put_output("disk_wr/s", sprintf("%9.1f", total_disk_writes)); + put_output("disk_rK/s", sprintf("%9.1f", total_disk_readk)); + put_output("disk_wK/s", sprintf("%9.1f", total_disk_writek)); + + put_output("tape_rd/s", sprintf("%9.1f", total_tape_reads)); + put_output("tape_wr/s", sprintf("%9.1f", total_tape_writes)); + put_output("tape_rK/s", sprintf("%9.1f", total_tape_readk)); + put_output("tape_wK/s", sprintf("%9.1f", total_tape_writek)); + + // If the number of disks and/or tapes has changed, say due to a + // add_drv, then print new headers. + if (previous_disk_count != disk_count) { + print_header = 1; + previous_disk_count = disk_count; + } + if (previous_tape_count != tape_count) { + print_header = 1; + previous_tape_count = tape_count; + } +} +#endif + +#ifdef WATCH_DNLC +measure_dnlc() +{ + put_output("dnlc_ref/s", sprintf("%10.3f", tmp_lr_dnlc.refrate)); + put_output("dnlc_hit%", sprintf("%9.3f", tmp_lr_dnlc.hitrate)); +} +#endif + +#ifdef WATCH_INODE +measure_inode() +{ + p_vmstat pvm; + + put_output("inod_ref/s", sprintf("%10.3f", tmp_lr_inode.refrate)); + put_output("inod_hit%", sprintf("%9.3f", tmp_lr_inode.hitrate)); + put_output("inod_stl/s", sprintf("%10.3f", tmp_lr_inode.iprate)); + put_output("ufsinopage/s", sprintf("%8.3f", pvm.ufsinopage + 0.0)); + +} +#endif + +#ifdef WATCH_RAM +measure_ram() +{ + put_output("swap_avail", sprintf("%10ld", GLOBAL_pvm[0].swap_avail)); + put_output("page_rstim", sprintf("%10d", tmp_lr_ram.restime)); + put_output(" freememK", sprintf("%10d", GLOBAL_pvm[0].freemem)); + put_output("free_pages", sprintf("%10d", (GLOBAL_pvm[0].freemem*1024)/page_size)); +} +#endif + +#ifdef WATCH_PAGES +measure_pages() +{ + put_output("pp_kernel", sprintf("%9lu", tmp_kstat_pages.pp_kernel)); + put_output("pagesfree", sprintf("%9lu", tmp_kstat_pages.pagesfree)); + put_output("pageslock", sprintf("%9lu", tmp_kstat_pages.pageslocked)); +#if MINOR_VERSION < 80 + put_output("pagesio", sprintf("%7lu", tmp_kstat_pages.pagesio)); +#endif + put_output("pagestotl", sprintf("%9lu", tmp_kstat_pages.pagestotal)); +} +#endif + +#ifdef WATCH_WEB +/* + * Breakdown access log format. + */ +accesslog(string buf) { + int z; + int size_index; + int ishead; + string word; + char first_byte[1]; + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + double xf; +#ifdef WATCH_SQUID + string logtag; + string request; +#endif +#ifdef WATCH_YAHOO + string arg; + ulong ptr; + ulong tmp; + ulong ulong_xf; +#endif +#endif + + ishead = 0; +#ifdef WATCH_YAHOO + /* + * Make sure that the input line has at least 32 bytes of data plus a new + * line, for a total length of 33. + */ + if (strlen(buf) < 33) { + return; + } + word = strtok(buf, "\05"); +#else + word = strtok(buf, " "); +#endif + if (word == nil) { + return; + } + +#ifdef WATCH_SQUID + /* + * Word contains unix time in seconds.milliseconds. + */ + word = strtok(nil, " "); + if (word == nil) { + return; + } + xf = atof(word)/1000.0; + www_dwnld_time_sum += xf; +#ifdef DINKY + printf("time: %s %f total %f\n", word, xf, xfer_sum); +#endif + word = strtok(nil, " "); /* Client IP address. */ + logtag = strtok(nil, "/"); /* Log tag. */ + if (logtag == nil) { + return; + } + if (logtag =~ "TCP") { + squid_client_http++; + } + if (logtag =~ "UDP") { + squid_icp_requests++; + } + if (logtag =~ "HIT") { + prxy_squid_cache_hits++; + } + if (logtag =~ "MISS") { + squid_cache_misses++; + } + + word = strtok(nil, " "); /* Reply code. */ + if (word == nil) { + return; + } + WWW_REPLY_CODE(word) + word = strtok(nil, " "); /* Size sent to client. */ + if (word == nil) { + return; + } + z = atoi(word); + WWW_SIZE_INDEX(z, size_index) + www_dwnld_time_by_size[size_index] += xf; + + request = strtok(nil, " "); /* Request method. */ + if (request == nil) { + return; + } + WWW_METHOD(request) + /* Do not add the size if it is a HEAD. */ + if (ishead == 0) { + dwnld_totalz += z; + } + + word = strtok(nil, " "); /* URL. */ + if (word == nil) { + return; + } + if (word =~ "cgi-bin") { + httpop_cgi_bins++; + } + if (word =~ www_search_url) { + httpop_searches++; + } + strtok(nil, " "); /* Optional user identity. */ + word = strtok(nil, "/"); /* Hierarchy. */ + if (word == nil) { + return; + } + if (word =~ "DIRECT") { + prxy_squid_indirect++; + } +#if 0 + word = strtok(nil, " "); /* Hostname. */ + if (word == nil) { + return; + } + word = strtok(nil, " "); /* Content-type. */ + if (word == nil) { + return; + } +#endif + +#elif WATCH_YAHOO + /* + * Yahoo log format. Fields in square brackets will only appear in the + * log file if the data actually exists (i.e. you will never see a null + * Referrer field). Further, fields labeled here with "(CONFIG)" will + * only appear if they are enabled via the YahooLogOptions configuration + * directive. + * + * IP Address (8 hex digits) + * Timestamp (time_t as 8 hex digits) + * Processing Time (in microseconds, as 8 hex digits) + * Bytes Sent (8 hex digits) + * URL + * [^Er referrer] (CONFIG) + * [^Em method] (CONFIG) + * [^Es status_code] + * ^Ed signature + * \n + */ + + /* + * Ignore the IP address and timestamp. Get the processing time, the + * number of bytes sent and the URL. For each portion of the line, split + * it up into separate pieces. + */ + if (sscanf(word, "%8lx%8lx%8x%8x", &tmp, &tmp, &ulong_xf, &z) != 4) { + return; + } + + xf = ulong_xf/1000000.0; + WWW_SIZE_INDEX(z, size_index) + www_dwnld_time_sum += xf; + www_dwnld_time_by_size[size_index] += xf; + + if (word =~ "cgi-bin") { + httpop_cgi_bins++; + } + if (word =~ www_search_url) { + httpop_searches++; + } + + for (;;) { + word = strtok(nil, "\05"); + if (word == nil) { + break; + } + first_byte = word; + ptr = &word + 1; + arg = ((string) ptr); + ptr = 0; + switch (first_byte[0]) { + case 'm': + WWW_METHOD(arg) + ptr = 1; + break; + case 's': + WWW_REPLY_CODE(arg) + break; + default: + break; + } + } + + /* If no method was seen, then assume it was a GET. */ + if (ptr == 0) { + httpop_gets++; + } + + /* Do not add the size if it is a HEAD. */ + if (ishead == 0) { + dwnld_totalz += z; + } + +#else /* common or Netscape proxy formats */ + strtok(nil, " "); /* -. */ + strtok(nil, " "); /* -. */ + strtok(nil, " ["); /* date. */ + strtok(nil, " "); /* zone]. */ + strtok(nil, " \""); /* GET or POST. */ + if (word == nil) { + return; + } + WWW_METHOD(word) + word = strtok(nil, " "); /* URL. */ + if (word == nil) { + return; + } + if (word =~ "cgi-bin") { + httpop_cgi_bins++; + } + if (word =~ www_search_url) { + httpop_searches++; + } + /* + * Sometimes HTTP/1.x is not listed in the access log. Skip it + * if it does exist. Load the error/success code. + */ + word = strtok(nil, " "); + if (word == nil) { + return; + } + if (word =~ "HTTP" || word =~ "http") { + word = strtok(nil, " "); + if (word == nil) { + return; + } + } + WWW_REPLY_CODE(word) + word = strtok(nil, " "); /* Bytes transferred. */ + if (word == nil) { + return; + } + z = atoi(word); + /* Do not add the size if it is a HEAD. */ + if (ishead == 0) { + dwnld_totalz += z; + } + WWW_SIZE_INDEX(z, size_index) +#ifdef WATCH_PROXY + strtok(nil, " "); /* Status from server. */ + strtok(nil, " "); /* Length from server. */ + strtok(nil, " "); /* Length from client POST. */ + strtok(nil, " "); /* Length POSTed to remote. */ + strtok(nil, " "); /* Client header request. */ + strtok(nil, " "); /* Proxy header response. */ + strtok(nil, " "); /* Proxy header request. */ + strtok(nil, " "); /* Server header response. */ + strtok(nil, " "); /* Transfer total seconds. */ + word = strtok(nil, " "); /* Route. */ + if (word == nil) { + return; + } + + /* - DIRECT PROXY(host.domain:port) SOCKS. */ + if (strncmp(word, "PROXY", 5) == 0 || + strncmp(word, "SOCKS", 5) == 0) { + prxy_squid_indirect++; + } + strtok(nil, " "); /* Client finish status. */ + strtok(nil, " "); /* Server finish status. */ + word = strtok(nil, " "); /* Cache finish status. */ + if (word == nil) { + return; + } + /* + * ERROR HOST-NOT-AVAILABLE = error or incomplete op + * WRITTEN REFRESHED CL-MISMATCH(content length mismatch) = cache_writes + * NO-CHECK UP-TO-DATE = cache_hits + * DO-NOT-CACHE NON-CACHEABLE = uncacheable + */ + switch(word) { + case "WRITTEN": + case "REFRESHED": + case "CL-MISMATCH": + prxy_cache_writes++; + break; + case "NO-CHECK": + case "UP-TO-DATE": + prxy_squid_cache_hits++; + break; + case "DO-NOT-CACHE": + case "NON-CACHEABLE": + prxy_uncacheable++; + break; + default: + break; + } + word = strtok(nil, " ["); /* [transfer total time x.xxx. */ + if (word == nil) { + return; + } + xf = atof(word); + www_dwnld_time_sum += xf; + www_dwnld_time_by_size[size_index] += xf; +#endif +#endif +} + +measure_web(long sleep_till) +{ + double lastops = 0.0; + char buf[BUFSIZ]; + int i; + long now; + long sleep_till_tmp; + + httpops = 0.0; + httpops5 = 0.0; + gateops = 0.0; + httpop_gets = 0; + httpop_condgets = 0; + httpop_posts = 0; + httpop_cgi_bins = 0; + httpop_errors = 0; + httpop_searches = 0; + + for (i=0; i<5; ++i) { + dwnld_size[i] = 0; +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + www_dwnld_time_by_size[i] = 0.0; +#endif + } + dwnld_totalz = 0; + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + www_dwnld_time_sum = 0.0; +#endif +#if WATCH_PROXY || WATCH_SQUID + prxy_squid_indirect = 0; + prxy_squid_cache_hits = 0; +#ifdef WATCH_PROXY + prxy_cache_writes = 0; + prxy_uncacheable = 0; +#else + squid_cache_misses = 0; + squid_icp_requests = 0; + squid_icp_queries = 0; + squid_client_http = 0; +#endif +#endif + + if (www_log_filename != nil) { + now = time(0); + while (now < sleep_till) { + if (now + 5 < sleep_till) { + sleep_till_tmp = now + 5; + } else { + sleep_till_tmp = sleep_till; + } +#ifdef WATCH_CPU + sleep_till_and_count_new_processes(sleep_till_tmp); +#else + orca_sleep_till(sleep_till_tmp); +#endif + + now = time(0); + if (www_log_fp != 0) { + buf[BUFSIZ-1] = 127; + while (fgets(buf, BUFSIZ, www_log_fp) != nil) { + httpops += 1.0; + if (www_gatelen > 0) { + if (strncmp(buf, www_gateway, www_gatelen) == 0) { + gateops += 1.0; + } + } + accesslog(buf); + + /* + * If the line is longer than the buffer, then ignore the rest + * of the line. + */ + while (buf[BUFSIZ-1] == 0 && + buf[BUFSIZ-2] != '\n') { + buf[BUFSIZ-1] = 127; + if (fgets(buf, BUFSIZ, www_log_fp) == nil) { + break; + } + } + } + } + + /* + * See if the file has been switched or truncated. + */ + if (stat(www_log_filename, www_log_stat) == 0) { + if (www_log_ino != www_log_stat[0].st_ino || + www_log_size > www_log_stat[0].st_size) { + /* + * Close the old log file and open the new one. + */ + if (www_log_fp != 0) { + fclose(www_log_fp); + } + + www_log_fp = fopen(www_log_filename, "r"); + if (www_log_fp != 0) { + fstat(fileno(www_log_fp), www_log_stat); + www_log_ino = www_log_stat[0].st_ino; + www_log_size = www_log_stat[0].st_size; + buf[BUFSIZ-1] = 127; + while(fgets(buf, BUFSIZ, www_log_fp) != nil) { + httpops += 1.0; + if (www_gatelen > 0) { + if (strncmp(buf, www_gateway, www_gatelen) == 0) { + gateops += 1.0; + } + } + accesslog(buf); + + /* + * If the line is longer than the buffer, then ignore + * the rest of the line. + */ + while (buf[BUFSIZ-1] == 0 && + buf[BUFSIZ-2] != '\n') { + buf[BUFSIZ-1] = 127; + if (fgets(buf, BUFSIZ, www_log_fp) == nil) { + break; + } + } + } + } else { + www_log_ino = 0; + www_log_size = 0; + } + } else { + /* + * Remember size for next time. + */ + www_log_size = www_log_stat[0].st_size; + } + } + + www5_now = gethrtime(); + www5_interval = (www5_now - www5_then) * 0.000000001; + www5_then = www5_now; + dtmp = (httpops - lastops)/www5_interval; + if (dtmp > httpops5) { + httpops5 = dtmp; + } + lastops = httpops; + } + } + else { + sleep_till_and_count_new_processes(sleep_till); + www5_now = gethrtime(); + } + + www_now = www5_now; + www_interval = (www_now - www_then) * 0.000000001; + www_then = www_now; + + /* + * Use dtmp to get percentages. + */ + if (httpops == 0.0) { + dtmp = 0.0; + } + else { + dtmp = 100.0 / httpops; + } + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + for (i=0; i<5; ++i) { + if (dwnld_size[i] == 0) { + www_dwnld_time_by_size[i] = 0.0; + } + else { + www_dwnld_time_by_size[i] = www_dwnld_time_by_size[i]/dwnld_size[i]; + } + } +#endif +} + +// Functions in SE cannot return an array, so to work around this, have +// count_procs place it's results in a global array. +#define MAX_COUNT_PROC_REGEXS 2 +int count_procs_results[MAX_COUNT_PROC_REGEXS]; +count_procs(int number_regexs, string regexs[]) +{ + psinfo_t p; + int i; + + if (number_regexs > MAX_COUNT_PROC_REGEXS) { + fprintf(stderr, "%s: too many regular expressions (%d). Increase MAX_COUNT_PROC_REGEXS.\n", + program_name, number_regexs); + exit(1); + } + + for (i=0; i +#include +#include +#include +#include +#include +#include +#include +#include + +#define PATH_TO_INST "/etc/path_to_inst" + +// sterr is not defined in kstat.se, so define here +kstat struct "sterr:" ks_sterr { + int number$; // linear counter + string name$; // name of error + int instance$; // instance number + + uint64_t "Soft Errors"; + uint64_t "Hard Errors"; + uint64_t "Transport Errors"; + string Vendor; + string Product; + string Revision; + string "Serial No"; +}; + +struct tape_info_t { + string short_name; + string long_name; + ks_sterr errors; +}; + +// this is a global array to keep similarity with diskinfo.se +// use functions provided below as access methods + +tape_info_t GLOBAL_tape_info[]; +int GLOBAL_tapeinfo_size = 1; +ulong_t GLOBAL_tapeinfo_short_tree; +ulong_t GLOBAL_tapeinfo_long_tree; + +int tapeinfo_inst_initialized; // set when data exists + +ks_sterr +find_tape_error(string name) +{ + ks_sterr sterr; + string short_name; + + if (name =~ "^st.*") { + sterr.number$ = 0; + for(refresh$(sterr); sterr.number$ != -1; sterr.number$++,refresh$(sterr)) { + short_name = sterr.name$; + strtok(short_name, ","); + if (short_name == name) { + break; + } + } + return sterr; + } +} + +int +setup_tapeinfo_inst() // return 1 if OK, 0 if not +{ + char buf[BUFSIZ]; + char points_at[MAXNAMELEN]; + string p; + string full; + string path; + string tape_dirs[2] = { "/dev/rmt", nil }; + int count = 0; + int i; + int n; + ulong ld; + ulong dirp; + ulong input; + dirent_t dp; + ulong_t path_tree; + ulong_t np; + + if (tapeinfo_inst_initialized == 1) { + return 1; + } + + path_tree = str2int_init(); + if (path_tree == 0) { + return 0; + } + + // load up the tree with the paths and quit traversing path_to_inst + input = fopen(PATH_TO_INST, "r"); + if (input == 0) { + avlfree(path_tree); + return 0; + } + while (fgets(buf, sizeof(buf), input) != nil) { + if ((buf[0] != '#') && (buf[0] != '\n')) { + p = strtok(buf, " "); + n = atoi(strtok(nil, " ")); + path = strtok(p, "\""); + + if (str2int_put(path_tree, path, n) == -1) { + fclose(input); + avlfree(path_tree); + return 0; + } + } + } + fclose(input); + + // create the global tape info array + GLOBAL_tape_info = new tape_info_t[GLOBAL_tapeinfo_size]; + + // scan /dev/rmt and insert tape entries + for (i=0; tape_dirs[i] != nil; i++) { + dirp = opendir(tape_dirs[i]); + if (dirp == 0) { + if (i > 0) { + // first is /dev/rmt + break; + } + avlfree(path_tree); + return 0; + } + + for (ld = readdir(dirp); ld != 0; ld = readdir(dirp)) { + // grow the array if needed + if (count == GLOBAL_tapeinfo_size) { + GLOBAL_tapeinfo_size += 1; + GLOBAL_tape_info = renew GLOBAL_tape_info[GLOBAL_tapeinfo_size]; + } + dp = *((dirent_t *) ld); + + // skip . and .. + if (dp.d_name == "." || dp.d_name == "..") { + continue; + } + + // skip everything but raw devices + if ( isdigit(dp.d_name[strlen(dp.d_name)-1]) == 0 ) { + continue; + } + + // read the link + full = sprintf("%s/%s", tape_dirs[i], dp.d_name); + + n = readlink(full, points_at, sizeof(points_at)); + if (n == -1) { + closedir(dirp); + avlfree(path_tree); + return 0; + } + points_at[n] = '\0'; + + // chop off the :a at the end + strcpy(strrchr(points_at, ':'), ""); + + // hack off ../../devices from the start + sscanf(points_at, "../../devices%s", &points_at); + + // hack off /dev/ from the start + // long name is the rmt/ + sscanf(full, "/dev/%s", &buf); + GLOBAL_tape_info[count].long_name = buf; + + GLOBAL_tape_info[count].short_name = nil; + + // construct the short name + if ((np = str2int_get(path_tree, points_at)) != 0) { + n = ((int) *((ulong_t *) np)); + p = strrchr(points_at, '/'); + p = strtok(p, "/"); + p = strtok(p, "@"); + GLOBAL_tape_info[count].short_name = sprintf("%s%d", p, n); + } + + // hard luck, can't find this device + if (GLOBAL_tape_info[count].short_name == nil) { + continue; + } + + // squirrel this away while we're at it + GLOBAL_tape_info[count].errors = + find_tape_error(GLOBAL_tape_info[count].short_name); + + count++; + } + closedir(dirp); + } + + // tree the names for fast lookup + GLOBAL_tapeinfo_short_tree = str2int_init(); + GLOBAL_tapeinfo_long_tree = str2int_init(); + if ((GLOBAL_tapeinfo_short_tree == 0) || (GLOBAL_tapeinfo_long_tree == 0)) { + return 0; + } + for(i=0; i= 0 && i < GLOBAL_tapeinfo_size) { + return GLOBAL_tape_info[i]; + } else { + no_info.short_name = name; + no_info.long_name = name; + return no_info; + } +} + +#endif From blair at orcaware.com Fri Sep 10 10:00:52 2004 From: blair at orcaware.com (Blair Zajac) Date: Fri, 10 Sep 2004 10:00:52 -0700 Subject: [Orca-checkins] r387 - trunk/orca Message-ID: <200409101700.i8AH0qCf026035@gw.orcaware.com> Author: blair Date: Fri Sep 10 09:58:43 2004 New Revision: 387 Modified: trunk/orca/COMMITTERS Log: * COMMITTERS: Add Dmitry Berezin to the list of committers. Modified: trunk/orca/COMMITTERS ============================================================================== --- trunk/orca/COMMITTERS (original) +++ trunk/orca/COMMITTERS Fri Sep 10 09:58:43 2004 @@ -8,4 +8,5 @@ directly. Blanket commit access: - blair Blair Zajac + blair at orcaware.com Blair Zajac + dmberezin at hotmail.com Dmitry Berezin From dmberezin at hotmail.com Fri Sep 10 10:43:36 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Fri, 10 Sep 2004 10:43:36 -0700 Subject: [Orca-checkins] r388 - in trunk/orca: data_gatherers/orcallator lib/SE/3.3.1 Message-ID: <200409101743.i8AHhaSB027252@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Fri Sep 10 10:41:38 2004 New Revision: 388 Modified: trunk/orca/data_gatherers/orcallator/orcallator.se trunk/orca/lib/SE/3.3.1/tapeinfo.se Log: Removed data fixing in orca_io_info_update. Should not occur with the current versions of Solaris and SE. Will re-add if problem re-occurs Removed temporary variables in orca_io_info_update - calculate using kio.xxxx Simplified orca_io_info_update further Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Fri Sep 10 10:41:38 2004 @@ -1,2210 +1,2164 @@ -// -// Orcallator.se, a log generating performance monitor. -// -// This program logs many different system quantities to a log file -// for later processing. -// -// Author: Blair Zajac . -// -// Portions copied from percollator.se written by Adrian Cockroft. -// -// $HeadURL$ -// $LastChangedDate$ -// $LastChangedBy$ -// $LastChangedRevision$ -// -// Revision history for this file can be retrieved by running svn log -// on the HeadURL listed above. -// - -// The default sampling interval in seconds. -#define SAMPLE_INTERVAL 300 - -// The maximum number of columns of data. -#define MAX_COLUMNS 2048 - -// Enable kstat io measuring code. -#define USE_KSTAT_IO 1 - -// If WATCH_OS is defined, then measure every part of the operating -// system. -#ifdef WATCH_OS -#define WATCH_CPU 1 -#define WATCH_MUTEX 1 -#define WATCH_NET 1 -#define WATCH_TCP 1 -#define WATCH_NFS_CLIENT 1 -#define WATCH_NFS_SERVER 1 -#define WATCH_MOUNTS 1 -#define WATCH_DISK 1 -#define WATCH_DNLC 1 -#define WATCH_INODE 1 -#define WATCH_RAM 1 -#define WATCH_PAGES 1 -#endif - -// Keep backwards compatibility with WATCH_HTTPD. -#ifdef WATCH_HTTPD -#define WATCH_WEB 1 -#endif - -// Keep backwards compatibility with WATCH_NFS. -#ifdef WATCH_NFS -#ifndef WATCH_NFS_CLIENT -#define WATCH_NFS_CLIENT 1 -#endif -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -//#include -#include -//#include -#include -#include -#include -#include -#include -#include - -#ifdef WATCH_MOUNTS -#include -#include -#endif - -#if WATCH_CPU || WATCH_WEB -#include - -#ifdef WATCH_CPU -// This is the maximum pid on Solaris hosts. -#define DEFAULT_MAXPID 30000 -#include -#endif - -#ifdef WATCH_WEB - -// Define this macro which returns the size index for a file of a -// particular size. This saves the overhead of a function call. -#define WWW_SIZE_INDEX(size, size_index) \ - if (size < 1024) { \ - size_index=0; /* Under 1KB */ \ - } else { \ - if (size < 10240) { \ - size_index=1; /* Under 10K */ \ - } else { \ - if (size < 102400) { \ - size_index=2; /* Under 100KB */ \ - } else { \ - if (size < 1048576) { \ - size_index=3; /* Under 1MB */ \ - } else { \ - size_index=4; /* Over 1MB */ \ - } \ - } \ - } \ - } \ - dwnld_size[size_index]++; - -// Handle the reply code from the server. -#define WWW_REPLY_CODE(word) \ - if (word == "304") { \ - httpop_condgets++; \ - } \ - else { \ - first_byte = word; \ - if (first_byte[0] == '4' || first_byte[0] == '5') { \ - httpop_errors++; \ - } \ - } \ - -// Handle the method of the object served. This define only works -// with non-proxy servers. -#define WWW_METHOD1(word) \ - switch (word) { \ - case "get": \ - case "GET": \ - httpop_gets++; \ - break; \ - case "post": \ - case "POST": \ - httpop_posts++; \ - break; \ - case "head": \ - case "HEAD": \ - ishead = 1; \ - httpop_condgets++; \ - break; - -#ifdef WATCH_SQUID -#define WWW_METHOD2 \ - case "icp_query": \ - case "ICP_QUERY": \ - squid_icp_queries++; \ - break; -#else -#define WWW_METHOD2 -#endif - -#define WWW_METHOD_END \ - default: \ - break; \ - } -#define WWW_METHOD(word) WWW_METHOD1(word) WWW_METHOD2 WWW_METHOD_END -#endif -#endif - -// Put all rules here so they can be accessed by the handle functions. -lr_cpu_t lr_cpu$cpu; -lr_cpu_t tmp_lr_cpu; -lr_mutex_t lr_mutex$m; -lr_mutex_t tmp_lr_mutex; -lr_net_t lr_net$nr; -lr_net_t tmp_lr_net; -lr_tcp_t lr_tcp$tcp; -lr_tcp_t tmp_lr_tcp; -lr_rpcclient_t lr_rpcclient$r; -lr_rpcclient_t tmp_lr_rpcclient; -lr_disk_t lr_disk$dr; -lr_disk_t tmp_lr_disk; -lr_dnlc_t lr_dnlc$dnlc; -lr_dnlc_t tmp_lr_dnlc; -lr_inode_t lr_inode$inode; -lr_inode_t tmp_lr_inode; -lr_ram_t lr_ram$ram; -lr_ram_t tmp_lr_ram; -lr_swapspace_t lr_swapspace$s; -lr_swapspace_t tmp_lr_swapspace; -lr_kmem_t lr_kmem$kmem; -lr_kmem_t tmp_lr_kmem; - -ks_system_misc kstat$misc; -ks_system_misc tmp_kstat_misc; -#ifdef WATCH_TCP -tcp tcp$tcp; -tcp tmp_tcp; -#endif -#ifdef WATCH_PAGES -ks_system_pages kstat$pages; -ks_system_pages tmp_kstat_pages; -#endif - -// Put application globals here. -string nodename; // Name of this machine. -string program_name; // Name of this program. -int hz; // Clock tick rate. -int page_size; // Page size in bytes. -long boot_time; // Boot time of the system. -long interval = SAMPLE_INTERVAL; // Sampling interval. - -#ifdef WATCH_CPU -int can_read_kernel = 0; // If the kernel can be read. -int kvm$mpid; // The last created PID. - -// These variables store the mpid before and after the standard interval. -int mpid_previous; -int mpid_current; -ulonglong mpid_then; -ulonglong mpid_now; - -// These variables store the mpid before and after 5 second intervals. -int mpid5_previous; -int mpid5_current; -ulonglong mpid5_then; -ulonglong mpid5_now; -double mpid5_rate; -#endif - -#ifdef WATCH_MOUNTS -mnttab_t mnt$mnt; -mnttab_t tmp_mnt; -#endif - -#ifdef WATCH_NFS_SERVER -ks_nfs_server kstat$nfs; -ks_nfs_server tmp_nfs; -ks_rfs_proc_v2 kstat$rfsproccnt_v2; -ks_rfs_proc_v2 tmp_rfsproccnt_v2; -ks_rfs_proc_v3 kstat$rfsproccnt_v3; -ks_rfs_proc_v3 tmp_rfsproccnt_v3; -#endif - -// Variables for handling the httpd access log. -#ifdef WATCH_WEB -string www_search_url = getenv("SEARCHURL"); -string www_server_proc_name = getenv("WEB_SERVER"); -string www_server_secure_proc_name = getenv("WEB_SERVER_SECURE"); -string www_log_filename = getenv("WEB_LOG"); -string www_gateway = getenv("GATEWAY"); -ulong www_log_fp; -uint www_gatelen; -stat_t www_log_stat[1]; -ulong www_log_ino; -long www_log_size; - -double www_interval; // Hi-res interval time. -ulonglong www_then; -ulonglong www_now; - -double www5_interval; // Actual hi-res 5 second interval. -ulonglong www5_then; -ulonglong www5_now; - -double httpops; -double httpops5; -double gateops; -double dtmp; - -long httpop_gets; -long httpop_condgets; // HEAD or code = 304 conditional get no data. -long httpop_posts; -long httpop_cgi_bins; -long httpop_searches; -long httpop_errors; -long dwnld_size[5]; // [0] < 1K, [1] < 10K, [2] < 100K, [3] < 1M, [4] >= 1M -long dwnld_totalz; // Total size counted from log. - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO -// If we're watching a Yahoo log, then take the transfer time to be the -// processing time. -double www_dwnld_time_sum; // Transfer time. -double www_dwnld_time_by_size[5]; // Mean transfer time by size bin. -#endif -#if WATCH_PROXY || WATCH_SQUID -long prxy_squid_indirect; // # hits that go via PROXY,SOCKS,parent -long prxy_squid_cache_hits; // # hits returned from cache. -#endif - -#ifdef WATCH_PROXY -long prxy_cache_writes; // Number of writes and updates to cache. -long prxy_uncacheable; // Number of explicitly uncacheable httpops. - // Any extra is errors or incomplete ops. -#endif - -#ifdef WATCH_SQUID -long squid_cache_misses; -long squid_icp_requests; -long squid_icp_queries; -long squid_client_http; -#endif - -#endif - -#ifdef USE_KSTAT_IO -#include -#include -// This code was developed so that the performance of virtual disks -// originating from a Sun A1000 raid controller could be monitored. -// These disks do not show up in the GLOBAL_disk[] io structure of SE. -// -// This extension accesses the sys_kstat.se interface to the kstat IO -// queues to extract info on drives not available in the kstat.se -// kstat$disk interface. Global data shared between function calls. -struct io_dev_info_t { - // Exposed interface that matches kstat. - string long_name; - string short_name; - double reads; - double kreads; - double writes; - double kwrites; - double avg_wait; - double avg_serv; - double service; - double wait_percent; - double run_percent; - - // Hidden internal registers to track sys_kstats counters. - int _number; // kstat disk # - ulonglong _nread; // Number of bytes read - ulonglong _nwritten; // Number of bytes written - uint _reads; // Number of read operations - uint _writes; // Number of write operations - longlong _wtime; // Cumulative wait (pre-service) time - longlong _wlentime; // Cumulative wait length*time product - longlong _wlastupdate; // Last time wait queue changed - longlong _rtime; // Cumulative run (service) time - longlong _rlentime; // Cumulative run length*time product - longlong _rlastupdate; // Last time run queue changed - uint _wcnt; // Count of elements in wait state - uint _rcnt; // Count of elements in run state -}; - -// Define global for tracking raw disk data. -io_dev_info_t ORCA_io_dev_info[]; -int ORCA_io_dev_count=0; -int ORCA_max_io_dev_count=0; - -orca_io_info_update() { - int iodev; - int index; - ulong ul; - kstat_ctl_t kc[1]; - kstat_t kp[1]; - kstat_t nkp[1]; - kstat_io_t kio; - ulonglong _nread; - ulonglong _nwritten; - uint _reads; - uint _writes; - longlong _wtime; - longlong _wlentime; - longlong _wlastupdate; - longlong _rtime; - longlong _rlentime; - longlong _rlastupdate; - longlong _wcnt; - longlong _rcnt; - - double read_writes; - double big_etime; - double elapsed_etime; - double hz_etime; - double nanosecond = NANOSEC; - - kc[0] = kstat_open(); - // Read them. - if (kstat_read(kc, kp, 0) == -1) { - perror("orca_io_info_update:kstat_read"); - exit(1); - } - - // Traverse the chain looking for IO events. - for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { - struct_fill(nkp[0], ul); - if (nkp[0].ks_type == KSTAT_TYPE_IO) { - // Look for disk or tape statistics - if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { - // Try to locate device. - for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { - if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { - break; - } - } - - // It must be new. Add it! - if (iodev == ORCA_io_dev_count) { - // Grow the device array if needed - if (ORCA_io_dev_count == ORCA_max_io_dev_count) { - ORCA_max_io_dev_count += 10; - ORCA_io_dev_info = renew ORCA_io_dev_info[ORCA_max_io_dev_count]; - } - - if (nkp[0].ks_class == "tape") { - index = find_tape_inst(nkp[0].ks_name); - } else { - index = find_inst(nkp[0].ks_name); - } - if (index != -1) { - if (nkp[0].ks_class == "tape") { - ORCA_io_dev_info[iodev].long_name = GLOBAL_tape_info[index].long_name; - } else { - ORCA_io_dev_info[iodev].long_name = GLOBAL_disk_info[index].long_name; - } - } else { - ORCA_io_dev_info[iodev].long_name = nkp[0].ks_name; - } - ORCA_io_dev_info[iodev].short_name = nkp[0].ks_name; - - ORCA_io_dev_info[iodev]._reads = 0; - ORCA_io_dev_info[iodev]._nread = 0; - ORCA_io_dev_info[iodev]._rlentime = 0; - ORCA_io_dev_info[iodev]._rlastupdate = boot_time; - ORCA_io_dev_info[iodev]._rcnt = 0; - ORCA_io_dev_info[iodev]._writes = 0; - ORCA_io_dev_info[iodev]._nwritten = 0; - ORCA_io_dev_info[iodev]._wlentime = 0; - ORCA_io_dev_info[iodev]._wlastupdate = boot_time; - ORCA_io_dev_info[iodev]._wcnt = 0; - ORCA_io_dev_count++; - } - - // Update the device registers. - if (kstat_read(kc, nkp, 0) == -1) { - perror("orca_io_info_update:kstat_read error"); - exit(1); - } else { - // Read sys_kstat device IO queue to find out about recent - // activity. We validate data that is returned. Solaris - // 2.6 has occasional glitches when updating certain disks - // (c0t0d0) so we cover up the glitches by using data from - // the previous cycle. Eventually, we will get a good - // update. Fixing the data is not necessarily the best - // choice. Currently only kio.nread glitches. Correcting - // the error forces the IOs to get attributed to the next IO - // cycle. - struct_fill(kio, nkp[0].ks_data); - - _nread = kio.nread; - if (ORCA_io_dev_info[iodev]._nread > _nread) { - _nread = ORCA_io_dev_info[iodev]._nread; - } - _reads = kio.reads; - if (ORCA_io_dev_info[iodev]._reads > _reads) { - _reads = ORCA_io_dev_info[iodev]._reads; - } - _rlentime = kio.rlentime; - _rtime = kio.rtime; - _rlastupdate = kio.wlastupdate; - _rcnt = kio.rcnt; - _nwritten = kio.nwritten; - if (ORCA_io_dev_info[iodev]._nwritten > _nwritten) { - _nwritten = ORCA_io_dev_info[iodev]._nwritten; - } - _writes = kio.writes; - if (ORCA_io_dev_info[iodev]._writes > _writes) { - _writes = ORCA_io_dev_info[iodev]._nwritten; - } - _wlentime = kio.wlentime; - _wtime = kio.wtime; - _wlastupdate = kio.wlastupdate; - _wcnt = kio.wcnt; - - elapsed_etime = (_wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); - if (elapsed_etime > 0) { - hz_etime = elapsed_etime / nanosecond; - big_etime = 1024.0 * hz_etime; - } else { - elapsed_etime = nanosecond; - hz_etime = 1.0; - big_etime = 1024.0; - } - ORCA_io_dev_info[iodev].reads =(_reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; - ORCA_io_dev_info[iodev].kreads =(_nread-ORCA_io_dev_info[iodev]._nread) /big_etime; - ORCA_io_dev_info[iodev].writes =(_writes-ORCA_io_dev_info[iodev]._writes)/hz_etime; - ORCA_io_dev_info[iodev].kwrites=(_nwritten-ORCA_io_dev_info[iodev]._nwritten) / big_etime; - - read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; - if (read_writes > 0) { - ORCA_io_dev_info[iodev].avg_wait = (_wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; - ORCA_io_dev_info[iodev].avg_serv = (_rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; - ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; - } else { - ORCA_io_dev_info[iodev].avg_wait = 0.0; - ORCA_io_dev_info[iodev].avg_serv = 0.0; - ORCA_io_dev_info[iodev].service = 0.0; - } - - // Update the counters. - ORCA_io_dev_info[iodev].run_percent = 100.0 * (_rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; - ORCA_io_dev_info[iodev].wait_percent = 100.0 * (_wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; - ORCA_io_dev_info[iodev]._writes = _writes; - ORCA_io_dev_info[iodev]._nwritten = _nwritten; - ORCA_io_dev_info[iodev]._wlastupdate = _wlastupdate; - ORCA_io_dev_info[iodev]._wlentime = _wlentime; - ORCA_io_dev_info[iodev]._wtime = _wtime; - ORCA_io_dev_info[iodev]._wcnt = _wcnt; - ORCA_io_dev_info[iodev]._reads = _reads; - ORCA_io_dev_info[iodev]._nread = _nread; - ORCA_io_dev_info[iodev]._rlastupdate = _rlastupdate; - ORCA_io_dev_info[iodev]._rlentime = _rlentime; - ORCA_io_dev_info[iodev]._rtime = _rtime; - ORCA_io_dev_info[iodev]._rcnt = _rcnt; - } - } - } - } - kstat_close(kc); -} -#endif // USE_KSTAT_IO - -// Variables for handling output. -string compress = getenv("COMPRESSOR"); // How to compress logs. -ulong out_log_fp; // File pointer to the logging file. -string col_comment[MAX_COLUMNS]; // Comments for each column. -string col_data[MAX_COLUMNS]; // Data for each column. -string col_previous_comment[MAX_COLUMNS]; // Previous comments. -int current_column = 0; // The current column. -int previous_number_columns = -1; // Number columns printed last. -int print_header = 1; // Flag to flush header. - -// This is a list of the extensions the compress programs add to the -// compress filename. -#define NUMBER_COMPRESS_SUFFIXES 3 -string compression_suffixes[NUMBER_COMPRESS_SUFFIXES] = {".Z", - ".gz", - ".bz2"}; - -// Add one column of comments and data to the buffers. -put_output(string comment, string data) -{ - if (current_column >= MAX_COLUMNS) { - fprintf(stderr, "%s: too many columns (%d). Increase MAX_COLUMNS.\n", - program_name, current_column); - exit(1); - } - - col_comment[current_column] = comment; - col_data[current_column] = data; - current_column++; -} - -// Send the stored columns of information to the output. -print_columns(string data[]) -{ - int i; - for (i=0; i 0) { - usleep(1000000*time_to_sleep - now[0].tv_usec); - gettimeofday(now, 0); - time_to_sleep = sleep_till - now[0].tv_sec; - } -} - -sleep_till_and_count_new_processes(long sleep_till) -{ - long now; -#ifdef WATCH_CPU - int mpid5_diff; - double mpid5_interval; - double rate; -#endif - - now = time(0); - while (now < sleep_till) { -#ifdef WATCH_CPU - if (can_read_kernel != 0) { - // Sleep for 5 seconds to make a measurement or less to stay - // within the sleep_till limit. - if (now + 5 < sleep_till) { - orca_sleep_till(now + 5); - } else { - orca_sleep_till(sleep_till); - } - - // Measure the 5 second process creation rate. - mpid5_current = kvm$mpid; - mpid5_now = gethrtime(); - mpid5_interval = (mpid5_now - mpid5_then) * 0.000000001; - mpid5_then = mpid5_now; - if (mpid5_current >= mpid5_previous) { - mpid5_diff = mpid5_current - mpid5_previous; - } - else { - mpid5_diff = mpid5_current + DEFAULT_MAXPID - mpid5_previous; - } - rate = mpid5_diff/mpid5_interval; - if (rate > mpid5_rate) { - mpid5_rate = rate; - } - mpid5_previous = mpid5_current; - - // Now take these results to measure the long interval rate. - // Because the mpid may flip over DEFAULT_MAXPID more than once - // in the long interval time span, use the difference between - // the previous and current mpid over a 5 second interval to - // calculate the long interval difference. - mpid_current += mpid5_diff; - mpid_now = mpid5_now; - } - else { - orca_sleep_till(sleep_till); - } -#else - orca_sleep_till(sleep_till); -#endif - now = time(0); - } -} - -#ifdef WATCH_CPU -measure_cpu() -{ - p_vmstat pvm; - double mpid_interval; - double mpid_rate; - - pvm = vmglobal_total(); - - // In SE 3.0 and below user_time and system_time are int and in SE - // 3.1 and above they are double, so cast everything to double using - // + 0.0. - put_output(" usr%", sprintf("%5.1f", pvm.user_time + 0.0)); - put_output(" sys%", sprintf("%5.1f", pvm.system_time + 0.0)); - put_output(" wio%", sprintf("%5.1f", pvm.wait_time + 0.0)); - put_output("idle%", sprintf("%5.1f", pvm.idle_time + 0.0)); - put_output(" 1runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_1min/256.0)); - put_output(" 5runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_5min/256.0)); - put_output("15runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_15min/256.0)); - put_output("#proc", sprintf("%5lu", tmp_kstat_misc.nproc)); - put_output(" #runque", sprintf("%8.2f", pvm.runque + 0.0)); - put_output("#waiting", sprintf("%8.2f", pvm.waiting + 0.0)); - put_output(" #swpque", sprintf("%8.2f", pvm.swpque + 0.0)); - put_output("scanrate", sprintf("%8.3f", pvm.scan + 0.0)); - put_output("pgrec/s", sprintf("%8.3f", pvm.pgrec + 0.0)); - put_output("pgfrec/s", sprintf("%8.3f", pvm.pgfrec + 0.0)); - put_output("pgin/s", sprintf("%8.3f", pvm.pgin + 0.0)); - put_output("pages_in/s", sprintf("%8.3f", pvm.pages_in + 0.0)); - put_output("pgout/s", sprintf("%8.3f", pvm.pgout + 0.0)); - put_output("pages_out/s", sprintf("%8.3f", pvm.pages_out + 0.0)); - put_output("dfree/s", sprintf("%8.3f", pvm.dfree + 0.0)); - put_output("min_fault/s", sprintf("%8.3f", pvm.hat_fault + pvm.as_fault + 0.0)) -; - put_output("maj_fault/s", sprintf("%8.3f", pvm.maj_fault + 0.0)); - put_output("prot_fault/s", sprintf("%8.3f", pvm.prot_fault + 0.0)); - put_output("cow_fault/s", sprintf("%8.3f", pvm.cow_fault + 0.0)); - put_output("zfod/s", sprintf("%8.3f", pvm.zfod + 0.0)); - put_output("interrupts/s", sprintf("%8.3f", pvm.interrupts + 0.0)); - put_output("intrthread/s", sprintf("%8.3f", pvm.intrthread + 0.0)); - put_output("system_calls/s", sprintf("%8.3f", pvm.system_calls + 0.0)); - put_output("context_switches/s", sprintf("%8.3f", pvm.context_switches + 0.0)); - put_output("invol_switches/s", sprintf("%8.3f", pvm.invol_switches + 0.0)); - put_output("traps/s", sprintf("%8.3f", pvm.trap + 0.0)); - put_output("forks/s", sprintf("%8.3f", pvm.sysfork + 0.0)); - put_output("vforks/s", sprintf("%8.3f", pvm.sysvfork + 0.0)); - put_output("execs/s", sprintf("%8.3f", pvm.sysexec + 0.0)); - put_output("namei/s", sprintf("%8.3f", pvm.namei + 0.0)); - put_output("ufsiget/s", sprintf("%8.3f", pvm.ufsiget + 0.0)); - put_output("ufsdirblk/s", sprintf("%8.3f", pvm.ufsdirblk + 0.0)); - - // Calculate the rate of new process spawning. - if (can_read_kernel != 0) { - mpid_interval = (mpid_now - mpid_then) * 0.000000001; - mpid_rate = (mpid_current - mpid_previous) / mpid_interval; - put_output("#proc/s", sprintf("%7.3f", mpid_rate)); - put_output("#proc/p5s", sprintf("%9.4f", mpid5_rate)); - - // Reset counters. - mpid_then = mpid_now; - mpid_previous = mpid_current; - mpid5_rate = 0; - } -} -#endif - -#ifdef WATCH_MUTEX -measure_mutex() -{ - put_output(" smtx", sprintf("%5d", tmp_lr_mutex.smtx)); - put_output("smtx/cpu", sprintf("%8d", tmp_lr_mutex.smtx/GLOBAL_pvm_ncpus)); -} -#endif - -#ifdef WATCH_NET -measure_net() -{ - int previous_count = -1; - int current_count; - int i; - - current_count = 0; - for (i=0; i. Check - // [wr]lentime to see if an EMC is using a fake disk for control. - // EMC disks have a fake disk which commands are run over to - // configure the disk array or to get stats from; they are not - // real data transfers. They cause 1000 MB/sec writes to appear - // in the stats. I still get them but not as often with this bit - // of code in. If the I/O which occurred in the last five minutes - // is not greater than 1/100sec then it is not a valid measurement - // anyway. What happens is that we can have a small I/O, say 1024 - // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making - // it wlentime+rlentime>2 since I am still getting fake write - // spikes. -#ifdef HAVE_EMC_DISK_CONTROL - if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { -#endif - total_disk_reads += ORCA_io_dev_info[i].reads; - total_disk_writes += ORCA_io_dev_info[i].writes; - total_disk_readk += ORCA_io_dev_info[i].kreads; - total_disk_writek += ORCA_io_dev_info[i].kwrites; - mean_disk_busy += ORCA_io_dev_info[i].run_percent; - if (ORCA_io_dev_info[i].run_percent > peak_disk_busy) { - peak_disk_busy = ORCA_io_dev_info[i].run_percent; - } -#ifdef HAVE_EMC_DISK_CONTROL - } -#endif - } -#else - for (i=0; i. Check - // [wr]lentime to see if an EMC is using a fake disk for control. - // EMC disks have a fake disk which commands are run over to - // configure the disk array or to get stats from; they are not - // real data transfers. They cause 1000 MB/sec writes to appear - // in the stats. I still get them but not as often with this bit - // of code in. If the I/O which occurred in the last five minutes - // is not greater than 1/100sec then it is not a valid measurement - // anyway. What happens is that we can have a small I/O, say 1024 - // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making - // it wlentime+rlentime>2 since I am still getting fake write - // spikes. -#ifdef HAVE_EMC_DISK_CONTROL - if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { -#endif - total_disk_reads += GLOBAL_disk[i].reads; - total_disk_writes += GLOBAL_disk[i].writes; - total_disk_readk += GLOBAL_disk[i].kreads; - total_disk_writek += GLOBAL_disk[i].kwrites; - mean_disk_busy += GLOBAL_disk[i].run_percent; - if (GLOBAL_disk[i].run_percent > peak_disk_busy) { - peak_disk_busy = GLOBAL_disk[i].run_percent; - } -#ifdef HAVE_EMC_DISK_CONTROL - } -#endif - } -#endif - - if (disk_count != 0) { - mean_disk_busy = mean_disk_busy/disk_count; - } - - put_output("disk_peak", sprintf("%9.3f", peak_disk_busy)); - put_output("disk_mean", sprintf("%9.3f", mean_disk_busy)); - put_output("disk_rd/s", sprintf("%9.1f", total_disk_reads)); - put_output("disk_wr/s", sprintf("%9.1f", total_disk_writes)); - put_output("disk_rK/s", sprintf("%9.1f", total_disk_readk)); - put_output("disk_wK/s", sprintf("%9.1f", total_disk_writek)); - - put_output("tape_rd/s", sprintf("%9.1f", total_tape_reads)); - put_output("tape_wr/s", sprintf("%9.1f", total_tape_writes)); - put_output("tape_rK/s", sprintf("%9.1f", total_tape_readk)); - put_output("tape_wK/s", sprintf("%9.1f", total_tape_writek)); - - // If the number of disks and/or tapes has changed, say due to a - // add_drv, then print new headers. - if (previous_disk_count != disk_count) { - print_header = 1; - previous_disk_count = disk_count; - } - if (previous_tape_count != tape_count) { - print_header = 1; - previous_tape_count = tape_count; - } -} -#endif - -#ifdef WATCH_DNLC -measure_dnlc() -{ - put_output("dnlc_ref/s", sprintf("%10.3f", tmp_lr_dnlc.refrate)); - put_output("dnlc_hit%", sprintf("%9.3f", tmp_lr_dnlc.hitrate)); -} -#endif - -#ifdef WATCH_INODE -measure_inode() -{ - p_vmstat pvm; - - put_output("inod_ref/s", sprintf("%10.3f", tmp_lr_inode.refrate)); - put_output("inod_hit%", sprintf("%9.3f", tmp_lr_inode.hitrate)); - put_output("inod_stl/s", sprintf("%10.3f", tmp_lr_inode.iprate)); - put_output("ufsinopage/s", sprintf("%8.3f", pvm.ufsinopage + 0.0)); - -} -#endif - -#ifdef WATCH_RAM -measure_ram() -{ - put_output("swap_avail", sprintf("%10ld", GLOBAL_pvm[0].swap_avail)); - put_output("page_rstim", sprintf("%10d", tmp_lr_ram.restime)); - put_output(" freememK", sprintf("%10d", GLOBAL_pvm[0].freemem)); - put_output("free_pages", sprintf("%10d", (GLOBAL_pvm[0].freemem*1024)/page_size)); -} -#endif - -#ifdef WATCH_PAGES -measure_pages() -{ - put_output("pp_kernel", sprintf("%9lu", tmp_kstat_pages.pp_kernel)); - put_output("pagesfree", sprintf("%9lu", tmp_kstat_pages.pagesfree)); - put_output("pageslock", sprintf("%9lu", tmp_kstat_pages.pageslocked)); -#if MINOR_VERSION < 80 - put_output("pagesio", sprintf("%7lu", tmp_kstat_pages.pagesio)); -#endif - put_output("pagestotl", sprintf("%9lu", tmp_kstat_pages.pagestotal)); -} -#endif - -#ifdef WATCH_WEB -/* - * Breakdown access log format. - */ -accesslog(string buf) { - int z; - int size_index; - int ishead; - string word; - char first_byte[1]; - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - double xf; -#ifdef WATCH_SQUID - string logtag; - string request; -#endif -#ifdef WATCH_YAHOO - string arg; - ulong ptr; - ulong tmp; - ulong ulong_xf; -#endif -#endif - - ishead = 0; -#ifdef WATCH_YAHOO - /* - * Make sure that the input line has at least 32 bytes of data plus a new - * line, for a total length of 33. - */ - if (strlen(buf) < 33) { - return; - } - word = strtok(buf, "\05"); -#else - word = strtok(buf, " "); -#endif - if (word == nil) { - return; - } - -#ifdef WATCH_SQUID - /* - * Word contains unix time in seconds.milliseconds. - */ - word = strtok(nil, " "); - if (word == nil) { - return; - } - xf = atof(word)/1000.0; - www_dwnld_time_sum += xf; -#ifdef DINKY - printf("time: %s %f total %f\n", word, xf, xfer_sum); -#endif - word = strtok(nil, " "); /* Client IP address. */ - logtag = strtok(nil, "/"); /* Log tag. */ - if (logtag == nil) { - return; - } - if (logtag =~ "TCP") { - squid_client_http++; - } - if (logtag =~ "UDP") { - squid_icp_requests++; - } - if (logtag =~ "HIT") { - prxy_squid_cache_hits++; - } - if (logtag =~ "MISS") { - squid_cache_misses++; - } - - word = strtok(nil, " "); /* Reply code. */ - if (word == nil) { - return; - } - WWW_REPLY_CODE(word) - word = strtok(nil, " "); /* Size sent to client. */ - if (word == nil) { - return; - } - z = atoi(word); - WWW_SIZE_INDEX(z, size_index) - www_dwnld_time_by_size[size_index] += xf; - - request = strtok(nil, " "); /* Request method. */ - if (request == nil) { - return; - } - WWW_METHOD(request) - /* Do not add the size if it is a HEAD. */ - if (ishead == 0) { - dwnld_totalz += z; - } - - word = strtok(nil, " "); /* URL. */ - if (word == nil) { - return; - } - if (word =~ "cgi-bin") { - httpop_cgi_bins++; - } - if (word =~ www_search_url) { - httpop_searches++; - } - strtok(nil, " "); /* Optional user identity. */ - word = strtok(nil, "/"); /* Hierarchy. */ - if (word == nil) { - return; - } - if (word =~ "DIRECT") { - prxy_squid_indirect++; - } -#if 0 - word = strtok(nil, " "); /* Hostname. */ - if (word == nil) { - return; - } - word = strtok(nil, " "); /* Content-type. */ - if (word == nil) { - return; - } -#endif - -#elif WATCH_YAHOO - /* - * Yahoo log format. Fields in square brackets will only appear in the - * log file if the data actually exists (i.e. you will never see a null - * Referrer field). Further, fields labeled here with "(CONFIG)" will - * only appear if they are enabled via the YahooLogOptions configuration - * directive. - * - * IP Address (8 hex digits) - * Timestamp (time_t as 8 hex digits) - * Processing Time (in microseconds, as 8 hex digits) - * Bytes Sent (8 hex digits) - * URL - * [^Er referrer] (CONFIG) - * [^Em method] (CONFIG) - * [^Es status_code] - * ^Ed signature - * \n - */ - - /* - * Ignore the IP address and timestamp. Get the processing time, the - * number of bytes sent and the URL. For each portion of the line, split - * it up into separate pieces. - */ - if (sscanf(word, "%8lx%8lx%8x%8x", &tmp, &tmp, &ulong_xf, &z) != 4) { - return; - } - - xf = ulong_xf/1000000.0; - WWW_SIZE_INDEX(z, size_index) - www_dwnld_time_sum += xf; - www_dwnld_time_by_size[size_index] += xf; - - if (word =~ "cgi-bin") { - httpop_cgi_bins++; - } - if (word =~ www_search_url) { - httpop_searches++; - } - - for (;;) { - word = strtok(nil, "\05"); - if (word == nil) { - break; - } - first_byte = word; - ptr = &word + 1; - arg = ((string) ptr); - ptr = 0; - switch (first_byte[0]) { - case 'm': - WWW_METHOD(arg) - ptr = 1; - break; - case 's': - WWW_REPLY_CODE(arg) - break; - default: - break; - } - } - - /* If no method was seen, then assume it was a GET. */ - if (ptr == 0) { - httpop_gets++; - } - - /* Do not add the size if it is a HEAD. */ - if (ishead == 0) { - dwnld_totalz += z; - } - -#else /* common or Netscape proxy formats */ - strtok(nil, " "); /* -. */ - strtok(nil, " "); /* -. */ - strtok(nil, " ["); /* date. */ - strtok(nil, " "); /* zone]. */ - strtok(nil, " \""); /* GET or POST. */ - if (word == nil) { - return; - } - WWW_METHOD(word) - word = strtok(nil, " "); /* URL. */ - if (word == nil) { - return; - } - if (word =~ "cgi-bin") { - httpop_cgi_bins++; - } - if (word =~ www_search_url) { - httpop_searches++; - } - /* - * Sometimes HTTP/1.x is not listed in the access log. Skip it - * if it does exist. Load the error/success code. - */ - word = strtok(nil, " "); - if (word == nil) { - return; - } - if (word =~ "HTTP" || word =~ "http") { - word = strtok(nil, " "); - if (word == nil) { - return; - } - } - WWW_REPLY_CODE(word) - word = strtok(nil, " "); /* Bytes transferred. */ - if (word == nil) { - return; - } - z = atoi(word); - /* Do not add the size if it is a HEAD. */ - if (ishead == 0) { - dwnld_totalz += z; - } - WWW_SIZE_INDEX(z, size_index) -#ifdef WATCH_PROXY - strtok(nil, " "); /* Status from server. */ - strtok(nil, " "); /* Length from server. */ - strtok(nil, " "); /* Length from client POST. */ - strtok(nil, " "); /* Length POSTed to remote. */ - strtok(nil, " "); /* Client header request. */ - strtok(nil, " "); /* Proxy header response. */ - strtok(nil, " "); /* Proxy header request. */ - strtok(nil, " "); /* Server header response. */ - strtok(nil, " "); /* Transfer total seconds. */ - word = strtok(nil, " "); /* Route. */ - if (word == nil) { - return; - } - - /* - DIRECT PROXY(host.domain:port) SOCKS. */ - if (strncmp(word, "PROXY", 5) == 0 || - strncmp(word, "SOCKS", 5) == 0) { - prxy_squid_indirect++; - } - strtok(nil, " "); /* Client finish status. */ - strtok(nil, " "); /* Server finish status. */ - word = strtok(nil, " "); /* Cache finish status. */ - if (word == nil) { - return; - } - /* - * ERROR HOST-NOT-AVAILABLE = error or incomplete op - * WRITTEN REFRESHED CL-MISMATCH(content length mismatch) = cache_writes - * NO-CHECK UP-TO-DATE = cache_hits - * DO-NOT-CACHE NON-CACHEABLE = uncacheable - */ - switch(word) { - case "WRITTEN": - case "REFRESHED": - case "CL-MISMATCH": - prxy_cache_writes++; - break; - case "NO-CHECK": - case "UP-TO-DATE": - prxy_squid_cache_hits++; - break; - case "DO-NOT-CACHE": - case "NON-CACHEABLE": - prxy_uncacheable++; - break; - default: - break; - } - word = strtok(nil, " ["); /* [transfer total time x.xxx. */ - if (word == nil) { - return; - } - xf = atof(word); - www_dwnld_time_sum += xf; - www_dwnld_time_by_size[size_index] += xf; -#endif -#endif -} - -measure_web(long sleep_till) -{ - double lastops = 0.0; - char buf[BUFSIZ]; - int i; - long now; - long sleep_till_tmp; - - httpops = 0.0; - httpops5 = 0.0; - gateops = 0.0; - httpop_gets = 0; - httpop_condgets = 0; - httpop_posts = 0; - httpop_cgi_bins = 0; - httpop_errors = 0; - httpop_searches = 0; - - for (i=0; i<5; ++i) { - dwnld_size[i] = 0; -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - www_dwnld_time_by_size[i] = 0.0; -#endif - } - dwnld_totalz = 0; - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - www_dwnld_time_sum = 0.0; -#endif -#if WATCH_PROXY || WATCH_SQUID - prxy_squid_indirect = 0; - prxy_squid_cache_hits = 0; -#ifdef WATCH_PROXY - prxy_cache_writes = 0; - prxy_uncacheable = 0; -#else - squid_cache_misses = 0; - squid_icp_requests = 0; - squid_icp_queries = 0; - squid_client_http = 0; -#endif -#endif - - if (www_log_filename != nil) { - now = time(0); - while (now < sleep_till) { - if (now + 5 < sleep_till) { - sleep_till_tmp = now + 5; - } else { - sleep_till_tmp = sleep_till; - } -#ifdef WATCH_CPU - sleep_till_and_count_new_processes(sleep_till_tmp); -#else - orca_sleep_till(sleep_till_tmp); -#endif - - now = time(0); - if (www_log_fp != 0) { - buf[BUFSIZ-1] = 127; - while (fgets(buf, BUFSIZ, www_log_fp) != nil) { - httpops += 1.0; - if (www_gatelen > 0) { - if (strncmp(buf, www_gateway, www_gatelen) == 0) { - gateops += 1.0; - } - } - accesslog(buf); - - /* - * If the line is longer than the buffer, then ignore the rest - * of the line. - */ - while (buf[BUFSIZ-1] == 0 && - buf[BUFSIZ-2] != '\n') { - buf[BUFSIZ-1] = 127; - if (fgets(buf, BUFSIZ, www_log_fp) == nil) { - break; - } - } - } - } - - /* - * See if the file has been switched or truncated. - */ - if (stat(www_log_filename, www_log_stat) == 0) { - if (www_log_ino != www_log_stat[0].st_ino || - www_log_size > www_log_stat[0].st_size) { - /* - * Close the old log file and open the new one. - */ - if (www_log_fp != 0) { - fclose(www_log_fp); - } - - www_log_fp = fopen(www_log_filename, "r"); - if (www_log_fp != 0) { - fstat(fileno(www_log_fp), www_log_stat); - www_log_ino = www_log_stat[0].st_ino; - www_log_size = www_log_stat[0].st_size; - buf[BUFSIZ-1] = 127; - while(fgets(buf, BUFSIZ, www_log_fp) != nil) { - httpops += 1.0; - if (www_gatelen > 0) { - if (strncmp(buf, www_gateway, www_gatelen) == 0) { - gateops += 1.0; - } - } - accesslog(buf); - - /* - * If the line is longer than the buffer, then ignore - * the rest of the line. - */ - while (buf[BUFSIZ-1] == 0 && - buf[BUFSIZ-2] != '\n') { - buf[BUFSIZ-1] = 127; - if (fgets(buf, BUFSIZ, www_log_fp) == nil) { - break; - } - } - } - } else { - www_log_ino = 0; - www_log_size = 0; - } - } else { - /* - * Remember size for next time. - */ - www_log_size = www_log_stat[0].st_size; - } - } - - www5_now = gethrtime(); - www5_interval = (www5_now - www5_then) * 0.000000001; - www5_then = www5_now; - dtmp = (httpops - lastops)/www5_interval; - if (dtmp > httpops5) { - httpops5 = dtmp; - } - lastops = httpops; - } - } - else { - sleep_till_and_count_new_processes(sleep_till); - www5_now = gethrtime(); - } - - www_now = www5_now; - www_interval = (www_now - www_then) * 0.000000001; - www_then = www_now; - - /* - * Use dtmp to get percentages. - */ - if (httpops == 0.0) { - dtmp = 0.0; - } - else { - dtmp = 100.0 / httpops; - } - -#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO - for (i=0; i<5; ++i) { - if (dwnld_size[i] == 0) { - www_dwnld_time_by_size[i] = 0.0; - } - else { - www_dwnld_time_by_size[i] = www_dwnld_time_by_size[i]/dwnld_size[i]; - } - } -#endif -} - -// Functions in SE cannot return an array, so to work around this, have -// count_procs place it's results in a global array. -#define MAX_COUNT_PROC_REGEXS 2 -int count_procs_results[MAX_COUNT_PROC_REGEXS]; -count_procs(int number_regexs, string regexs[]) -{ - psinfo_t p; - int i; - - if (number_regexs > MAX_COUNT_PROC_REGEXS) { - fprintf(stderr, "%s: too many regular expressions (%d). Increase MAX_COUNT_PROC_REGEXS.\n", - program_name, number_regexs); - exit(1); - } - - for (i=0; i. +// +// Portions copied from percollator.se written by Adrian Cockroft. +// +// $HeadURL$ +// $LastChangedDate$ +// $LastChangedBy$ +// $LastChangedRevision$ +// +// Revision history for this file can be retrieved by running svn log +// on the HeadURL listed above. +// + +// The default sampling interval in seconds. +#define SAMPLE_INTERVAL 300 + +// The maximum number of columns of data. +#define MAX_COLUMNS 2048 + +// Enable kstat io measuring code. +#define USE_KSTAT_IO 1 + +// If WATCH_OS is defined, then measure every part of the operating +// system. +#ifdef WATCH_OS +#define WATCH_CPU 1 +#define WATCH_MUTEX 1 +#define WATCH_NET 1 +#define WATCH_TCP 1 +#define WATCH_NFS_CLIENT 1 +#define WATCH_NFS_SERVER 1 +#define WATCH_MOUNTS 1 +#define WATCH_DISK 1 +#define WATCH_DNLC 1 +#define WATCH_INODE 1 +#define WATCH_RAM 1 +#define WATCH_PAGES 1 +#endif + +// Keep backwards compatibility with WATCH_HTTPD. +#ifdef WATCH_HTTPD +#define WATCH_WEB 1 +#endif + +// Keep backwards compatibility with WATCH_NFS. +#ifdef WATCH_NFS +#ifndef WATCH_NFS_CLIENT +#define WATCH_NFS_CLIENT 1 +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +//#include +#include +//#include +#include +#include +#include +#include +#include +#include + +#ifdef WATCH_MOUNTS +#include +#include +#endif + +#if WATCH_CPU || WATCH_WEB +#include + +#ifdef WATCH_CPU +// This is the maximum pid on Solaris hosts. +#define DEFAULT_MAXPID 30000 +#include +#endif + +#ifdef WATCH_WEB + +// Define this macro which returns the size index for a file of a +// particular size. This saves the overhead of a function call. +#define WWW_SIZE_INDEX(size, size_index) \ + if (size < 1024) { \ + size_index=0; /* Under 1KB */ \ + } else { \ + if (size < 10240) { \ + size_index=1; /* Under 10K */ \ + } else { \ + if (size < 102400) { \ + size_index=2; /* Under 100KB */ \ + } else { \ + if (size < 1048576) { \ + size_index=3; /* Under 1MB */ \ + } else { \ + size_index=4; /* Over 1MB */ \ + } \ + } \ + } \ + } \ + dwnld_size[size_index]++; + +// Handle the reply code from the server. +#define WWW_REPLY_CODE(word) \ + if (word == "304") { \ + httpop_condgets++; \ + } \ + else { \ + first_byte = word; \ + if (first_byte[0] == '4' || first_byte[0] == '5') { \ + httpop_errors++; \ + } \ + } \ + +// Handle the method of the object served. This define only works +// with non-proxy servers. +#define WWW_METHOD1(word) \ + switch (word) { \ + case "get": \ + case "GET": \ + httpop_gets++; \ + break; \ + case "post": \ + case "POST": \ + httpop_posts++; \ + break; \ + case "head": \ + case "HEAD": \ + ishead = 1; \ + httpop_condgets++; \ + break; + +#ifdef WATCH_SQUID +#define WWW_METHOD2 \ + case "icp_query": \ + case "ICP_QUERY": \ + squid_icp_queries++; \ + break; +#else +#define WWW_METHOD2 +#endif + +#define WWW_METHOD_END \ + default: \ + break; \ + } +#define WWW_METHOD(word) WWW_METHOD1(word) WWW_METHOD2 WWW_METHOD_END +#endif +#endif + +// Put all rules here so they can be accessed by the handle functions. +lr_cpu_t lr_cpu$cpu; +lr_cpu_t tmp_lr_cpu; +lr_mutex_t lr_mutex$m; +lr_mutex_t tmp_lr_mutex; +lr_net_t lr_net$nr; +lr_net_t tmp_lr_net; +lr_tcp_t lr_tcp$tcp; +lr_tcp_t tmp_lr_tcp; +lr_rpcclient_t lr_rpcclient$r; +lr_rpcclient_t tmp_lr_rpcclient; +lr_disk_t lr_disk$dr; +lr_disk_t tmp_lr_disk; +lr_dnlc_t lr_dnlc$dnlc; +lr_dnlc_t tmp_lr_dnlc; +lr_inode_t lr_inode$inode; +lr_inode_t tmp_lr_inode; +lr_ram_t lr_ram$ram; +lr_ram_t tmp_lr_ram; +lr_swapspace_t lr_swapspace$s; +lr_swapspace_t tmp_lr_swapspace; +lr_kmem_t lr_kmem$kmem; +lr_kmem_t tmp_lr_kmem; + +ks_system_misc kstat$misc; +ks_system_misc tmp_kstat_misc; +#ifdef WATCH_TCP +tcp tcp$tcp; +tcp tmp_tcp; +#endif +#ifdef WATCH_PAGES +ks_system_pages kstat$pages; +ks_system_pages tmp_kstat_pages; +#endif + +// Put application globals here. +string nodename; // Name of this machine. +string program_name; // Name of this program. +int hz; // Clock tick rate. +int page_size; // Page size in bytes. +long boot_time; // Boot time of the system. +long interval = SAMPLE_INTERVAL; // Sampling interval. + +#ifdef WATCH_CPU +int can_read_kernel = 0; // If the kernel can be read. +int kvm$mpid; // The last created PID. + +// These variables store the mpid before and after the standard interval. +int mpid_previous; +int mpid_current; +ulonglong mpid_then; +ulonglong mpid_now; + +// These variables store the mpid before and after 5 second intervals. +int mpid5_previous; +int mpid5_current; +ulonglong mpid5_then; +ulonglong mpid5_now; +double mpid5_rate; +#endif + +#ifdef WATCH_MOUNTS +mnttab_t mnt$mnt; +mnttab_t tmp_mnt; +#endif + +#ifdef WATCH_NFS_SERVER +ks_nfs_server kstat$nfs; +ks_nfs_server tmp_nfs; +ks_rfs_proc_v2 kstat$rfsproccnt_v2; +ks_rfs_proc_v2 tmp_rfsproccnt_v2; +ks_rfs_proc_v3 kstat$rfsproccnt_v3; +ks_rfs_proc_v3 tmp_rfsproccnt_v3; +#endif + +// Variables for handling the httpd access log. +#ifdef WATCH_WEB +string www_search_url = getenv("SEARCHURL"); +string www_server_proc_name = getenv("WEB_SERVER"); +string www_server_secure_proc_name = getenv("WEB_SERVER_SECURE"); +string www_log_filename = getenv("WEB_LOG"); +string www_gateway = getenv("GATEWAY"); +ulong www_log_fp; +uint www_gatelen; +stat_t www_log_stat[1]; +ulong www_log_ino; +long www_log_size; + +double www_interval; // Hi-res interval time. +ulonglong www_then; +ulonglong www_now; + +double www5_interval; // Actual hi-res 5 second interval. +ulonglong www5_then; +ulonglong www5_now; + +double httpops; +double httpops5; +double gateops; +double dtmp; + +long httpop_gets; +long httpop_condgets; // HEAD or code = 304 conditional get no data. +long httpop_posts; +long httpop_cgi_bins; +long httpop_searches; +long httpop_errors; +long dwnld_size[5]; // [0] < 1K, [1] < 10K, [2] < 100K, [3] < 1M, [4] >= 1M +long dwnld_totalz; // Total size counted from log. + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO +// If we're watching a Yahoo log, then take the transfer time to be the +// processing time. +double www_dwnld_time_sum; // Transfer time. +double www_dwnld_time_by_size[5]; // Mean transfer time by size bin. +#endif +#if WATCH_PROXY || WATCH_SQUID +long prxy_squid_indirect; // # hits that go via PROXY,SOCKS,parent +long prxy_squid_cache_hits; // # hits returned from cache. +#endif + +#ifdef WATCH_PROXY +long prxy_cache_writes; // Number of writes and updates to cache. +long prxy_uncacheable; // Number of explicitly uncacheable httpops. + // Any extra is errors or incomplete ops. +#endif + +#ifdef WATCH_SQUID +long squid_cache_misses; +long squid_icp_requests; +long squid_icp_queries; +long squid_client_http; +#endif + +#endif + +#ifdef USE_KSTAT_IO +#include +#include +// This code was developed so that the performance of virtual disks +// originating from a Sun A1000 raid controller could be monitored. +// These disks do not show up in the GLOBAL_disk[] io structure of SE. +// +// This extension accesses the sys_kstat.se interface to the kstat IO +// queues to extract info on drives not available in the kstat.se +// kstat$disk interface. Global data shared between function calls. +struct io_dev_info_t { + // Exposed interface that matches kstat. + string dev_class; + string long_name; + string short_name; + double reads; + double kreads; + double writes; + double kwrites; + double avg_wait; + double avg_serv; + double service; + double wait_percent; + double run_percent; + + // Hidden internal registers to track sys_kstats counters. + int _number; // kstat disk # + ulonglong _nread; // Number of bytes read + ulonglong _nwritten; // Number of bytes written + uint _reads; // Number of read operations + uint _writes; // Number of write operations + longlong _wtime; // Cumulative wait (pre-service) time + longlong _wlentime; // Cumulative wait length*time product + longlong _wlastupdate; // Last time wait queue changed + longlong _rtime; // Cumulative run (service) time + longlong _rlentime; // Cumulative run length*time product + longlong _rlastupdate; // Last time run queue changed + uint _wcnt; // Count of elements in wait state + uint _rcnt; // Count of elements in run state +}; + +// Define global for tracking raw disk data. +io_dev_info_t ORCA_io_dev_info[]; +int ORCA_io_dev_count=0; +int ORCA_max_io_dev_count=0; + +orca_io_info_update() { + int iodev; + int index; + ulong ul; + kstat_ctl_t kc[1]; + kstat_t kp[1]; + kstat_t nkp[1]; + kstat_io_t kio; + + double read_writes; + double big_etime; + double elapsed_etime; + double hz_etime; + + kc[0] = kstat_open(); + // Read them. + if (kstat_read(kc, kp, 0) == -1) { + perror("orca_io_info_update:kstat_read"); + exit(1); + } + + // Traverse the chain looking for IO events. + for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { + struct_fill(nkp[0], ul); + if (nkp[0].ks_type == KSTAT_TYPE_IO) { + // Look for disk or tape statistics + if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { + // Update the device registers. + if (kstat_read(kc, nkp, 0) == -1) { + perror("orca_io_info_update:kstat_read error"); + exit(1); + } + // Read sys_kstat device IO queue to find out about recent activity. + struct_fill(kio, nkp[0].ks_data); + + // Try to locate device. + for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { + if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { + break; + } + } + + // It must be new. Add it! + if (iodev == ORCA_io_dev_count) { + // Grow the device array if needed + if (ORCA_io_dev_count == ORCA_max_io_dev_count) { + ORCA_max_io_dev_count += 10; + ORCA_io_dev_info = renew ORCA_io_dev_info[ORCA_max_io_dev_count]; + } + + if (nkp[0].ks_class == "tape") { + index = find_tape_inst(nkp[0].ks_name); + } else { + index = find_inst(nkp[0].ks_name); + } + if (index != -1) { + if (nkp[0].ks_class == "tape") { + ORCA_io_dev_info[iodev].long_name = GLOBAL_tape_info[index].long_name; + } else { + ORCA_io_dev_info[iodev].long_name = GLOBAL_disk_info[index].long_name; + } + } else { + ORCA_io_dev_info[iodev].long_name = nkp[0].ks_name; + } + ORCA_io_dev_info[iodev].short_name = nkp[0].ks_name; + + ORCA_io_dev_info[iodev]._writes = kio.writes; + ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; + ORCA_io_dev_info[iodev]._wlastupdate = kio.wlastupdate; + ORCA_io_dev_info[iodev]._wlentime = kio.wlentime; + ORCA_io_dev_info[iodev]._wtime = kio.wtime; + ORCA_io_dev_info[iodev]._wcnt = kio.wcnt; + ORCA_io_dev_info[iodev]._reads = kio.reads; + ORCA_io_dev_info[iodev]._nread = kio.nread; + ORCA_io_dev_info[iodev]._rlastupdate = kio.rlastupdate; + ORCA_io_dev_info[iodev]._rlentime = kio.rlentime; + ORCA_io_dev_info[iodev]._rtime = kio.rtime; + ORCA_io_dev_info[iodev]._rcnt = kio.rcnt; + ORCA_io_dev_count++; + } + + elapsed_etime = (kio.wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); + if (elapsed_etime == 0) { + elapsed_etime = NANOSEC; + } + hz_etime = elapsed_etime / NANOSEC; + big_etime = 1024.0 * hz_etime; + + ORCA_io_dev_info[iodev].reads =(kio.reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; + ORCA_io_dev_info[iodev].kreads =(kio.nread-ORCA_io_dev_info[iodev]._nread) /big_etime; + ORCA_io_dev_info[iodev].writes =(kio.writes-ORCA_io_dev_info[iodev]._writes) /hz_etime; + ORCA_io_dev_info[iodev].kwrites=(kio.nwritten-ORCA_io_dev_info[iodev]._nwritten)/big_etime; + + read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; + if (read_writes > 0) { + ORCA_io_dev_info[iodev].avg_wait = (kio.wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; + ORCA_io_dev_info[iodev].avg_serv = (kio.rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; + ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; + } else { + ORCA_io_dev_info[iodev].avg_wait = 0.0; + ORCA_io_dev_info[iodev].avg_serv = 0.0; + ORCA_io_dev_info[iodev].service = 0.0; + } + + // Update the counters. + ORCA_io_dev_info[iodev].run_percent = 100.0 * (kio.rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; + ORCA_io_dev_info[iodev].wait_percent = 100.0 * (kio.wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; + ORCA_io_dev_info[iodev]._writes = kio.writes; + ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; + ORCA_io_dev_info[iodev]._wlastupdate = kio.wlastupdate; + ORCA_io_dev_info[iodev]._wlentime = kio.wlentime; + ORCA_io_dev_info[iodev]._wtime = kio.wtime; + ORCA_io_dev_info[iodev]._wcnt = kio.wcnt; + ORCA_io_dev_info[iodev]._reads = kio.reads; + ORCA_io_dev_info[iodev]._nread = kio.nread; + ORCA_io_dev_info[iodev]._rlastupdate = kio.rlastupdate; + ORCA_io_dev_info[iodev]._rlentime = kio.rlentime; + ORCA_io_dev_info[iodev]._rtime = kio.rtime; + ORCA_io_dev_info[iodev]._rcnt = kio.rcnt; + } + } + } + kstat_close(kc); +} +#endif // USE_KSTAT_IO + +// Variables for handling output. +string compress = getenv("COMPRESSOR"); // How to compress logs. +ulong out_log_fp; // File pointer to the logging file. +string col_comment[MAX_COLUMNS]; // Comments for each column. +string col_data[MAX_COLUMNS]; // Data for each column. +string col_previous_comment[MAX_COLUMNS]; // Previous comments. +int current_column = 0; // The current column. +int previous_number_columns = -1; // Number columns printed last. +int print_header = 1; // Flag to flush header. + +// This is a list of the extensions the compress programs add to the +// compress filename. +#define NUMBER_COMPRESS_SUFFIXES 3 +string compression_suffixes[NUMBER_COMPRESS_SUFFIXES] = {".Z", + ".gz", + ".bz2"}; + +// Add one column of comments and data to the buffers. +put_output(string comment, string data) +{ + if (current_column >= MAX_COLUMNS) { + fprintf(stderr, "%s: too many columns (%d). Increase MAX_COLUMNS.\n", + program_name, current_column); + exit(1); + } + + col_comment[current_column] = comment; + col_data[current_column] = data; + current_column++; +} + +// Send the stored columns of information to the output. +print_columns(string data[]) +{ + int i; + for (i=0; i 0) { + usleep(1000000*time_to_sleep - now[0].tv_usec); + gettimeofday(now, 0); + time_to_sleep = sleep_till - now[0].tv_sec; + } +} + +sleep_till_and_count_new_processes(long sleep_till) +{ + long now; +#ifdef WATCH_CPU + int mpid5_diff; + double mpid5_interval; + double rate; +#endif + + now = time(0); + while (now < sleep_till) { +#ifdef WATCH_CPU + if (can_read_kernel != 0) { + // Sleep for 5 seconds to make a measurement or less to stay + // within the sleep_till limit. + if (now + 5 < sleep_till) { + orca_sleep_till(now + 5); + } else { + orca_sleep_till(sleep_till); + } + + // Measure the 5 second process creation rate. + mpid5_current = kvm$mpid; + mpid5_now = gethrtime(); + mpid5_interval = (mpid5_now - mpid5_then) * 0.000000001; + mpid5_then = mpid5_now; + if (mpid5_current >= mpid5_previous) { + mpid5_diff = mpid5_current - mpid5_previous; + } + else { + mpid5_diff = mpid5_current + DEFAULT_MAXPID - mpid5_previous; + } + rate = mpid5_diff/mpid5_interval; + if (rate > mpid5_rate) { + mpid5_rate = rate; + } + mpid5_previous = mpid5_current; + + // Now take these results to measure the long interval rate. + // Because the mpid may flip over DEFAULT_MAXPID more than once + // in the long interval time span, use the difference between + // the previous and current mpid over a 5 second interval to + // calculate the long interval difference. + mpid_current += mpid5_diff; + mpid_now = mpid5_now; + } + else { + orca_sleep_till(sleep_till); + } +#else + orca_sleep_till(sleep_till); +#endif + now = time(0); + } +} + +#ifdef WATCH_CPU +measure_cpu() +{ + p_vmstat pvm; + double mpid_interval; + double mpid_rate; + + pvm = vmglobal_total(); + + // In SE 3.0 and below user_time and system_time are int and in SE + // 3.1 and above they are double, so cast everything to double using + // + 0.0. + put_output(" usr%", sprintf("%5.1f", pvm.user_time + 0.0)); + put_output(" sys%", sprintf("%5.1f", pvm.system_time + 0.0)); + put_output(" wio%", sprintf("%5.1f", pvm.wait_time + 0.0)); + put_output("idle%", sprintf("%5.1f", pvm.idle_time + 0.0)); + put_output(" 1runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_1min/256.0)); + put_output(" 5runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_5min/256.0)); + put_output("15runq", sprintf("%6.2f", tmp_kstat_misc.avenrun_15min/256.0)); + put_output("#proc", sprintf("%5lu", tmp_kstat_misc.nproc)); + put_output(" #runque", sprintf("%8.2f", pvm.runque + 0.0)); + put_output("#waiting", sprintf("%8.2f", pvm.waiting + 0.0)); + put_output(" #swpque", sprintf("%8.2f", pvm.swpque + 0.0)); + put_output("scanrate", sprintf("%8.3f", pvm.scan + 0.0)); + put_output("pgrec/s", sprintf("%8.3f", pvm.pgrec + 0.0)); + put_output("pgfrec/s", sprintf("%8.3f", pvm.pgfrec + 0.0)); + put_output("pgin/s", sprintf("%8.3f", pvm.pgin + 0.0)); + put_output("pages_in/s", sprintf("%8.3f", pvm.pages_in + 0.0)); + put_output("pgout/s", sprintf("%8.3f", pvm.pgout + 0.0)); + put_output("pages_out/s", sprintf("%8.3f", pvm.pages_out + 0.0)); + put_output("dfree/s", sprintf("%8.3f", pvm.dfree + 0.0)); + put_output("min_fault/s", sprintf("%8.3f", pvm.hat_fault + pvm.as_fault + 0.0)) +; + put_output("maj_fault/s", sprintf("%8.3f", pvm.maj_fault + 0.0)); + put_output("prot_fault/s", sprintf("%8.3f", pvm.prot_fault + 0.0)); + put_output("cow_fault/s", sprintf("%8.3f", pvm.cow_fault + 0.0)); + put_output("zfod/s", sprintf("%8.3f", pvm.zfod + 0.0)); + put_output("interrupts/s", sprintf("%8.3f", pvm.interrupts + 0.0)); + put_output("intrthread/s", sprintf("%8.3f", pvm.intrthread + 0.0)); + put_output("system_calls/s", sprintf("%8.3f", pvm.system_calls + 0.0)); + put_output("context_switches/s", sprintf("%8.3f", pvm.context_switches + 0.0)); + put_output("invol_switches/s", sprintf("%8.3f", pvm.invol_switches + 0.0)); + put_output("traps/s", sprintf("%8.3f", pvm.trap + 0.0)); + put_output("forks/s", sprintf("%8.3f", pvm.sysfork + 0.0)); + put_output("vforks/s", sprintf("%8.3f", pvm.sysvfork + 0.0)); + put_output("execs/s", sprintf("%8.3f", pvm.sysexec + 0.0)); + put_output("namei/s", sprintf("%8.3f", pvm.namei + 0.0)); + put_output("ufsiget/s", sprintf("%8.3f", pvm.ufsiget + 0.0)); + put_output("ufsdirblk/s", sprintf("%8.3f", pvm.ufsdirblk + 0.0)); + + // Calculate the rate of new process spawning. + if (can_read_kernel != 0) { + mpid_interval = (mpid_now - mpid_then) * 0.000000001; + mpid_rate = (mpid_current - mpid_previous) / mpid_interval; + put_output("#proc/s", sprintf("%7.3f", mpid_rate)); + put_output("#proc/p5s", sprintf("%9.4f", mpid5_rate)); + + // Reset counters. + mpid_then = mpid_now; + mpid_previous = mpid_current; + mpid5_rate = 0; + } +} +#endif + +#ifdef WATCH_MUTEX +measure_mutex() +{ + put_output(" smtx", sprintf("%5d", tmp_lr_mutex.smtx)); + put_output("smtx/cpu", sprintf("%8d", tmp_lr_mutex.smtx/GLOBAL_pvm_ncpus)); +} +#endif + +#ifdef WATCH_NET +measure_net() +{ + int previous_count = -1; + int current_count; + int i; + + current_count = 0; + for (i=0; i. Check + // [wr]lentime to see if an EMC is using a fake disk for control. + // EMC disks have a fake disk which commands are run over to + // configure the disk array or to get stats from; they are not + // real data transfers. They cause 1000 MB/sec writes to appear + // in the stats. I still get them but not as often with this bit + // of code in. If the I/O which occurred in the last five minutes + // is not greater than 1/100sec then it is not a valid measurement + // anyway. What happens is that we can have a small I/O, say 1024 + // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making + // it wlentime+rlentime>2 since I am still getting fake write + // spikes. +#ifdef HAVE_EMC_DISK_CONTROL + if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { +#endif + total_disk_reads += ORCA_io_dev_info[i].reads; + total_disk_writes += ORCA_io_dev_info[i].writes; + total_disk_readk += ORCA_io_dev_info[i].kreads; + total_disk_writek += ORCA_io_dev_info[i].kwrites; + mean_disk_busy += ORCA_io_dev_info[i].run_percent; + if (ORCA_io_dev_info[i].run_percent > peak_disk_busy) { + peak_disk_busy = ORCA_io_dev_info[i].run_percent; + } +#ifdef HAVE_EMC_DISK_CONTROL + } +#endif + } +#else + for (i=0; i. Check + // [wr]lentime to see if an EMC is using a fake disk for control. + // EMC disks have a fake disk which commands are run over to + // configure the disk array or to get stats from; they are not + // real data transfers. They cause 1000 MB/sec writes to appear + // in the stats. I still get them but not as often with this bit + // of code in. If the I/O which occurred in the last five minutes + // is not greater than 1/100sec then it is not a valid measurement + // anyway. What happens is that we can have a small I/O, say 1024 + // bytes, in a 1/100sec = 1024*100/sec. I am thinking of making + // it wlentime+rlentime>2 since I am still getting fake write + // spikes. +#ifdef HAVE_EMC_DISK_CONTROL + if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { +#endif + total_disk_reads += GLOBAL_disk[i].reads; + total_disk_writes += GLOBAL_disk[i].writes; + total_disk_readk += GLOBAL_disk[i].kreads; + total_disk_writek += GLOBAL_disk[i].kwrites; + mean_disk_busy += GLOBAL_disk[i].run_percent; + if (GLOBAL_disk[i].run_percent > peak_disk_busy) { + peak_disk_busy = GLOBAL_disk[i].run_percent; + } +#ifdef HAVE_EMC_DISK_CONTROL + } +#endif + } +#endif + + if (disk_count != 0) { + mean_disk_busy = mean_disk_busy/disk_count; + } + + put_output("disk_peak", sprintf("%9.3f", peak_disk_busy)); + put_output("disk_mean", sprintf("%9.3f", mean_disk_busy)); + put_output("disk_rd/s", sprintf("%9.1f", total_disk_reads)); + put_output("disk_wr/s", sprintf("%9.1f", total_disk_writes)); + put_output("disk_rK/s", sprintf("%9.1f", total_disk_readk)); + put_output("disk_wK/s", sprintf("%9.1f", total_disk_writek)); + + put_output("tape_rd/s", sprintf("%9.1f", total_tape_reads)); + put_output("tape_wr/s", sprintf("%9.1f", total_tape_writes)); + put_output("tape_rK/s", sprintf("%9.1f", total_tape_readk)); + put_output("tape_wK/s", sprintf("%9.1f", total_tape_writek)); + + // If the number of disks and/or tapes has changed, say due to a + // add_drv, then print new headers. + if (previous_disk_count != disk_count) { + print_header = 1; + previous_disk_count = disk_count; + } + if (previous_tape_count != tape_count) { + print_header = 1; + previous_tape_count = tape_count; + } +} +#endif + +#ifdef WATCH_DNLC +measure_dnlc() +{ + put_output("dnlc_ref/s", sprintf("%10.3f", tmp_lr_dnlc.refrate)); + put_output("dnlc_hit%", sprintf("%9.3f", tmp_lr_dnlc.hitrate)); +} +#endif + +#ifdef WATCH_INODE +measure_inode() +{ + p_vmstat pvm; + + put_output("inod_ref/s", sprintf("%10.3f", tmp_lr_inode.refrate)); + put_output("inod_hit%", sprintf("%9.3f", tmp_lr_inode.hitrate)); + put_output("inod_stl/s", sprintf("%10.3f", tmp_lr_inode.iprate)); + put_output("ufsinopage/s", sprintf("%8.3f", pvm.ufsinopage + 0.0)); + +} +#endif + +#ifdef WATCH_RAM +measure_ram() +{ + put_output("swap_avail", sprintf("%10ld", GLOBAL_pvm[0].swap_avail)); + put_output("page_rstim", sprintf("%10d", tmp_lr_ram.restime)); + put_output(" freememK", sprintf("%10d", GLOBAL_pvm[0].freemem)); + put_output("free_pages", sprintf("%10d", (GLOBAL_pvm[0].freemem*1024)/page_size)); +} +#endif + +#ifdef WATCH_PAGES +measure_pages() +{ + put_output("pp_kernel", sprintf("%9lu", tmp_kstat_pages.pp_kernel)); + put_output("pagesfree", sprintf("%9lu", tmp_kstat_pages.pagesfree)); + put_output("pageslock", sprintf("%9lu", tmp_kstat_pages.pageslocked)); +#if MINOR_VERSION < 80 + put_output("pagesio", sprintf("%7lu", tmp_kstat_pages.pagesio)); +#endif + put_output("pagestotl", sprintf("%9lu", tmp_kstat_pages.pagestotal)); +} +#endif + +#ifdef WATCH_WEB +/* + * Breakdown access log format. + */ +accesslog(string buf) { + int z; + int size_index; + int ishead; + string word; + char first_byte[1]; + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + double xf; +#ifdef WATCH_SQUID + string logtag; + string request; +#endif +#ifdef WATCH_YAHOO + string arg; + ulong ptr; + ulong tmp; + ulong ulong_xf; +#endif +#endif + + ishead = 0; +#ifdef WATCH_YAHOO + /* + * Make sure that the input line has at least 32 bytes of data plus a new + * line, for a total length of 33. + */ + if (strlen(buf) < 33) { + return; + } + word = strtok(buf, "\05"); +#else + word = strtok(buf, " "); +#endif + if (word == nil) { + return; + } + +#ifdef WATCH_SQUID + /* + * Word contains unix time in seconds.milliseconds. + */ + word = strtok(nil, " "); + if (word == nil) { + return; + } + xf = atof(word)/1000.0; + www_dwnld_time_sum += xf; +#ifdef DINKY + printf("time: %s %f total %f\n", word, xf, xfer_sum); +#endif + word = strtok(nil, " "); /* Client IP address. */ + logtag = strtok(nil, "/"); /* Log tag. */ + if (logtag == nil) { + return; + } + if (logtag =~ "TCP") { + squid_client_http++; + } + if (logtag =~ "UDP") { + squid_icp_requests++; + } + if (logtag =~ "HIT") { + prxy_squid_cache_hits++; + } + if (logtag =~ "MISS") { + squid_cache_misses++; + } + + word = strtok(nil, " "); /* Reply code. */ + if (word == nil) { + return; + } + WWW_REPLY_CODE(word) + word = strtok(nil, " "); /* Size sent to client. */ + if (word == nil) { + return; + } + z = atoi(word); + WWW_SIZE_INDEX(z, size_index) + www_dwnld_time_by_size[size_index] += xf; + + request = strtok(nil, " "); /* Request method. */ + if (request == nil) { + return; + } + WWW_METHOD(request) + /* Do not add the size if it is a HEAD. */ + if (ishead == 0) { + dwnld_totalz += z; + } + + word = strtok(nil, " "); /* URL. */ + if (word == nil) { + return; + } + if (word =~ "cgi-bin") { + httpop_cgi_bins++; + } + if (word =~ www_search_url) { + httpop_searches++; + } + strtok(nil, " "); /* Optional user identity. */ + word = strtok(nil, "/"); /* Hierarchy. */ + if (word == nil) { + return; + } + if (word =~ "DIRECT") { + prxy_squid_indirect++; + } +#if 0 + word = strtok(nil, " "); /* Hostname. */ + if (word == nil) { + return; + } + word = strtok(nil, " "); /* Content-type. */ + if (word == nil) { + return; + } +#endif + +#elif WATCH_YAHOO + /* + * Yahoo log format. Fields in square brackets will only appear in the + * log file if the data actually exists (i.e. you will never see a null + * Referrer field). Further, fields labeled here with "(CONFIG)" will + * only appear if they are enabled via the YahooLogOptions configuration + * directive. + * + * IP Address (8 hex digits) + * Timestamp (time_t as 8 hex digits) + * Processing Time (in microseconds, as 8 hex digits) + * Bytes Sent (8 hex digits) + * URL + * [^Er referrer] (CONFIG) + * [^Em method] (CONFIG) + * [^Es status_code] + * ^Ed signature + * \n + */ + + /* + * Ignore the IP address and timestamp. Get the processing time, the + * number of bytes sent and the URL. For each portion of the line, split + * it up into separate pieces. + */ + if (sscanf(word, "%8lx%8lx%8x%8x", &tmp, &tmp, &ulong_xf, &z) != 4) { + return; + } + + xf = ulong_xf/1000000.0; + WWW_SIZE_INDEX(z, size_index) + www_dwnld_time_sum += xf; + www_dwnld_time_by_size[size_index] += xf; + + if (word =~ "cgi-bin") { + httpop_cgi_bins++; + } + if (word =~ www_search_url) { + httpop_searches++; + } + + for (;;) { + word = strtok(nil, "\05"); + if (word == nil) { + break; + } + first_byte = word; + ptr = &word + 1; + arg = ((string) ptr); + ptr = 0; + switch (first_byte[0]) { + case 'm': + WWW_METHOD(arg) + ptr = 1; + break; + case 's': + WWW_REPLY_CODE(arg) + break; + default: + break; + } + } + + /* If no method was seen, then assume it was a GET. */ + if (ptr == 0) { + httpop_gets++; + } + + /* Do not add the size if it is a HEAD. */ + if (ishead == 0) { + dwnld_totalz += z; + } + +#else /* common or Netscape proxy formats */ + strtok(nil, " "); /* -. */ + strtok(nil, " "); /* -. */ + strtok(nil, " ["); /* date. */ + strtok(nil, " "); /* zone]. */ + strtok(nil, " \""); /* GET or POST. */ + if (word == nil) { + return; + } + WWW_METHOD(word) + word = strtok(nil, " "); /* URL. */ + if (word == nil) { + return; + } + if (word =~ "cgi-bin") { + httpop_cgi_bins++; + } + if (word =~ www_search_url) { + httpop_searches++; + } + /* + * Sometimes HTTP/1.x is not listed in the access log. Skip it + * if it does exist. Load the error/success code. + */ + word = strtok(nil, " "); + if (word == nil) { + return; + } + if (word =~ "HTTP" || word =~ "http") { + word = strtok(nil, " "); + if (word == nil) { + return; + } + } + WWW_REPLY_CODE(word) + word = strtok(nil, " "); /* Bytes transferred. */ + if (word == nil) { + return; + } + z = atoi(word); + /* Do not add the size if it is a HEAD. */ + if (ishead == 0) { + dwnld_totalz += z; + } + WWW_SIZE_INDEX(z, size_index) +#ifdef WATCH_PROXY + strtok(nil, " "); /* Status from server. */ + strtok(nil, " "); /* Length from server. */ + strtok(nil, " "); /* Length from client POST. */ + strtok(nil, " "); /* Length POSTed to remote. */ + strtok(nil, " "); /* Client header request. */ + strtok(nil, " "); /* Proxy header response. */ + strtok(nil, " "); /* Proxy header request. */ + strtok(nil, " "); /* Server header response. */ + strtok(nil, " "); /* Transfer total seconds. */ + word = strtok(nil, " "); /* Route. */ + if (word == nil) { + return; + } + + /* - DIRECT PROXY(host.domain:port) SOCKS. */ + if (strncmp(word, "PROXY", 5) == 0 || + strncmp(word, "SOCKS", 5) == 0) { + prxy_squid_indirect++; + } + strtok(nil, " "); /* Client finish status. */ + strtok(nil, " "); /* Server finish status. */ + word = strtok(nil, " "); /* Cache finish status. */ + if (word == nil) { + return; + } + /* + * ERROR HOST-NOT-AVAILABLE = error or incomplete op + * WRITTEN REFRESHED CL-MISMATCH(content length mismatch) = cache_writes + * NO-CHECK UP-TO-DATE = cache_hits + * DO-NOT-CACHE NON-CACHEABLE = uncacheable + */ + switch(word) { + case "WRITTEN": + case "REFRESHED": + case "CL-MISMATCH": + prxy_cache_writes++; + break; + case "NO-CHECK": + case "UP-TO-DATE": + prxy_squid_cache_hits++; + break; + case "DO-NOT-CACHE": + case "NON-CACHEABLE": + prxy_uncacheable++; + break; + default: + break; + } + word = strtok(nil, " ["); /* [transfer total time x.xxx. */ + if (word == nil) { + return; + } + xf = atof(word); + www_dwnld_time_sum += xf; + www_dwnld_time_by_size[size_index] += xf; +#endif +#endif +} + +measure_web(long sleep_till) +{ + double lastops = 0.0; + char buf[BUFSIZ]; + int i; + long now; + long sleep_till_tmp; + + httpops = 0.0; + httpops5 = 0.0; + gateops = 0.0; + httpop_gets = 0; + httpop_condgets = 0; + httpop_posts = 0; + httpop_cgi_bins = 0; + httpop_errors = 0; + httpop_searches = 0; + + for (i=0; i<5; ++i) { + dwnld_size[i] = 0; +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + www_dwnld_time_by_size[i] = 0.0; +#endif + } + dwnld_totalz = 0; + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + www_dwnld_time_sum = 0.0; +#endif +#if WATCH_PROXY || WATCH_SQUID + prxy_squid_indirect = 0; + prxy_squid_cache_hits = 0; +#ifdef WATCH_PROXY + prxy_cache_writes = 0; + prxy_uncacheable = 0; +#else + squid_cache_misses = 0; + squid_icp_requests = 0; + squid_icp_queries = 0; + squid_client_http = 0; +#endif +#endif + + if (www_log_filename != nil) { + now = time(0); + while (now < sleep_till) { + if (now + 5 < sleep_till) { + sleep_till_tmp = now + 5; + } else { + sleep_till_tmp = sleep_till; + } +#ifdef WATCH_CPU + sleep_till_and_count_new_processes(sleep_till_tmp); +#else + orca_sleep_till(sleep_till_tmp); +#endif + + now = time(0); + if (www_log_fp != 0) { + buf[BUFSIZ-1] = 127; + while (fgets(buf, BUFSIZ, www_log_fp) != nil) { + httpops += 1.0; + if (www_gatelen > 0) { + if (strncmp(buf, www_gateway, www_gatelen) == 0) { + gateops += 1.0; + } + } + accesslog(buf); + + /* + * If the line is longer than the buffer, then ignore the rest + * of the line. + */ + while (buf[BUFSIZ-1] == 0 && + buf[BUFSIZ-2] != '\n') { + buf[BUFSIZ-1] = 127; + if (fgets(buf, BUFSIZ, www_log_fp) == nil) { + break; + } + } + } + } + + /* + * See if the file has been switched or truncated. + */ + if (stat(www_log_filename, www_log_stat) == 0) { + if (www_log_ino != www_log_stat[0].st_ino || + www_log_size > www_log_stat[0].st_size) { + /* + * Close the old log file and open the new one. + */ + if (www_log_fp != 0) { + fclose(www_log_fp); + } + + www_log_fp = fopen(www_log_filename, "r"); + if (www_log_fp != 0) { + fstat(fileno(www_log_fp), www_log_stat); + www_log_ino = www_log_stat[0].st_ino; + www_log_size = www_log_stat[0].st_size; + buf[BUFSIZ-1] = 127; + while(fgets(buf, BUFSIZ, www_log_fp) != nil) { + httpops += 1.0; + if (www_gatelen > 0) { + if (strncmp(buf, www_gateway, www_gatelen) == 0) { + gateops += 1.0; + } + } + accesslog(buf); + + /* + * If the line is longer than the buffer, then ignore + * the rest of the line. + */ + while (buf[BUFSIZ-1] == 0 && + buf[BUFSIZ-2] != '\n') { + buf[BUFSIZ-1] = 127; + if (fgets(buf, BUFSIZ, www_log_fp) == nil) { + break; + } + } + } + } else { + www_log_ino = 0; + www_log_size = 0; + } + } else { + /* + * Remember size for next time. + */ + www_log_size = www_log_stat[0].st_size; + } + } + + www5_now = gethrtime(); + www5_interval = (www5_now - www5_then) * 0.000000001; + www5_then = www5_now; + dtmp = (httpops - lastops)/www5_interval; + if (dtmp > httpops5) { + httpops5 = dtmp; + } + lastops = httpops; + } + } + else { + sleep_till_and_count_new_processes(sleep_till); + www5_now = gethrtime(); + } + + www_now = www5_now; + www_interval = (www_now - www_then) * 0.000000001; + www_then = www_now; + + /* + * Use dtmp to get percentages. + */ + if (httpops == 0.0) { + dtmp = 0.0; + } + else { + dtmp = 100.0 / httpops; + } + +#if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO + for (i=0; i<5; ++i) { + if (dwnld_size[i] == 0) { + www_dwnld_time_by_size[i] = 0.0; + } + else { + www_dwnld_time_by_size[i] = www_dwnld_time_by_size[i]/dwnld_size[i]; + } + } +#endif +} + +// Functions in SE cannot return an array, so to work around this, have +// count_procs place it's results in a global array. +#define MAX_COUNT_PROC_REGEXS 2 +int count_procs_results[MAX_COUNT_PROC_REGEXS]; +count_procs(int number_regexs, string regexs[]) +{ + psinfo_t p; + int i; + + if (number_regexs > MAX_COUNT_PROC_REGEXS) { + fprintf(stderr, "%s: too many regular expressions (%d). Increase MAX_COUNT_PROC_REGEXS.\n", + program_name, number_regexs); + exit(1); + } + + for (i=0; i -#include -#include -#include -#include -#include -#include -#include -#include - -#define PATH_TO_INST "/etc/path_to_inst" - -// sterr is not defined in kstat.se, so define here -kstat struct "sterr:" ks_sterr { - int number$; // linear counter - string name$; // name of error - int instance$; // instance number - - uint64_t "Soft Errors"; - uint64_t "Hard Errors"; - uint64_t "Transport Errors"; - string Vendor; - string Product; - string Revision; - string "Serial No"; -}; - -struct tape_info_t { - string short_name; - string long_name; - ks_sterr errors; -}; - -// this is a global array to keep similarity with diskinfo.se -// use functions provided below as access methods - -tape_info_t GLOBAL_tape_info[]; -int GLOBAL_tapeinfo_size = 1; -ulong_t GLOBAL_tapeinfo_short_tree; -ulong_t GLOBAL_tapeinfo_long_tree; - -int tapeinfo_inst_initialized; // set when data exists - -ks_sterr -find_tape_error(string name) -{ - ks_sterr sterr; - string short_name; - - if (name =~ "^st.*") { - sterr.number$ = 0; - for(refresh$(sterr); sterr.number$ != -1; sterr.number$++,refresh$(sterr)) { - short_name = sterr.name$; - strtok(short_name, ","); - if (short_name == name) { - break; - } - } - return sterr; - } -} - -int -setup_tapeinfo_inst() // return 1 if OK, 0 if not -{ - char buf[BUFSIZ]; - char points_at[MAXNAMELEN]; - string p; - string full; - string path; - string tape_dirs[2] = { "/dev/rmt", nil }; - int count = 0; - int i; - int n; - ulong ld; - ulong dirp; - ulong input; - dirent_t dp; - ulong_t path_tree; - ulong_t np; - - if (tapeinfo_inst_initialized == 1) { - return 1; - } - - path_tree = str2int_init(); - if (path_tree == 0) { - return 0; - } - - // load up the tree with the paths and quit traversing path_to_inst - input = fopen(PATH_TO_INST, "r"); - if (input == 0) { - avlfree(path_tree); - return 0; - } - while (fgets(buf, sizeof(buf), input) != nil) { - if ((buf[0] != '#') && (buf[0] != '\n')) { - p = strtok(buf, " "); - n = atoi(strtok(nil, " ")); - path = strtok(p, "\""); - - if (str2int_put(path_tree, path, n) == -1) { - fclose(input); - avlfree(path_tree); - return 0; - } - } - } - fclose(input); - - // create the global tape info array - GLOBAL_tape_info = new tape_info_t[GLOBAL_tapeinfo_size]; - - // scan /dev/rmt and insert tape entries - for (i=0; tape_dirs[i] != nil; i++) { - dirp = opendir(tape_dirs[i]); - if (dirp == 0) { - if (i > 0) { - // first is /dev/rmt - break; - } - avlfree(path_tree); - return 0; - } - - for (ld = readdir(dirp); ld != 0; ld = readdir(dirp)) { - // grow the array if needed - if (count == GLOBAL_tapeinfo_size) { - GLOBAL_tapeinfo_size += 1; - GLOBAL_tape_info = renew GLOBAL_tape_info[GLOBAL_tapeinfo_size]; - } - dp = *((dirent_t *) ld); - - // skip . and .. - if (dp.d_name == "." || dp.d_name == "..") { - continue; - } - - // skip everything but raw devices - if ( isdigit(dp.d_name[strlen(dp.d_name)-1]) == 0 ) { - continue; - } - - // read the link - full = sprintf("%s/%s", tape_dirs[i], dp.d_name); - - n = readlink(full, points_at, sizeof(points_at)); - if (n == -1) { - closedir(dirp); - avlfree(path_tree); - return 0; - } - points_at[n] = '\0'; - - // chop off the :a at the end - strcpy(strrchr(points_at, ':'), ""); - - // hack off ../../devices from the start - sscanf(points_at, "../../devices%s", &points_at); - - // hack off /dev/ from the start - // long name is the rmt/ - sscanf(full, "/dev/%s", &buf); - GLOBAL_tape_info[count].long_name = buf; - - GLOBAL_tape_info[count].short_name = nil; - - // construct the short name - if ((np = str2int_get(path_tree, points_at)) != 0) { - n = ((int) *((ulong_t *) np)); - p = strrchr(points_at, '/'); - p = strtok(p, "/"); - p = strtok(p, "@"); - GLOBAL_tape_info[count].short_name = sprintf("%s%d", p, n); - } - - // hard luck, can't find this device - if (GLOBAL_tape_info[count].short_name == nil) { - continue; - } - - // squirrel this away while we're at it - GLOBAL_tape_info[count].errors = - find_tape_error(GLOBAL_tape_info[count].short_name); - - count++; - } - closedir(dirp); - } - - // tree the names for fast lookup - GLOBAL_tapeinfo_short_tree = str2int_init(); - GLOBAL_tapeinfo_long_tree = str2int_init(); - if ((GLOBAL_tapeinfo_short_tree == 0) || (GLOBAL_tapeinfo_long_tree == 0)) { - return 0; - } - for(i=0; i= 0 && i < GLOBAL_tapeinfo_size) { - return GLOBAL_tape_info[i]; - } else { - no_info.short_name = name; - no_info.long_name = name; - return no_info; - } -} - -#endif +// +// 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 _TAPEINFO_SE_ +#define _TAPEINFO_SE_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PATH_TO_INST "/etc/path_to_inst" + +// sterr is not defined in kstat.se, so define here +kstat struct "sterr:" ks_sterr { + int number$; // linear counter + string name$; // name of error + int instance$; // instance number + + uint64_t "Soft Errors"; + uint64_t "Hard Errors"; + uint64_t "Transport Errors"; + string Vendor; + string Product; + string Revision; + string "Serial No"; +}; + +struct tape_info_t { + string short_name; + string long_name; + ks_sterr errors; +}; + +// this is a global array to keep similarity with diskinfo.se +// use functions provided below as access methods + +tape_info_t GLOBAL_tape_info[]; +int GLOBAL_tapeinfo_size = 1; +ulong_t GLOBAL_tapeinfo_short_tree; +ulong_t GLOBAL_tapeinfo_long_tree; + +int tapeinfo_inst_initialized; // set when data exists + +ks_sterr +find_tape_error(string name) +{ + ks_sterr sterr; + string short_name; + + if (name =~ "^st.*") { + sterr.number$ = 0; + for(refresh$(sterr); sterr.number$ != -1; sterr.number$++,refresh$(sterr)) { + short_name = sterr.name$; + strtok(short_name, ","); + if (short_name == name) { + break; + } + } + return sterr; + } +} + +int +setup_tapeinfo_inst() // return 1 if OK, 0 if not +{ + char buf[BUFSIZ]; + char points_at[MAXNAMELEN]; + string p; + string full; + string path; + string tape_dirs[2] = { "/dev/rmt", nil }; + int count = 0; + int i; + int n; + ulong ld; + ulong dirp; + ulong input; + dirent_t dp; + ulong_t path_tree; + ulong_t np; + + if (tapeinfo_inst_initialized == 1) { + return 1; + } + + path_tree = str2int_init(); + if (path_tree == 0) { + return 0; + } + + // load up the tree with the paths and quit traversing path_to_inst + input = fopen(PATH_TO_INST, "r"); + if (input == 0) { + avlfree(path_tree); + return 0; + } + while (fgets(buf, sizeof(buf), input) != nil) { + if ((buf[0] != '#') && (buf[0] != '\n')) { + p = strtok(buf, " "); + n = atoi(strtok(nil, " ")); + path = strtok(p, "\""); + + if (str2int_put(path_tree, path, n) == -1) { + fclose(input); + avlfree(path_tree); + return 0; + } + } + } + fclose(input); + + // create the global tape info array + GLOBAL_tape_info = new tape_info_t[GLOBAL_tapeinfo_size]; + + // scan /dev/rmt and insert tape entries + for (i=0; tape_dirs[i] != nil; i++) { + dirp = opendir(tape_dirs[i]); + if (dirp == 0) { + if (i > 0) { + // first is /dev/rmt + break; + } + avlfree(path_tree); + return 0; + } + + for (ld = readdir(dirp); ld != 0; ld = readdir(dirp)) { + // grow the array if needed + if (count == GLOBAL_tapeinfo_size) { + GLOBAL_tapeinfo_size += 1; + GLOBAL_tape_info = renew GLOBAL_tape_info[GLOBAL_tapeinfo_size]; + } + dp = *((dirent_t *) ld); + + // skip . and .. + if (dp.d_name == "." || dp.d_name == "..") { + continue; + } + + // skip everything but raw devices + if ( isdigit(dp.d_name[strlen(dp.d_name)-1]) == 0 ) { + continue; + } + + // read the link + full = sprintf("%s/%s", tape_dirs[i], dp.d_name); + + n = readlink(full, points_at, sizeof(points_at)); + if (n == -1) { + closedir(dirp); + avlfree(path_tree); + return 0; + } + points_at[n] = '\0'; + + // chop off the :a at the end + strcpy(strrchr(points_at, ':'), ""); + + // hack off ../../devices from the start + sscanf(points_at, "../../devices%s", &points_at); + + // hack off /dev/ from the start + // long name is the rmt/ + sscanf(full, "/dev/%s", &buf); + GLOBAL_tape_info[count].long_name = buf; + + GLOBAL_tape_info[count].short_name = nil; + + // construct the short name + if ((np = str2int_get(path_tree, points_at)) != 0) { + n = ((int) *((ulong_t *) np)); + p = strrchr(points_at, '/'); + p = strtok(p, "/"); + p = strtok(p, "@"); + GLOBAL_tape_info[count].short_name = sprintf("%s%d", p, n); + } + + // hard luck, can't find this device + if (GLOBAL_tape_info[count].short_name == nil) { + continue; + } + + // squirrel this away while we're at it + GLOBAL_tape_info[count].errors = + find_tape_error(GLOBAL_tape_info[count].short_name); + + count++; + } + closedir(dirp); + } + + // tree the names for fast lookup + GLOBAL_tapeinfo_short_tree = str2int_init(); + GLOBAL_tapeinfo_long_tree = str2int_init(); + if ((GLOBAL_tapeinfo_short_tree == 0) || (GLOBAL_tapeinfo_long_tree == 0)) { + return 0; + } + for(i=0; i= 0 && i < GLOBAL_tapeinfo_size) { + return GLOBAL_tape_info[i]; + } else { + no_info.short_name = name; + no_info.long_name = name; + return no_info; + } +} + +#endif From dmberezin at hotmail.com Fri Sep 10 11:20:32 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Fri, 10 Sep 2004 11:20:32 -0700 Subject: [Orca-checkins] r389 - trunk/orca/data_gatherers/orcallator Message-ID: <200409101820.i8AIKW2Q027776@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Fri Sep 10 11:18:32 2004 New Revision: 389 Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: One more fix for orca_io_info_update: removed unnecessary kstat function calls fixed some comments Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Fri Sep 10 11:18:32 2004 @@ -348,7 +348,6 @@ int index; ulong ul; kstat_ctl_t kc[1]; - kstat_t kp[1]; kstat_t nkp[1]; kstat_io_t kio; @@ -357,28 +356,22 @@ double elapsed_etime; double hz_etime; + // Initialize kstat control structure kc[0] = kstat_open(); - // Read them. - if (kstat_read(kc, kp, 0) == -1) { - perror("orca_io_info_update:kstat_read"); - exit(1); - } - // Traverse the chain looking for IO events. - for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { + for (ul=kc[0].kc_chain; ul!=0; ul=nkp[0].ks_next) { struct_fill(nkp[0], ul); if (nkp[0].ks_type == KSTAT_TYPE_IO) { // Look for disk or tape statistics if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { - // Update the device registers. + // Get data from the kernel for this kstat if (kstat_read(kc, nkp, 0) == -1) { perror("orca_io_info_update:kstat_read error"); exit(1); } - // Read sys_kstat device IO queue to find out about recent activity. struct_fill(kio, nkp[0].ks_data); - // Try to locate device. + // Try to locate device in our array for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { break; From dmberezin at hotmail.com Tue Sep 14 09:31:45 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Tue, 14 Sep 2004 09:31:45 -0700 Subject: [Orca-checkins] r390 - in trunk/orca: data_gatherers/orcallator lib/SE/3.3.1 Message-ID: <200409141631.i8EGVjqI027478@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Tue Sep 14 09:26:29 2004 New Revision: 390 Removed: trunk/orca/lib/SE/3.3.1/tapeinfo.se Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: * data_gatherers/orcallator/orcallator.se * lib/SE/3.3.1/tapeinfo.se Revert previous commits, which had files with Windows end-of-line endings, back to revision 385. Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Tue Sep 14 09:26:29 2004 @@ -23,8 +23,8 @@ // The maximum number of columns of data. #define MAX_COLUMNS 2048 -// Enable kstat io measuring code. -#define USE_KSTAT_IO 1 +// Enable the raw disk measuring code. +#define USE_RAWDISK 1 // If WATCH_OS is defined, then measure every part of the operating // system. @@ -297,9 +297,8 @@ #endif -#ifdef USE_KSTAT_IO +#ifdef USE_RAWDISK #include -#include // This code was developed so that the performance of virtual disks // originating from a Sun A1000 raid controller could be monitored. // These disks do not show up in the GLOBAL_disk[] io structure of SE. @@ -307,11 +306,10 @@ // This extension accesses the sys_kstat.se interface to the kstat IO // queues to extract info on drives not available in the kstat.se // kstat$disk interface. Global data shared between function calls. -struct io_dev_info_t { +struct RawDisk { // Exposed interface that matches kstat. - string dev_class; - string long_name; - string short_name; + char long_name[48]; + char short_name[8]; double reads; double kreads; double writes; @@ -339,128 +337,293 @@ }; // Define global for tracking raw disk data. -io_dev_info_t ORCA_io_dev_info[]; -int ORCA_io_dev_count=0; -int ORCA_max_io_dev_count=0; - -orca_io_info_update() { - int iodev; - int index; - ulong ul; - kstat_ctl_t kc[1]; - kstat_t nkp[1]; - kstat_io_t kio; - - double read_writes; - double big_etime; - double elapsed_etime; - double hz_etime; +#ifndef MAX_RAWDISKS +#define MAX_RAWDISKS 1024 +#endif + +RawDisk RAW_disk[MAX_RAWDISKS]; +int RAW_disk_map=0; +int RAW_disk_count=0; +double RAW_disk_lastupdate; + +// Compare two short disk names and return if they have on the same +// physical device name, ignoring slice info. +int raw_disk_short_name_cmp(char disk1[], + int disk1_length, + char disk2[], + int disk2_length) +{ + int i; + + // Handle dad disks first since they do not have commas. + if (strncmp("dad", disk1, 3) == 0) { + return strncmp(disk1, disk2, disk1_length); + } + + // Extract the physical disk name from disk slices. This only works + // with SCSI disks where slices have commma separators. + for (i=0; i 1) { + strcpy(second_name, GLOBAL_disk_info[1].short_name); + second_name_length = strlen(second_name); + } + for (i=0; i 0) { + short_name_length = strlen(short_name); + if (raw_disk_short_name_cmp(first_name, + first_name_length, + short_name, + short_name_length) == 0) { + break; + } + if (j > 1) { + if (raw_disk_short_name_cmp(second_name, + second_name_length, + short_name, + short_name_length) == 0) { + break; + } + } + } + if (strcmp(RAW_disk[i].short_name, short_name) == 0) { + strcpy(long_name, GLOBAL_disk_info[j].long_name); + strcpy(RAW_disk[i].long_name, long_name); + break; + } + } + } + } + RAW_disk_map = 0; +} + +raw_disk_update() { + int rdisk; + ulong ul; + kstat_ctl_t kc[1]; + kstat_t kp[1]; + kstat_t nkp[1]; + kstat_io_t kio; + ulonglong _nread; + ulonglong _nwritten; + uint _reads; + uint _writes; + longlong _wtime; + longlong _wlentime; + longlong _wlastupdate; + longlong _rtime; + longlong _rlentime; + longlong _rlastupdate; + longlong _wcnt; + longlong _rcnt; + + double read_writes; + double big_etime; + double elapsed_etime; + double hz_etime; + double nanosecond = NANOSEC; + double update; + double delta; + timeval_t time_update[1]; + ulong time_void; + char short_name[8]; + + gettimeofday(time_update, time_void); + update = time_update[0].tv_sec + (time_update[0].tv_usec / 1000000.0); + delta = update - RAW_disk_lastupdate; + RAW_disk_lastupdate = update; - // Initialize kstat control structure kc[0] = kstat_open(); + // Read them. + if (kstat_read(kc, kp, 0) == -1) { + perror("raw_disk_update:kstat_read"); + exit(1); + } + // Traverse the chain looking for IO events. - for (ul=kc[0].kc_chain; ul!=0; ul=nkp[0].ks_next) { + for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { struct_fill(nkp[0], ul); if (nkp[0].ks_type == KSTAT_TYPE_IO) { - // Look for disk or tape statistics - if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { - // Get data from the kernel for this kstat - if (kstat_read(kc, nkp, 0) == -1) { - perror("orca_io_info_update:kstat_read error"); - exit(1); - } - struct_fill(kio, nkp[0].ks_data); - - // Try to locate device in our array - for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { - if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { + strcpy(short_name, nkp[0].ks_name); + if (short_name[0] != 'm' && + short_name[0] != 'n' && + strchr(short_name,',') == nil) { + // Try to locate device. + for (rdisk=0; rdisk _nread) { + _nread = RAW_disk[rdisk]._nread; + } + _reads = kio.reads; + if (RAW_disk[rdisk]._reads > _reads) { + _reads = RAW_disk[rdisk]._reads; + } + _rlentime = kio.rlentime; + _rtime = kio.rtime; + _rlastupdate = kio.wlastupdate; + _rcnt = kio.rcnt; + _nwritten = kio.nwritten; + if (RAW_disk[rdisk]._nwritten > _nwritten) { + _nwritten = RAW_disk[rdisk]._nwritten; + } + _writes = kio.writes; + if (RAW_disk[rdisk]._writes > _writes) { + _writes = RAW_disk[rdisk]._nwritten; + } + _wlentime = kio.wlentime; + _wtime = kio.wtime; + _wlastupdate = kio.wlastupdate; + _wcnt = kio.wcnt; + + elapsed_etime = (_wlastupdate - RAW_disk[rdisk]._wlastupdate); + if (elapsed_etime > 0) { + hz_etime = elapsed_etime / nanosecond; + big_etime = 1024.0 * hz_etime; } else { - index = find_inst(nkp[0].ks_name); + elapsed_etime = nanosecond; + hz_etime = 1.0; + big_etime = 1024.0; } - if (index != -1) { - if (nkp[0].ks_class == "tape") { - ORCA_io_dev_info[iodev].long_name = GLOBAL_tape_info[index].long_name; - } else { - ORCA_io_dev_info[iodev].long_name = GLOBAL_disk_info[index].long_name; - } + RAW_disk[rdisk].reads =(_reads-RAW_disk[rdisk]._reads) /hz_etime; + RAW_disk[rdisk].kreads =(_nread-RAW_disk[rdisk]._nread) /big_etime; + RAW_disk[rdisk].writes =(_writes-RAW_disk[rdisk]._writes)/hz_etime; + RAW_disk[rdisk].kwrites=(_nwritten-RAW_disk[rdisk]._nwritten) / big_etime; + + read_writes = elapsed_etime * (RAW_disk[rdisk].reads + RAW_disk[rdisk].writes) / 1024.0; + if (read_writes > 0) { + RAW_disk[rdisk].avg_wait = (_wlentime - RAW_disk[rdisk]._wlentime) / read_writes; + RAW_disk[rdisk].avg_serv = (_rlentime - RAW_disk[rdisk]._rlentime) / read_writes; + RAW_disk[rdisk].service = RAW_disk[rdisk].avg_wait + RAW_disk[rdisk].avg_serv; } else { - ORCA_io_dev_info[iodev].long_name = nkp[0].ks_name; + RAW_disk[rdisk].avg_wait = 0.0; + RAW_disk[rdisk].avg_serv = 0.0; + RAW_disk[rdisk].service = 0.0; } - ORCA_io_dev_info[iodev].short_name = nkp[0].ks_name; - ORCA_io_dev_info[iodev]._writes = kio.writes; - ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; - ORCA_io_dev_info[iodev]._wlastupdate = kio.wlastupdate; - ORCA_io_dev_info[iodev]._wlentime = kio.wlentime; - ORCA_io_dev_info[iodev]._wtime = kio.wtime; - ORCA_io_dev_info[iodev]._wcnt = kio.wcnt; - ORCA_io_dev_info[iodev]._reads = kio.reads; - ORCA_io_dev_info[iodev]._nread = kio.nread; - ORCA_io_dev_info[iodev]._rlastupdate = kio.rlastupdate; - ORCA_io_dev_info[iodev]._rlentime = kio.rlentime; - ORCA_io_dev_info[iodev]._rtime = kio.rtime; - ORCA_io_dev_info[iodev]._rcnt = kio.rcnt; - ORCA_io_dev_count++; + // Update the counters. + RAW_disk[rdisk].run_percent = 100.0 * (_rtime - RAW_disk[rdisk]._rtime) / elapsed_etime; + RAW_disk[rdisk].wait_percent = 100.0 * (_wtime - RAW_disk[rdisk]._wtime) / elapsed_etime; + RAW_disk[rdisk]._writes = _writes; + RAW_disk[rdisk]._nwritten = _nwritten; + RAW_disk[rdisk]._wlastupdate = _wlastupdate; + RAW_disk[rdisk]._wlentime = _wlentime; + RAW_disk[rdisk]._wtime = _wtime; + RAW_disk[rdisk]._wcnt = _wcnt; + RAW_disk[rdisk]._reads = _reads; + RAW_disk[rdisk]._nread = _nread; + RAW_disk[rdisk]._rlastupdate = _rlastupdate; + RAW_disk[rdisk]._rlentime = _rlentime; + RAW_disk[rdisk]._rtime = _rtime; + RAW_disk[rdisk]._rcnt = _rcnt; } - - elapsed_etime = (kio.wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); - if (elapsed_etime == 0) { - elapsed_etime = NANOSEC; - } - hz_etime = elapsed_etime / NANOSEC; - big_etime = 1024.0 * hz_etime; - - ORCA_io_dev_info[iodev].reads =(kio.reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; - ORCA_io_dev_info[iodev].kreads =(kio.nread-ORCA_io_dev_info[iodev]._nread) /big_etime; - ORCA_io_dev_info[iodev].writes =(kio.writes-ORCA_io_dev_info[iodev]._writes) /hz_etime; - ORCA_io_dev_info[iodev].kwrites=(kio.nwritten-ORCA_io_dev_info[iodev]._nwritten)/big_etime; - - read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; - if (read_writes > 0) { - ORCA_io_dev_info[iodev].avg_wait = (kio.wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; - ORCA_io_dev_info[iodev].avg_serv = (kio.rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; - ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; - } else { - ORCA_io_dev_info[iodev].avg_wait = 0.0; - ORCA_io_dev_info[iodev].avg_serv = 0.0; - ORCA_io_dev_info[iodev].service = 0.0; - } - - // Update the counters. - ORCA_io_dev_info[iodev].run_percent = 100.0 * (kio.rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; - ORCA_io_dev_info[iodev].wait_percent = 100.0 * (kio.wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; - ORCA_io_dev_info[iodev]._writes = kio.writes; - ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; - ORCA_io_dev_info[iodev]._wlastupdate = kio.wlastupdate; - ORCA_io_dev_info[iodev]._wlentime = kio.wlentime; - ORCA_io_dev_info[iodev]._wtime = kio.wtime; - ORCA_io_dev_info[iodev]._wcnt = kio.wcnt; - ORCA_io_dev_info[iodev]._reads = kio.reads; - ORCA_io_dev_info[iodev]._nread = kio.nread; - ORCA_io_dev_info[iodev]._rlastupdate = kio.rlastupdate; - ORCA_io_dev_info[iodev]._rlentime = kio.rlentime; - ORCA_io_dev_info[iodev]._rtime = kio.rtime; - ORCA_io_dev_info[iodev]._rcnt = kio.rcnt; } } } kstat_close(kc); + + // Map long device names for any drives that we just discovered. + if (RAW_disk_map == 1) { + raw_disk_map(); + } } -#endif // USE_KSTAT_IO +#endif +// RAWDISK // Variables for handling output. string compress = getenv("COMPRESSOR"); // How to compress logs. @@ -862,8 +1025,8 @@ tmp_tcp = tcp$tcp; #endif -#ifdef USE_KSTAT_IO - orca_io_info_update(); +#ifdef USE_RAWDISK + raw_disk_update(); #endif } @@ -1435,29 +1598,29 @@ total_tape_writek = 0.0; tape_count = 0; -#ifdef USE_KSTAT_IO - for (i=0; i. Check // [wr]lentime to see if an EMC is using a fake disk for control. @@ -1474,13 +1637,13 @@ #ifdef HAVE_EMC_DISK_CONTROL if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { #endif - total_disk_reads += ORCA_io_dev_info[i].reads; - total_disk_writes += ORCA_io_dev_info[i].writes; - total_disk_readk += ORCA_io_dev_info[i].kreads; - total_disk_writek += ORCA_io_dev_info[i].kwrites; - mean_disk_busy += ORCA_io_dev_info[i].run_percent; - if (ORCA_io_dev_info[i].run_percent > peak_disk_busy) { - peak_disk_busy = ORCA_io_dev_info[i].run_percent; + total_disk_reads += RAW_disk[i].reads; + total_disk_writes += RAW_disk[i].writes; + total_disk_readk += RAW_disk[i].kreads; + total_disk_writek += RAW_disk[i].kwrites; + mean_disk_busy += RAW_disk[i].run_percent; + if (RAW_disk[i].run_percent > peak_disk_busy) { + peak_disk_busy = RAW_disk[i].run_percent; } #ifdef HAVE_EMC_DISK_CONTROL } From dmberezin at hotmail.com Tue Sep 14 11:28:56 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Tue, 14 Sep 2004 11:28:56 -0700 Subject: [Orca-checkins] r391 - in trunk/orca: data_gatherers/orcallator lib/SE/3.3.1 Message-ID: <200409141828.i8EISuLk030087@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Tue Sep 14 11:27:02 2004 New Revision: 391 Added: trunk/orca/lib/SE/3.3.1/tapeinfo.se Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: The first update to the disk/tape data collection on Solaris. * lib/SE/3.3.1/tapeinfo.se New file, based on diskinfo.se that is included in SE Toolkit. * data_gatherers/orcallator/orcallator.se Naming conventions are changed from RAW_disk to KSTAT_IO Static RAW_disk array is replaced by dynamic ORCA_io_dev_info array (struct RawDisk): Renamed to struct io_dev_info_t (raw_disk_update): Renamed to orca_io_info_update (struct io_dev_info_t): long_name and short_name are now strings, thus dynamic (orca_io_info_update): Removed some unused variables: update delta time_update time_void short_name (raw_disk_short_name_cmp and raw_disk_map): Removed. Replaced by name lookup using find_inst Added tape long name mapping (stxxx is being mapped to rmt/xx) support. This requires tapeinfo.se (modified version of diskinfo.se) The following global variables are removed: RAW_disk_map RAW_disk_count RAW_disk_lastupdate Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Tue Sep 14 11:27:02 2004 @@ -23,8 +23,8 @@ // The maximum number of columns of data. #define MAX_COLUMNS 2048 -// Enable the raw disk measuring code. -#define USE_RAWDISK 1 +// Enable kstat io measuring code. +#define USE_KSTAT_IO 1 // If WATCH_OS is defined, then measure every part of the operating // system. @@ -297,8 +297,9 @@ #endif -#ifdef USE_RAWDISK +#ifdef USE_KSTAT_IO #include +#include // This code was developed so that the performance of virtual disks // originating from a Sun A1000 raid controller could be monitored. // These disks do not show up in the GLOBAL_disk[] io structure of SE. @@ -306,10 +307,10 @@ // This extension accesses the sys_kstat.se interface to the kstat IO // queues to extract info on drives not available in the kstat.se // kstat$disk interface. Global data shared between function calls. -struct RawDisk { +struct io_dev_info_t { // Exposed interface that matches kstat. - char long_name[48]; - char short_name[8]; + string long_name; + string short_name; double reads; double kreads; double writes; @@ -337,124 +338,13 @@ }; // Define global for tracking raw disk data. -#ifndef MAX_RAWDISKS -#define MAX_RAWDISKS 1024 -#endif - -RawDisk RAW_disk[MAX_RAWDISKS]; -int RAW_disk_map=0; -int RAW_disk_count=0; -double RAW_disk_lastupdate; - -// Compare two short disk names and return if they have on the same -// physical device name, ignoring slice info. -int raw_disk_short_name_cmp(char disk1[], - int disk1_length, - char disk2[], - int disk2_length) -{ - int i; - - // Handle dad disks first since they do not have commas. - if (strncmp("dad", disk1, 3) == 0) { - return strncmp(disk1, disk2, disk1_length); - } - - // Extract the physical disk name from disk slices. This only works - // with SCSI disks where slices have commma separators. - for (i=0; i 1) { - strcpy(second_name, GLOBAL_disk_info[1].short_name); - second_name_length = strlen(second_name); - } - for (i=0; i 0) { - short_name_length = strlen(short_name); - if (raw_disk_short_name_cmp(first_name, - first_name_length, - short_name, - short_name_length) == 0) { - break; - } - if (j > 1) { - if (raw_disk_short_name_cmp(second_name, - second_name_length, - short_name, - short_name_length) == 0) { - break; - } - } - } - if (strcmp(RAW_disk[i].short_name, short_name) == 0) { - strcpy(long_name, GLOBAL_disk_info[j].long_name); - strcpy(RAW_disk[i].long_name, long_name); - break; - } - } - } - } - RAW_disk_map = 0; -} - -raw_disk_update() { - int rdisk; +io_dev_info_t ORCA_io_dev_info[]; +int ORCA_io_dev_count=0; +int ORCA_max_io_dev_count=0; + +orca_io_info_update() { + int iodev; + int index; ulong ul; kstat_ctl_t kc[1]; kstat_t kp[1]; @@ -478,21 +368,11 @@ double elapsed_etime; double hz_etime; double nanosecond = NANOSEC; - double update; - double delta; - timeval_t time_update[1]; - ulong time_void; - char short_name[8]; - - gettimeofday(time_update, time_void); - update = time_update[0].tv_sec + (time_update[0].tv_usec / 1000000.0); - delta = update - RAW_disk_lastupdate; - RAW_disk_lastupdate = update; kc[0] = kstat_open(); // Read them. if (kstat_read(kc, kp, 0) == -1) { - perror("raw_disk_update:kstat_read"); + perror("orca_io_info_update:kstat_read"); exit(1); } @@ -500,40 +380,55 @@ for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { struct_fill(nkp[0], ul); if (nkp[0].ks_type == KSTAT_TYPE_IO) { - strcpy(short_name, nkp[0].ks_name); - if (short_name[0] != 'm' && - short_name[0] != 'n' && - strchr(short_name,',') == nil) { + // Look for disk or tape statistics + if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { // Try to locate device. - for (rdisk=0; rdisk _nread) { - _nread = RAW_disk[rdisk]._nread; + if (ORCA_io_dev_info[iodev]._nread > _nread) { + _nread = ORCA_io_dev_info[iodev]._nread; } _reads = kio.reads; - if (RAW_disk[rdisk]._reads > _reads) { - _reads = RAW_disk[rdisk]._reads; + if (ORCA_io_dev_info[iodev]._reads > _reads) { + _reads = ORCA_io_dev_info[iodev]._reads; } _rlentime = kio.rlentime; _rtime = kio.rtime; _rlastupdate = kio.wlastupdate; _rcnt = kio.rcnt; _nwritten = kio.nwritten; - if (RAW_disk[rdisk]._nwritten > _nwritten) { - _nwritten = RAW_disk[rdisk]._nwritten; + if (ORCA_io_dev_info[iodev]._nwritten > _nwritten) { + _nwritten = ORCA_io_dev_info[iodev]._nwritten; } _writes = kio.writes; - if (RAW_disk[rdisk]._writes > _writes) { - _writes = RAW_disk[rdisk]._nwritten; + if (ORCA_io_dev_info[iodev]._writes > _writes) { + _writes = ORCA_io_dev_info[iodev]._nwritten; } _wlentime = kio.wlentime; _wtime = kio.wtime; _wlastupdate = kio.wlastupdate; _wcnt = kio.wcnt; - elapsed_etime = (_wlastupdate - RAW_disk[rdisk]._wlastupdate); + elapsed_etime = (_wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); if (elapsed_etime > 0) { hz_etime = elapsed_etime / nanosecond; big_etime = 1024.0 * hz_etime; @@ -580,50 +476,44 @@ hz_etime = 1.0; big_etime = 1024.0; } - RAW_disk[rdisk].reads =(_reads-RAW_disk[rdisk]._reads) /hz_etime; - RAW_disk[rdisk].kreads =(_nread-RAW_disk[rdisk]._nread) /big_etime; - RAW_disk[rdisk].writes =(_writes-RAW_disk[rdisk]._writes)/hz_etime; - RAW_disk[rdisk].kwrites=(_nwritten-RAW_disk[rdisk]._nwritten) / big_etime; + ORCA_io_dev_info[iodev].reads =(_reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; + ORCA_io_dev_info[iodev].kreads =(_nread-ORCA_io_dev_info[iodev]._nread) /big_etime; + ORCA_io_dev_info[iodev].writes =(_writes-ORCA_io_dev_info[iodev]._writes)/hz_etime; + ORCA_io_dev_info[iodev].kwrites=(_nwritten-ORCA_io_dev_info[iodev]._nwritten) / big_etime; - read_writes = elapsed_etime * (RAW_disk[rdisk].reads + RAW_disk[rdisk].writes) / 1024.0; + read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; if (read_writes > 0) { - RAW_disk[rdisk].avg_wait = (_wlentime - RAW_disk[rdisk]._wlentime) / read_writes; - RAW_disk[rdisk].avg_serv = (_rlentime - RAW_disk[rdisk]._rlentime) / read_writes; - RAW_disk[rdisk].service = RAW_disk[rdisk].avg_wait + RAW_disk[rdisk].avg_serv; + ORCA_io_dev_info[iodev].avg_wait = (_wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; + ORCA_io_dev_info[iodev].avg_serv = (_rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; + ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; } else { - RAW_disk[rdisk].avg_wait = 0.0; - RAW_disk[rdisk].avg_serv = 0.0; - RAW_disk[rdisk].service = 0.0; + ORCA_io_dev_info[iodev].avg_wait = 0.0; + ORCA_io_dev_info[iodev].avg_serv = 0.0; + ORCA_io_dev_info[iodev].service = 0.0; } // Update the counters. - RAW_disk[rdisk].run_percent = 100.0 * (_rtime - RAW_disk[rdisk]._rtime) / elapsed_etime; - RAW_disk[rdisk].wait_percent = 100.0 * (_wtime - RAW_disk[rdisk]._wtime) / elapsed_etime; - RAW_disk[rdisk]._writes = _writes; - RAW_disk[rdisk]._nwritten = _nwritten; - RAW_disk[rdisk]._wlastupdate = _wlastupdate; - RAW_disk[rdisk]._wlentime = _wlentime; - RAW_disk[rdisk]._wtime = _wtime; - RAW_disk[rdisk]._wcnt = _wcnt; - RAW_disk[rdisk]._reads = _reads; - RAW_disk[rdisk]._nread = _nread; - RAW_disk[rdisk]._rlastupdate = _rlastupdate; - RAW_disk[rdisk]._rlentime = _rlentime; - RAW_disk[rdisk]._rtime = _rtime; - RAW_disk[rdisk]._rcnt = _rcnt; + ORCA_io_dev_info[iodev].run_percent = 100.0 * (_rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; + ORCA_io_dev_info[iodev].wait_percent = 100.0 * (_wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; + ORCA_io_dev_info[iodev]._writes = _writes; + ORCA_io_dev_info[iodev]._nwritten = _nwritten; + ORCA_io_dev_info[iodev]._wlastupdate = _wlastupdate; + ORCA_io_dev_info[iodev]._wlentime = _wlentime; + ORCA_io_dev_info[iodev]._wtime = _wtime; + ORCA_io_dev_info[iodev]._wcnt = _wcnt; + ORCA_io_dev_info[iodev]._reads = _reads; + ORCA_io_dev_info[iodev]._nread = _nread; + ORCA_io_dev_info[iodev]._rlastupdate = _rlastupdate; + ORCA_io_dev_info[iodev]._rlentime = _rlentime; + ORCA_io_dev_info[iodev]._rtime = _rtime; + ORCA_io_dev_info[iodev]._rcnt = _rcnt; } } } } kstat_close(kc); - - // Map long device names for any drives that we just discovered. - if (RAW_disk_map == 1) { - raw_disk_map(); - } } -#endif -// RAWDISK +#endif // USE_KSTAT_IO // Variables for handling output. string compress = getenv("COMPRESSOR"); // How to compress logs. @@ -1025,8 +915,8 @@ tmp_tcp = tcp$tcp; #endif -#ifdef USE_RAWDISK - raw_disk_update(); +#ifdef USE_KSTAT_IO + orca_io_info_update(); #endif } @@ -1598,29 +1488,29 @@ total_tape_writek = 0.0; tape_count = 0; -#ifdef USE_RAWDISK - for (i=0; i. Check // [wr]lentime to see if an EMC is using a fake disk for control. @@ -1637,13 +1527,13 @@ #ifdef HAVE_EMC_DISK_CONTROL if ((pioGLOB_old_wlentime[i] + pioGLOB_old_rlentime[i]) > 1) { #endif - total_disk_reads += RAW_disk[i].reads; - total_disk_writes += RAW_disk[i].writes; - total_disk_readk += RAW_disk[i].kreads; - total_disk_writek += RAW_disk[i].kwrites; - mean_disk_busy += RAW_disk[i].run_percent; - if (RAW_disk[i].run_percent > peak_disk_busy) { - peak_disk_busy = RAW_disk[i].run_percent; + total_disk_reads += ORCA_io_dev_info[i].reads; + total_disk_writes += ORCA_io_dev_info[i].writes; + total_disk_readk += ORCA_io_dev_info[i].kreads; + total_disk_writek += ORCA_io_dev_info[i].kwrites; + mean_disk_busy += ORCA_io_dev_info[i].run_percent; + if (ORCA_io_dev_info[i].run_percent > peak_disk_busy) { + peak_disk_busy = ORCA_io_dev_info[i].run_percent; } #ifdef HAVE_EMC_DISK_CONTROL } Added: trunk/orca/lib/SE/3.3.1/tapeinfo.se ============================================================================== --- (empty file) +++ trunk/orca/lib/SE/3.3.1/tapeinfo.se Tue Sep 14 11:27:02 2004 @@ -0,0 +1,277 @@ +// +// 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 _TAPEINFO_SE_ +#define _TAPEINFO_SE_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PATH_TO_INST "/etc/path_to_inst" + +// sterr is not defined in kstat.se, so define here +kstat struct "sterr:" ks_sterr { + int number$; // linear counter + string name$; // name of error + int instance$; // instance number + + uint64_t "Soft Errors"; + uint64_t "Hard Errors"; + uint64_t "Transport Errors"; + string Vendor; + string Product; + string Revision; + string "Serial No"; +}; + +struct tape_info_t { + string short_name; + string long_name; + ks_sterr errors; +}; + +// this is a global array to keep similarity with diskinfo.se +// use functions provided below as access methods + +tape_info_t GLOBAL_tape_info[]; +int GLOBAL_tapeinfo_size = 1; +ulong_t GLOBAL_tapeinfo_short_tree; +ulong_t GLOBAL_tapeinfo_long_tree; + +int tapeinfo_inst_initialized; // set when data exists + +ks_sterr +find_tape_error(string name) +{ + ks_sterr sterr; + string short_name; + + if (name =~ "^st.*") { + sterr.number$ = 0; + for(refresh$(sterr); sterr.number$ != -1; sterr.number$++,refresh$(sterr)) { + short_name = sterr.name$; + strtok(short_name, ","); + if (short_name == name) { + break; + } + } + return sterr; + } +} + +int +setup_tapeinfo_inst() // return 1 if OK, 0 if not +{ + char buf[BUFSIZ]; + char points_at[MAXNAMELEN]; + string p; + string full; + string path; + string tape_dirs[2] = { "/dev/rmt", nil }; + int count = 0; + int i; + int n; + ulong ld; + ulong dirp; + ulong input; + dirent_t dp; + ulong_t path_tree; + ulong_t np; + + if (tapeinfo_inst_initialized == 1) { + return 1; + } + + path_tree = str2int_init(); + if (path_tree == 0) { + return 0; + } + + // load up the tree with the paths and quit traversing path_to_inst + input = fopen(PATH_TO_INST, "r"); + if (input == 0) { + avlfree(path_tree); + return 0; + } + while (fgets(buf, sizeof(buf), input) != nil) { + if ((buf[0] != '#') && (buf[0] != '\n')) { + p = strtok(buf, " "); + n = atoi(strtok(nil, " ")); + path = strtok(p, "\""); + + if (str2int_put(path_tree, path, n) == -1) { + fclose(input); + avlfree(path_tree); + return 0; + } + } + } + fclose(input); + + // create the global tape info array + GLOBAL_tape_info = new tape_info_t[GLOBAL_tapeinfo_size]; + + // scan /dev/rmt and insert tape entries + for (i=0; tape_dirs[i] != nil; i++) { + dirp = opendir(tape_dirs[i]); + if (dirp == 0) { + if (i > 0) { + // first is /dev/rmt + break; + } + avlfree(path_tree); + return 0; + } + + for (ld = readdir(dirp); ld != 0; ld = readdir(dirp)) { + // grow the array if needed + if (count == GLOBAL_tapeinfo_size) { + GLOBAL_tapeinfo_size += 1; + GLOBAL_tape_info = renew GLOBAL_tape_info[GLOBAL_tapeinfo_size]; + } + dp = *((dirent_t *) ld); + + // skip . and .. + if (dp.d_name == "." || dp.d_name == "..") { + continue; + } + + // skip everything but raw devices + if ( isdigit(dp.d_name[strlen(dp.d_name)-1]) == 0 ) { + continue; + } + + // read the link + full = sprintf("%s/%s", tape_dirs[i], dp.d_name); + + n = readlink(full, points_at, sizeof(points_at)); + if (n == -1) { + closedir(dirp); + avlfree(path_tree); + return 0; + } + points_at[n] = '\0'; + + // chop off the :a at the end + strcpy(strrchr(points_at, ':'), ""); + + // hack off ../../devices from the start + sscanf(points_at, "../../devices%s", &points_at); + + // hack off /dev/ from the start + // long name is the rmt/ + sscanf(full, "/dev/%s", &buf); + GLOBAL_tape_info[count].long_name = buf; + + GLOBAL_tape_info[count].short_name = nil; + + // construct the short name + if ((np = str2int_get(path_tree, points_at)) != 0) { + n = ((int) *((ulong_t *) np)); + p = strrchr(points_at, '/'); + p = strtok(p, "/"); + p = strtok(p, "@"); + GLOBAL_tape_info[count].short_name = sprintf("%s%d", p, n); + } + + // hard luck, can't find this device + if (GLOBAL_tape_info[count].short_name == nil) { + continue; + } + + // squirrel this away while we're at it + GLOBAL_tape_info[count].errors = + find_tape_error(GLOBAL_tape_info[count].short_name); + + count++; + } + closedir(dirp); + } + + // tree the names for fast lookup + GLOBAL_tapeinfo_short_tree = str2int_init(); + GLOBAL_tapeinfo_long_tree = str2int_init(); + if ((GLOBAL_tapeinfo_short_tree == 0) || (GLOBAL_tapeinfo_long_tree == 0)) { + return 0; + } + for(i=0; i= 0 && i < GLOBAL_tapeinfo_size) { + return GLOBAL_tape_info[i]; + } else { + no_info.short_name = name; + no_info.long_name = name; + return no_info; + } +} + +#endif From dmberezin at hotmail.com Tue Sep 14 12:19:38 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Tue, 14 Sep 2004 12:19:38 -0700 Subject: [Orca-checkins] r392 - trunk/orca/data_gatherers/orcallator Message-ID: <200409141919.i8EJJccQ030672@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Tue Sep 14 12:17:03 2004 New Revision: 392 Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: Update to the disk/tape data collection on Solaris. * data_gatherers/orcallator/orcallator.se (orca_io_info_update): Removed data fixing code. Should not occur with the current versions of Solaris and SE. Re-add if problem re-occures. (orca_io_info_update): Removed temporary variables - calculate using kio.xxxx _nread _nwritten _reads _writes _wtime _wlentime _wlastupdate _rtime _rlentime _rlastupdate _wcnt _rcnt nanosecond (orca_io_info_update): Simplified further Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Tue Sep 14 12:17:03 2004 @@ -350,24 +350,11 @@ kstat_t kp[1]; kstat_t nkp[1]; kstat_io_t kio; - ulonglong _nread; - ulonglong _nwritten; - uint _reads; - uint _writes; - longlong _wtime; - longlong _wlentime; - longlong _wlastupdate; - longlong _rtime; - longlong _rlentime; - longlong _rlastupdate; - longlong _wcnt; - longlong _rcnt; double read_writes; double big_etime; double elapsed_etime; double hz_etime; - double nanosecond = NANOSEC; kc[0] = kstat_open(); // Read them. @@ -382,6 +369,14 @@ if (nkp[0].ks_type == KSTAT_TYPE_IO) { // Look for disk or tape statistics if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { + // Update the device registers. + if (kstat_read(kc, nkp, 0) == -1) { + perror("orca_io_info_update:kstat_read error"); + exit(1); + } + // Read sys_kstat device IO queue to find out about recent activity. + struct_fill(kio, nkp[0].ks_data); + // Try to locate device. for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { @@ -413,101 +408,59 @@ } ORCA_io_dev_info[iodev].short_name = nkp[0].ks_name; - ORCA_io_dev_info[iodev]._reads = 0; - ORCA_io_dev_info[iodev]._nread = 0; - ORCA_io_dev_info[iodev]._rlentime = 0; - ORCA_io_dev_info[iodev]._rlastupdate = boot_time; - ORCA_io_dev_info[iodev]._rcnt = 0; - ORCA_io_dev_info[iodev]._writes = 0; - ORCA_io_dev_info[iodev]._nwritten = 0; - ORCA_io_dev_info[iodev]._wlentime = 0; - ORCA_io_dev_info[iodev]._wlastupdate = boot_time; - ORCA_io_dev_info[iodev]._wcnt = 0; + ORCA_io_dev_info[iodev]._writes = kio.writes; + ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; + ORCA_io_dev_info[iodev]._wlastupdate = kio.wlastupdate; + ORCA_io_dev_info[iodev]._wlentime = kio.wlentime; + ORCA_io_dev_info[iodev]._wtime = kio.wtime; + ORCA_io_dev_info[iodev]._wcnt = kio.wcnt; + ORCA_io_dev_info[iodev]._reads = kio.reads; + ORCA_io_dev_info[iodev]._nread = kio.nread; + ORCA_io_dev_info[iodev]._rlastupdate = kio.rlastupdate; + ORCA_io_dev_info[iodev]._rlentime = kio.rlentime; + ORCA_io_dev_info[iodev]._rtime = kio.rtime; + ORCA_io_dev_info[iodev]._rcnt = kio.rcnt; ORCA_io_dev_count++; } - // Update the device registers. - if (kstat_read(kc, nkp, 0) == -1) { - perror("orca_io_info_update:kstat_read error"); - exit(1); - } else { - // Read sys_kstat device IO queue to find out about recent - // activity. We validate data that is returned. Solaris - // 2.6 has occasional glitches when updating certain disks - // (c0t0d0) so we cover up the glitches by using data from - // the previous cycle. Eventually, we will get a good - // update. Fixing the data is not necessarily the best - // choice. Currently only kio.nread glitches. Correcting - // the error forces the IOs to get attributed to the next IO - // cycle. - struct_fill(kio, nkp[0].ks_data); - - _nread = kio.nread; - if (ORCA_io_dev_info[iodev]._nread > _nread) { - _nread = ORCA_io_dev_info[iodev]._nread; - } - _reads = kio.reads; - if (ORCA_io_dev_info[iodev]._reads > _reads) { - _reads = ORCA_io_dev_info[iodev]._reads; - } - _rlentime = kio.rlentime; - _rtime = kio.rtime; - _rlastupdate = kio.wlastupdate; - _rcnt = kio.rcnt; - _nwritten = kio.nwritten; - if (ORCA_io_dev_info[iodev]._nwritten > _nwritten) { - _nwritten = ORCA_io_dev_info[iodev]._nwritten; - } - _writes = kio.writes; - if (ORCA_io_dev_info[iodev]._writes > _writes) { - _writes = ORCA_io_dev_info[iodev]._nwritten; - } - _wlentime = kio.wlentime; - _wtime = kio.wtime; - _wlastupdate = kio.wlastupdate; - _wcnt = kio.wcnt; - - elapsed_etime = (_wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); - if (elapsed_etime > 0) { - hz_etime = elapsed_etime / nanosecond; - big_etime = 1024.0 * hz_etime; - } else { - elapsed_etime = nanosecond; - hz_etime = 1.0; - big_etime = 1024.0; - } - ORCA_io_dev_info[iodev].reads =(_reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; - ORCA_io_dev_info[iodev].kreads =(_nread-ORCA_io_dev_info[iodev]._nread) /big_etime; - ORCA_io_dev_info[iodev].writes =(_writes-ORCA_io_dev_info[iodev]._writes)/hz_etime; - ORCA_io_dev_info[iodev].kwrites=(_nwritten-ORCA_io_dev_info[iodev]._nwritten) / big_etime; - - read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; - if (read_writes > 0) { - ORCA_io_dev_info[iodev].avg_wait = (_wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; - ORCA_io_dev_info[iodev].avg_serv = (_rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; - ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; - } else { - ORCA_io_dev_info[iodev].avg_wait = 0.0; - ORCA_io_dev_info[iodev].avg_serv = 0.0; - ORCA_io_dev_info[iodev].service = 0.0; - } + elapsed_etime = (kio.wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); + if (elapsed_etime == 0) { + elapsed_etime = NANOSEC; + } + hz_etime = elapsed_etime / NANOSEC; + big_etime = 1024.0 * hz_etime; - // Update the counters. - ORCA_io_dev_info[iodev].run_percent = 100.0 * (_rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; - ORCA_io_dev_info[iodev].wait_percent = 100.0 * (_wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; - ORCA_io_dev_info[iodev]._writes = _writes; - ORCA_io_dev_info[iodev]._nwritten = _nwritten; - ORCA_io_dev_info[iodev]._wlastupdate = _wlastupdate; - ORCA_io_dev_info[iodev]._wlentime = _wlentime; - ORCA_io_dev_info[iodev]._wtime = _wtime; - ORCA_io_dev_info[iodev]._wcnt = _wcnt; - ORCA_io_dev_info[iodev]._reads = _reads; - ORCA_io_dev_info[iodev]._nread = _nread; - ORCA_io_dev_info[iodev]._rlastupdate = _rlastupdate; - ORCA_io_dev_info[iodev]._rlentime = _rlentime; - ORCA_io_dev_info[iodev]._rtime = _rtime; - ORCA_io_dev_info[iodev]._rcnt = _rcnt; + ORCA_io_dev_info[iodev].reads =(kio.reads-ORCA_io_dev_info[iodev]._reads) /hz_etime; + ORCA_io_dev_info[iodev].kreads =(kio.nread-ORCA_io_dev_info[iodev]._nread) /big_etime; + ORCA_io_dev_info[iodev].writes =(kio.writes-ORCA_io_dev_info[iodev]._writes) /hz_etime; + ORCA_io_dev_info[iodev].kwrites=(kio.nwritten-ORCA_io_dev_info[iodev]._nwritten)/big_etime; + + read_writes = elapsed_etime * (ORCA_io_dev_info[iodev].reads + ORCA_io_dev_info[iodev].writes) / 1024.0; + if (read_writes > 0) { + ORCA_io_dev_info[iodev].avg_wait = (kio.wlentime - ORCA_io_dev_info[iodev]._wlentime) / read_writes; + ORCA_io_dev_info[iodev].avg_serv = (kio.rlentime - ORCA_io_dev_info[iodev]._rlentime) / read_writes; + ORCA_io_dev_info[iodev].service = ORCA_io_dev_info[iodev].avg_wait + ORCA_io_dev_info[iodev].avg_serv; + } else { + ORCA_io_dev_info[iodev].avg_wait = 0.0; + ORCA_io_dev_info[iodev].avg_serv = 0.0; + ORCA_io_dev_info[iodev].service = 0.0; } + + // Update the counters. + ORCA_io_dev_info[iodev].run_percent = 100.0 * (kio.rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; + ORCA_io_dev_info[iodev].wait_percent = 100.0 * (kio.wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; + ORCA_io_dev_info[iodev]._writes = kio.writes; + ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; + ORCA_io_dev_info[iodev]._wlastupdate = kio.wlastupdate; + ORCA_io_dev_info[iodev]._wlentime = kio.wlentime; + ORCA_io_dev_info[iodev]._wtime = kio.wtime; + ORCA_io_dev_info[iodev]._wcnt = kio.wcnt; + ORCA_io_dev_info[iodev]._reads = kio.reads; + ORCA_io_dev_info[iodev]._nread = kio.nread; + ORCA_io_dev_info[iodev]._rlastupdate = kio.rlastupdate; + ORCA_io_dev_info[iodev]._rlentime = kio.rlentime; + ORCA_io_dev_info[iodev]._rtime = kio.rtime; + ORCA_io_dev_info[iodev]._rcnt = kio.rcnt; } } } From dmberezin at hotmail.com Tue Sep 14 12:31:32 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Tue, 14 Sep 2004 12:31:32 -0700 Subject: [Orca-checkins] r393 - trunk/orca/data_gatherers/orcallator Message-ID: <200409141931.i8EJVWFr030973@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Tue Sep 14 12:29:33 2004 New Revision: 393 Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: Update to the disk/tape data collection on Solaris. * data_gatherers/orcallator/orcallator.se (orca_io_info_update): Removed unnecessary kstat function calls (orca_io_info_update): Removed unused variable kp (orca_io_info_update): Fixed some comments Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Tue Sep 14 12:29:33 2004 @@ -347,7 +347,6 @@ int index; ulong ul; kstat_ctl_t kc[1]; - kstat_t kp[1]; kstat_t nkp[1]; kstat_io_t kio; @@ -356,28 +355,22 @@ double elapsed_etime; double hz_etime; + // Initialize kstat control structure kc[0] = kstat_open(); - // Read them. - if (kstat_read(kc, kp, 0) == -1) { - perror("orca_io_info_update:kstat_read"); - exit(1); - } - // Traverse the chain looking for IO events. - for (ul=kc[0].kc_chain; ul !=0; ul=nkp[0].ks_next) { + for (ul=kc[0].kc_chain; ul!=0; ul=nkp[0].ks_next) { struct_fill(nkp[0], ul); if (nkp[0].ks_type == KSTAT_TYPE_IO) { // Look for disk or tape statistics if (nkp[0].ks_class == "disk" || nkp[0].ks_class == "tape") { - // Update the device registers. + // Get data from the kernel for this kstat if (kstat_read(kc, nkp, 0) == -1) { perror("orca_io_info_update:kstat_read error"); exit(1); } - // Read sys_kstat device IO queue to find out about recent activity. struct_fill(kio, nkp[0].ks_data); - // Try to locate device. + // Try to locate device in our array for (iodev=0; iodev < ORCA_io_dev_count; ++iodev) { if (ORCA_io_dev_info[iodev].short_name == nkp[0].ks_name) { break; From dmberezin at hotmail.com Wed Sep 15 09:47:01 2004 From: dmberezin at hotmail.com (dmberezin at hotmail.com) Date: Wed, 15 Sep 2004 09:47:01 -0700 Subject: [Orca-checkins] r394 - trunk/orca/data_gatherers/orcallator Message-ID: <200409151647.i8FGl1ME010739@gw.orcaware.com> Author: dmberezin at hotmail.com Date: Wed Sep 15 09:44:55 2004 New Revision: 394 Modified: trunk/orca/data_gatherers/orcallator/orcallator.se Log: Fix TABs in data_gatherers/orcallator/orcallator.se * data_gatherers/orcallator/orcallator.se Replaced all 'tabs' with 'spaces' Modified: trunk/orca/data_gatherers/orcallator/orcallator.se ============================================================================== --- trunk/orca/data_gatherers/orcallator/orcallator.se (original) +++ trunk/orca/data_gatherers/orcallator/orcallator.se Wed Sep 15 09:44:55 2004 @@ -18,40 +18,40 @@ // // The default sampling interval in seconds. -#define SAMPLE_INTERVAL 300 +#define SAMPLE_INTERVAL 300 // The maximum number of columns of data. -#define MAX_COLUMNS 2048 +#define MAX_COLUMNS 2048 // Enable kstat io measuring code. -#define USE_KSTAT_IO 1 +#define USE_KSTAT_IO 1 // If WATCH_OS is defined, then measure every part of the operating // system. #ifdef WATCH_OS -#define WATCH_CPU 1 -#define WATCH_MUTEX 1 -#define WATCH_NET 1 -#define WATCH_TCP 1 -#define WATCH_NFS_CLIENT 1 -#define WATCH_NFS_SERVER 1 -#define WATCH_MOUNTS 1 -#define WATCH_DISK 1 -#define WATCH_DNLC 1 -#define WATCH_INODE 1 -#define WATCH_RAM 1 -#define WATCH_PAGES 1 +#define WATCH_CPU 1 +#define WATCH_MUTEX 1 +#define WATCH_NET 1 +#define WATCH_TCP 1 +#define WATCH_NFS_CLIENT 1 +#define WATCH_NFS_SERVER 1 +#define WATCH_MOUNTS 1 +#define WATCH_DISK 1 +#define WATCH_DNLC 1 +#define WATCH_INODE 1 +#define WATCH_RAM 1 +#define WATCH_PAGES 1 #endif // Keep backwards compatibility with WATCH_HTTPD. #ifdef WATCH_HTTPD -#define WATCH_WEB 1 +#define WATCH_WEB 1 #endif // Keep backwards compatibility with WATCH_NFS. #ifdef WATCH_NFS #ifndef WATCH_NFS_CLIENT -#define WATCH_NFS_CLIENT 1 +#define WATCH_NFS_CLIENT 1 #endif #endif @@ -93,103 +93,103 @@ // Define this macro which returns the size index for a file of a // particular size. This saves the overhead of a function call. -#define WWW_SIZE_INDEX(size, size_index) \ - if (size < 1024) { \ - size_index=0; /* Under 1KB */ \ - } else { \ - if (size < 10240) { \ - size_index=1; /* Under 10K */ \ - } else { \ - if (size < 102400) { \ - size_index=2; /* Under 100KB */ \ - } else { \ - if (size < 1048576) { \ - size_index=3; /* Under 1MB */ \ - } else { \ - size_index=4; /* Over 1MB */ \ - } \ - } \ - } \ - } \ +#define WWW_SIZE_INDEX(size, size_index) \ + if (size < 1024) { \ + size_index=0; /* Under 1KB */ \ + } else { \ + if (size < 10240) { \ + size_index=1; /* Under 10K */ \ + } else { \ + if (size < 102400) { \ + size_index=2; /* Under 100KB */ \ + } else { \ + if (size < 1048576) { \ + size_index=3; /* Under 1MB */ \ + } else { \ + size_index=4; /* Over 1MB */ \ + } \ + } \ + } \ + } \ dwnld_size[size_index]++; // Handle the reply code from the server. -#define WWW_REPLY_CODE(word) \ - if (word == "304") { \ - httpop_condgets++; \ - } \ - else { \ - first_byte = word; \ - if (first_byte[0] == '4' || first_byte[0] == '5') { \ - httpop_errors++; \ - } \ - } \ +#define WWW_REPLY_CODE(word) \ + if (word == "304") { \ + httpop_condgets++; \ + } \ + else { \ + first_byte = word; \ + if (first_byte[0] == '4' || first_byte[0] == '5') { \ + httpop_errors++; \ + } \ + } \ // Handle the method of the object served. This define only works // with non-proxy servers. -#define WWW_METHOD1(word) \ - switch (word) { \ - case "get": \ - case "GET": \ - httpop_gets++; \ - break; \ - case "post": \ - case "POST": \ - httpop_posts++; \ - break; \ - case "head": \ - case "HEAD": \ - ishead = 1; \ - httpop_condgets++; \ +#define WWW_METHOD1(word) \ + switch (word) { \ + case "get": \ + case "GET": \ + httpop_gets++; \ + break; \ + case "post": \ + case "POST": \ + httpop_posts++; \ + break; \ + case "head": \ + case "HEAD": \ + ishead = 1; \ + httpop_condgets++; \ break; #ifdef WATCH_SQUID -#define WWW_METHOD2 \ - case "icp_query": \ - case "ICP_QUERY": \ - squid_icp_queries++; \ +#define WWW_METHOD2 \ + case "icp_query": \ + case "ICP_QUERY": \ + squid_icp_queries++; \ break; #else #define WWW_METHOD2 #endif -#define WWW_METHOD_END \ - default: \ - break; \ +#define WWW_METHOD_END \ + default: \ + break; \ } #define WWW_METHOD(word) WWW_METHOD1(word) WWW_METHOD2 WWW_METHOD_END #endif #endif // Put all rules here so they can be accessed by the handle functions. -lr_cpu_t lr_cpu$cpu; -lr_cpu_t tmp_lr_cpu; -lr_mutex_t lr_mutex$m; -lr_mutex_t tmp_lr_mutex; -lr_net_t lr_net$nr; -lr_net_t tmp_lr_net; -lr_tcp_t lr_tcp$tcp; -lr_tcp_t tmp_lr_tcp; -lr_rpcclient_t lr_rpcclient$r; -lr_rpcclient_t tmp_lr_rpcclient; -lr_disk_t lr_disk$dr; -lr_disk_t tmp_lr_disk; -lr_dnlc_t lr_dnlc$dnlc; -lr_dnlc_t tmp_lr_dnlc; -lr_inode_t lr_inode$inode; -lr_inode_t tmp_lr_inode; -lr_ram_t lr_ram$ram; -lr_ram_t tmp_lr_ram; -lr_swapspace_t lr_swapspace$s; -lr_swapspace_t tmp_lr_swapspace; -lr_kmem_t lr_kmem$kmem; -lr_kmem_t tmp_lr_kmem; +lr_cpu_t lr_cpu$cpu; +lr_cpu_t tmp_lr_cpu; +lr_mutex_t lr_mutex$m; +lr_mutex_t tmp_lr_mutex; +lr_net_t lr_net$nr; +lr_net_t tmp_lr_net; +lr_tcp_t lr_tcp$tcp; +lr_tcp_t tmp_lr_tcp; +lr_rpcclient_t lr_rpcclient$r; +lr_rpcclient_t tmp_lr_rpcclient; +lr_disk_t lr_disk$dr; +lr_disk_t tmp_lr_disk; +lr_dnlc_t lr_dnlc$dnlc; +lr_dnlc_t tmp_lr_dnlc; +lr_inode_t lr_inode$inode; +lr_inode_t tmp_lr_inode; +lr_ram_t lr_ram$ram; +lr_ram_t tmp_lr_ram; +lr_swapspace_t lr_swapspace$s; +lr_swapspace_t tmp_lr_swapspace; +lr_kmem_t lr_kmem$kmem; +lr_kmem_t tmp_lr_kmem; -ks_system_misc kstat$misc; -ks_system_misc tmp_kstat_misc; +ks_system_misc kstat$misc; +ks_system_misc tmp_kstat_misc; #ifdef WATCH_TCP -tcp tcp$tcp; -tcp tmp_tcp; +tcp tcp$tcp; +tcp tmp_tcp; #endif #ifdef WATCH_PAGES ks_system_pages kstat$pages; @@ -197,102 +197,102 @@ #endif // Put application globals here. -string nodename; // Name of this machine. -string program_name; // Name of this program. -int hz; // Clock tick rate. -int page_size; // Page size in bytes. -long boot_time; // Boot time of the system. -long interval = SAMPLE_INTERVAL; // Sampling interval. +string nodename; // Name of this machine. +string program_name; // Name of this program. +int hz; // Clock tick rate. +int page_size; // Page size in bytes. +long boot_time; // Boot time of the system. +long interval = SAMPLE_INTERVAL; // Sampling interval. #ifdef WATCH_CPU -int can_read_kernel = 0; // If the kernel can be read. -int kvm$mpid; // The last created PID. +int can_read_kernel = 0; // If the kernel can be read. +int kvm$mpid; // The last created PID. // These variables store the mpid before and after the standard interval. -int mpid_previous; -int mpid_current; -ulonglong mpid_then; -ulonglong mpid_now; +int mpid_previous; +int mpid_current; +ulonglong mpid_then; +ulonglong mpid_now; // These variables store the mpid before and after 5 second intervals. -int mpid5_previous; -int mpid5_current; -ulonglong mpid5_then; -ulonglong mpid5_now; -double mpid5_rate; +int mpid5_previous; +int mpid5_current; +ulonglong mpid5_then; +ulonglong mpid5_now; +double mpid5_rate; #endif #ifdef WATCH_MOUNTS -mnttab_t mnt$mnt; -mnttab_t tmp_mnt; +mnttab_t mnt$mnt; +mnttab_t tmp_mnt; #endif #ifdef WATCH_NFS_SERVER -ks_nfs_server kstat$nfs; -ks_nfs_server tmp_nfs; -ks_rfs_proc_v2 kstat$rfsproccnt_v2; -ks_rfs_proc_v2 tmp_rfsproccnt_v2; -ks_rfs_proc_v3 kstat$rfsproccnt_v3; -ks_rfs_proc_v3 tmp_rfsproccnt_v3; +ks_nfs_server kstat$nfs; +ks_nfs_server tmp_nfs; +ks_rfs_proc_v2 kstat$rfsproccnt_v2; +ks_rfs_proc_v2 tmp_rfsproccnt_v2; +ks_rfs_proc_v3 kstat$rfsproccnt_v3; +ks_rfs_proc_v3 tmp_rfsproccnt_v3; #endif // Variables for handling the httpd access log. #ifdef WATCH_WEB -string www_search_url = getenv("SEARCHURL"); -string www_server_proc_name = getenv("WEB_SERVER"); -string www_server_secure_proc_name = getenv("WEB_SERVER_SECURE"); -string www_log_filename = getenv("WEB_LOG"); -string www_gateway = getenv("GATEWAY"); -ulong www_log_fp; -uint www_gatelen; -stat_t www_log_stat[1]; -ulong www_log_ino; -long www_log_size; - -double www_interval; // Hi-res interval time. -ulonglong www_then; -ulonglong www_now; - -double www5_interval; // Actual hi-res 5 second interval. -ulonglong www5_then; -ulonglong www5_now; - -double httpops; -double httpops5; -double gateops; -double dtmp; - -long httpop_gets; -long httpop_condgets; // HEAD or code = 304 conditional get no data. -long httpop_posts; -long httpop_cgi_bins; -long httpop_searches; -long httpop_errors; -long dwnld_size[5]; // [0] < 1K, [1] < 10K, [2] < 100K, [3] < 1M, [4] >= 1M -long dwnld_totalz; // Total size counted from log. +string www_search_url = getenv("SEARCHURL"); +string www_server_proc_name = getenv("WEB_SERVER"); +string www_server_secure_proc_name = getenv("WEB_SERVER_SECURE"); +string www_log_filename = getenv("WEB_LOG"); +string www_gateway = getenv("GATEWAY"); +ulong www_log_fp; +uint www_gatelen; +stat_t www_log_stat[1]; +ulong www_log_ino; +long www_log_size; + +double www_interval; // Hi-res interval time. +ulonglong www_then; +ulonglong www_now; + +double www5_interval; // Actual hi-res 5 second interval. +ulonglong www5_then; +ulonglong www5_now; + +double httpops; +double httpops5; +double gateops; +double dtmp; + +long httpop_gets; +long httpop_condgets; // HEAD or code = 304 conditional get no data. +long httpop_posts; +long httpop_cgi_bins; +long httpop_searches; +long httpop_errors; +long dwnld_size[5]; // [0]<1K, [1]<10K, [2]<100K, [3]<1M, [4]>=1M +long dwnld_totalz; // Total size counted from log. #if WATCH_PROXY || WATCH_SQUID || WATCH_YAHOO // If we're watching a Yahoo log, then take the transfer time to be the // processing time. -double www_dwnld_time_sum; // Transfer time. -double www_dwnld_time_by_size[5]; // Mean transfer time by size bin. +double www_dwnld_time_sum; // Transfer time. +double www_dwnld_time_by_size[5]; // Mean transfer time by size bin. #endif #if WATCH_PROXY || WATCH_SQUID -long prxy_squid_indirect; // # hits that go via PROXY,SOCKS,parent -long prxy_squid_cache_hits; // # hits returned from cache. +long prxy_squid_indirect; // # hits that go via PROXY,SOCKS,parent +long prxy_squid_cache_hits; // # hits returned from cache. #endif #ifdef WATCH_PROXY -long prxy_cache_writes; // Number of writes and updates to cache. -long prxy_uncacheable; // Number of explicitly uncacheable httpops. - // Any extra is errors or incomplete ops. +long prxy_cache_writes; // Number of writes and updates to cache. +long prxy_uncacheable; // Number of explicitly uncacheable httpops. + // Any extra is errors or incomplete ops. #endif #ifdef WATCH_SQUID -long squid_cache_misses; -long squid_icp_requests; -long squid_icp_queries; -long squid_client_http; +long squid_cache_misses; +long squid_icp_requests; +long squid_icp_queries; +long squid_client_http; #endif #endif @@ -309,51 +309,51 @@ // kstat$disk interface. Global data shared between function calls. struct io_dev_info_t { // Exposed interface that matches kstat. - string long_name; - string short_name; - double reads; - double kreads; - double writes; - double kwrites; - double avg_wait; - double avg_serv; - double service; - double wait_percent; - double run_percent; + string long_name; + string short_name; + double reads; + double kreads; + double writes; + double kwrites; + double avg_wait; + double avg_serv; + double service; + double wait_percent; + double run_percent; // Hidden internal registers to track sys_kstats counters. - int _number; // kstat disk # - ulonglong _nread; // Number of bytes read - ulonglong _nwritten; // Number of bytes written - uint _reads; // Number of read operations - uint _writes; // Number of write operations - longlong _wtime; // Cumulative wait (pre-service) time - longlong _wlentime; // Cumulative wait length*time product - longlong _wlastupdate; // Last time wait queue changed - longlong _rtime; // Cumulative run (service) time - longlong _rlentime; // Cumulative run length*time product - longlong _rlastupdate; // Last time run queue changed - uint _wcnt; // Count of elements in wait state - uint _rcnt; // Count of elements in run state + int _number; // kstat disk # + ulonglong _nread; // Number of bytes read + ulonglong _nwritten; // Number of bytes written + uint _reads; // Number of read operations + uint _writes; // Number of write operations + longlong _wtime; // Cumulative wait (pre-service) time + longlong _wlentime; // Cumulative wait length*time product + longlong _wlastupdate; // Last time wait queue changed + longlong _rtime; // Cumulative run (service) time + longlong _rlentime; // Cumulative run length*time product + longlong _rlastupdate; // Last time run queue changed + uint _wcnt; // Count of elements in wait state + uint _rcnt; // Count of elements in run state }; // Define global for tracking raw disk data. -io_dev_info_t ORCA_io_dev_info[]; -int ORCA_io_dev_count=0; -int ORCA_max_io_dev_count=0; +io_dev_info_t ORCA_io_dev_info[]; +int ORCA_io_dev_count=0; +int ORCA_max_io_dev_count=0; orca_io_info_update() { - int iodev; - int index; - ulong ul; - kstat_ctl_t kc[1]; - kstat_t nkp[1]; - kstat_io_t kio; - - double read_writes; - double big_etime; - double elapsed_etime; - double hz_etime; + int iodev; + int index; + ulong ul; + kstat_ctl_t kc[1]; + kstat_t nkp[1]; + kstat_io_t kio; + + double read_writes; + double big_etime; + double elapsed_etime; + double hz_etime; // Initialize kstat control structure kc[0] = kstat_open(); @@ -416,7 +416,7 @@ ORCA_io_dev_count++; } - elapsed_etime = (kio.wlastupdate - ORCA_io_dev_info[iodev]._wlastupdate); + elapsed_etime = (kio.wlastupdate-ORCA_io_dev_info[iodev]._wlastupdate); if (elapsed_etime == 0) { elapsed_etime = NANOSEC; } @@ -440,7 +440,7 @@ } // Update the counters. - ORCA_io_dev_info[iodev].run_percent = 100.0 * (kio.rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; + ORCA_io_dev_info[iodev].run_percent = 100.0 * (kio.rtime - ORCA_io_dev_info[iodev]._rtime) / elapsed_etime; ORCA_io_dev_info[iodev].wait_percent = 100.0 * (kio.wtime - ORCA_io_dev_info[iodev]._wtime) / elapsed_etime; ORCA_io_dev_info[iodev]._writes = kio.writes; ORCA_io_dev_info[iodev]._nwritten = kio.nwritten; @@ -462,28 +462,28 @@ #endif // USE_KSTAT_IO // Variables for handling output. -string compress = getenv("COMPRESSOR"); // How to compress logs. -ulong out_log_fp; // File pointer to the logging file. -string col_comment[MAX_COLUMNS]; // Comments for each column. -string col_data[MAX_COLUMNS]; // Data for each column. -string col_previous_comment[MAX_COLUMNS]; // Previous comments. -int current_column = 0; // The current column. -int previous_number_columns = -1; // Number columns printed last. -int print_header = 1; // Flag to flush header. +string compress = getenv("COMPRESSOR"); // How to compress logs. +ulong out_log_fp; // File pointer to the logging file. +string col_comment[MAX_COLUMNS]; // Comments for each column. +string col_data[MAX_COLUMNS]; // Data for each column. +string col_previous_comment[MAX_COLUMNS]; // Previous comments. +int current_column = 0; // The current column. +int previous_number_columns = -1; // Number columns printed last. +int print_header = 1; // Flag to flush header. // This is a list of the extensions the compress programs add to the // compress filename. #define NUMBER_COMPRESS_SUFFIXES 3 -string compression_suffixes[NUMBER_COMPRESS_SUFFIXES] = {".Z", - ".gz", - ".bz2"}; +string compression_suffixes[NUMBER_COMPRESS_SUFFIXES] = {".Z", + ".gz", + ".bz2"}; // Add one column of comments and data to the buffers. put_output(string comment, string data) { if (current_column >= MAX_COLUMNS) { fprintf(stderr, "%s: too many columns (%d). Increase MAX_COLUMNS.\n", - program_name, current_column); + program_name, current_column); exit(1); } @@ -528,18 +528,18 @@ // previous days log file if the environmental variable COMPRESSOR is // set. check_output_log_filename(tm_t now) { - string output_directory = getenv("OUTDIR"); - string output_filename; - string compressed_filename; - stat_t log_file_stat[1]; - tm_t then; - char tm_buf[32]; - int file_number; - int need_new_log_file; - int exists_uncompressed; - int exists_compressed; - int result; - int i; + string output_directory = getenv("OUTDIR"); + string output_filename; + string compressed_filename; + stat_t log_file_stat[1]; + tm_t then; + char tm_buf[32]; + int file_number; + int need_new_log_file; + int exists_uncompressed; + int exists_compressed; + int result; + int i; if (output_directory == nil) { // No output directory so use stdout. @@ -649,10 +649,10 @@ int main(int argc, string argv[]) { - utsname_t u[1]; - long now; - long sleep_till; // Time to sleep to. - tm_t tm_now; + utsname_t u[1]; + long now; + long sleep_till; // Time to sleep to. + tm_t tm_now; // Get the nodename of the machine. uname(u); @@ -1195,31 +1195,31 @@ // } current_count++; put_output(sprintf("%5sIpkt/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].ipackets)); + sprintf("%11.3f", GLOBAL_net[i].ipackets)); put_output(sprintf("%5sOpkt/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].opackets)); + sprintf("%11.3f", GLOBAL_net[i].opackets)); put_output(sprintf("%5sInKB/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].ioctets/1024.0)); + sprintf("%11.3f", GLOBAL_net[i].ioctets/1024.0)); put_output(sprintf("%5sInDtSz/p", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].idtsize)); + sprintf("%11.3f", GLOBAL_net[i].idtsize)); put_output(sprintf("%5sInOvH%%/p", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].ihdrovhd)); + sprintf("%11.3f", GLOBAL_net[i].ihdrovhd)); put_output(sprintf("%5sOuKB/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].ooctets/1024.0)); + sprintf("%11.3f", GLOBAL_net[i].ooctets/1024.0)); put_output(sprintf("%5sOuDtSz/p", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].odtsize)); + sprintf("%11.3f", GLOBAL_net[i].odtsize)); put_output(sprintf("%5sOuOvH%%/p", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].ohdrovhd)); + sprintf("%11.3f", GLOBAL_net[i].ohdrovhd)); put_output(sprintf("%5sIErr/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].ierrors)); + sprintf("%11.3f", GLOBAL_net[i].ierrors)); put_output(sprintf("%5sOErr/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].oerrors)); + sprintf("%11.3f", GLOBAL_net[i].oerrors)); put_output(sprintf("%5sColl%%", tmp_lr_net.names[i]), - sprintf("%10.3f", GLOBAL_net[i].collpercent)); + sprintf("%10.3f", GLOBAL_net[i].collpercent)); put_output(sprintf("%5sNoCP/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].nocanput)); + sprintf("%11.3f", GLOBAL_net[i].nocanput)); put_output(sprintf("%5sDefr/s", tmp_lr_net.names[i]), - sprintf("%11.3f", GLOBAL_net[i].defer)); + sprintf("%11.3f", GLOBAL_net[i].defer)); } // If the number of up interfaces changes, then print new headers. @@ -1651,8 +1651,8 @@ #ifdef DINKY printf("time: %s %f total %f\n", word, xf, xfer_sum); #endif - word = strtok(nil, " "); /* Client IP address. */ - logtag = strtok(nil, "/"); /* Log tag. */ + word = strtok(nil, " "); /* Client IP address. */ + logtag = strtok(nil, "/"); /* Log tag. */ if (logtag == nil) { return; } @@ -1669,12 +1669,12 @@ squid_cache_misses++; } - word = strtok(nil, " "); /* Reply code. */ + word = strtok(nil, " "); /* Reply code. */ if (word == nil) { return; } WWW_REPLY_CODE(word) - word = strtok(nil, " "); /* Size sent to client. */ + word = strtok(nil, " "); /* Size sent to client. */ if (word == nil) { return; } @@ -1682,7 +1682,7 @@ WWW_SIZE_INDEX(z, size_index) www_dwnld_time_by_size[size_index] += xf; - request = strtok(nil, " "); /* Request method. */ + request = strtok(nil, " "); /* Request method. */ if (request == nil) { return; } @@ -1692,7 +1692,7 @@ dwnld_totalz += z; } - word = strtok(nil, " "); /* URL. */ + word = strtok(nil, " "); /* URL. */ if (word == nil) { return; } @@ -1702,8 +1702,8 @@ if (word =~ www_search_url) { httpop_searches++; } - strtok(nil, " "); /* Optional user identity. */ - word = strtok(nil, "/"); /* Hierarchy. */ + strtok(nil, " "); /* Optional user identity. */ + word = strtok(nil, "/"); /* Hierarchy. */ if (word == nil) { return; } @@ -1711,11 +1711,11 @@ prxy_squid_indirect++; } #if 0 - word = strtok(nil, " "); /* Hostname. */ + word = strtok(nil, " "); /* Hostname. */ if (word == nil) { return; } - word = strtok(nil, " "); /* Content-type. */ + word = strtok(nil, " "); /* Content-type. */ if (word == nil) { return; } @@ -1729,10 +1729,10 @@ * only appear if they are enabled via the YahooLogOptions configuration * directive. * - * IP Address (8 hex digits) - * Timestamp (time_t as 8 hex digits) - * Processing Time (in microseconds, as 8 hex digits) - * Bytes Sent (8 hex digits) + * IP Address (8 hex digits) + * Timestamp (time_t as 8 hex digits) + * Processing Time (in microseconds, as 8 hex digits) + * Bytes Sent (8 hex digits) * URL * [^Er referrer] (CONFIG) * [^Em method] (CONFIG) @@ -1794,17 +1794,17 @@ dwnld_totalz += z; } -#else /* common or Netscape proxy formats */ - strtok(nil, " "); /* -. */ - strtok(nil, " "); /* -. */ - strtok(nil, " ["); /* date. */ - strtok(nil, " "); /* zone]. */ - strtok(nil, " \""); /* GET or POST. */ +#else /* common or Netscape proxy formats */ + strtok(nil, " "); /* -. */ + strtok(nil, " "); /* -. */ + strtok(nil, " ["); /* date. */ + strtok(nil, " "); /* zone]. */ + strtok(nil, " \""); /* GET or POST. */ if (word == nil) { return; } WWW_METHOD(word) - word = strtok(nil, " "); /* URL. */ + word = strtok(nil, " "); /* URL. */ if (word == nil) { return; } @@ -1829,7 +1829,7 @@ } } WWW_REPLY_CODE(word) - word = strtok(nil, " "); /* Bytes transferred. */ + word = strtok(nil, " "); /* Bytes transferred. */ if (word == nil) { return; } @@ -1840,16 +1840,16 @@ } WWW_SIZE_INDEX(z, size_index) #ifdef WATCH_PROXY - strtok(nil, " "); /* Status from server. */ - strtok(nil, " "); /* Length from server. */ - strtok(nil, " "); /* Length from client POST. */ - strtok(nil, " "); /* Length POSTed to remote. */ - strtok(nil, " "); /* Client header request. */ - strtok(nil, " "); /* Proxy header response. */ - strtok(nil, " "); /* Proxy header request. */ - strtok(nil, " "); /* Server header response. */ - strtok(nil, " "); /* Transfer total seconds. */ - word = strtok(nil, " "); /* Route. */ + strtok(nil, " "); /* Status from server. */ + strtok(nil, " "); /* Length from server. */ + strtok(nil, " "); /* Length from client POST. */ + strtok(nil, " "); /* Length POSTed to remote. */ + strtok(nil, " "); /* Client header request. */ + strtok(nil, " "); /* Proxy header response. */ + strtok(nil, " "); /* Proxy header request. */ + strtok(nil, " "); /* Server header response. */ + strtok(nil, " "); /* Transfer total seconds. */ + word = strtok(nil, " "); /* Route. */ if (word == nil) { return; } @@ -1859,9 +1859,9 @@ strncmp(word, "SOCKS", 5) == 0) { prxy_squid_indirect++; } - strtok(nil, " "); /* Client finish status. */ - strtok(nil, " "); /* Server finish status. */ - word = strtok(nil, " "); /* Cache finish status. */ + strtok(nil, " "); /* Client finish status. */ + strtok(nil, " "); /* Server finish status. */ + word = strtok(nil, " "); /* Cache finish status. */ if (word == nil) { return; } @@ -1888,7 +1888,7 @@ default: break; } - word = strtok(nil, " ["); /* [transfer total time x.xxx. */ + word = strtok(nil, " ["); /* [transfer total time x.xxx. */ if (word == nil) { return; }