[Orca-checkins] r388 - in trunk/orca: data_gatherers/orcallator lib/SE/3.3.1
dmberezin at hotmail.com
dmberezin at hotmail.com
Fri Sep 10 10:43:36 PDT 2004
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 <blair at orcaware.com>.
-//
-// 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 <stdio.se>
-#include <stdlib.se>
-#include <unistd.se>
-#include <string.se>
-#include <time.se>
-#include <kstat.se>
-#include <stat.se>
-#include <utsname.se>
-
-#include <p_iostat_class.se>
-//#include <p_netstat_class.se>
-#include <orca_p_netstat_class.se>
-//#include <p_vmstat_class.se>
-#include <orca_p_vmstat_class.se>
-#include <pure_rules.se>
-#include <live_rules.se>
-#include <mib.se>
-#include <tcp_class.se>
-#include <tcp_rules.se>
-
-#ifdef WATCH_MOUNTS
-#include <mnt_class.se>
-#include <statvfs.se>
-#endif
-
-#if WATCH_CPU || WATCH_WEB
-#include <proc.se>
-
-#ifdef WATCH_CPU
-// This is the maximum pid on Solaris hosts.
-#define DEFAULT_MAXPID 30000
-#include <fcntl.se>
-#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 <sys_kstat.se>
-#include <tapeinfo.se>
-// 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<current_column; ++i) {
- fprintf(out_log_fp, "%s", data[i]);
- if (i != current_column-1) {
- fputc(' ', out_log_fp);
- }
- }
- fputc('\n', out_log_fp);
- fflush(out_log_fp);
-}
-
-// Flush all of the stored output.
-print_output() {
- if (print_header != 0) {
- print_columns(col_comment);
- print_header = 0;
- }
- print_columns(col_data);
-
- // Save the current number of columns stored and the column names so
- // that the next set can be compared with to determine if the
- // headers should be printed again.
- col_previous_comment = col_comment;
- previous_number_columns = current_column - 1;
- current_column = 0;
-}
-
-// Sets out_log_fp to the output file pointer. Creates or appends to
-// the log file if OUTDIR is set, otherwise sets the file pointer to
-// STDOUT. It start a new log file each day. It compresses the
-// 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;
-
- if (output_directory == nil) {
- // No output directory so use stdout.
- if (out_log_fp == 0) {
- // First time, so print header and set out_log_fp.
- out_log_fp = stdout;
- print_header = 1;
- }
- return;
- }
-
- // Check if a new output log is needed. This happens when the day
- // changes, if the number of columns changes or if the column
- // comments change since the last measurement.
- if (now.tm_yday != then.tm_yday ||
- previous_number_columns != (current_column - 1)) {
- need_new_log_file = 1;
- } else {
- need_new_log_file = 0;
- for (i=0; i<current_column; ++i) {
- if (col_comment[i] != col_previous_comment[i]) {
- need_new_log_file = 1;
- break;
- }
- }
- }
-
- // Maintain daily output log files in OUTDIR.
- if (need_new_log_file != 0) {
- // Close and optionally compress the existing output file. The
- // first time through out_log_fp will be 0.
- if (out_log_fp != 0) {
- if (fclose(out_log_fp) != 0) {
- perror("cannot close output log file");
- }
- if (compress != nil) {
- system(sprintf(compress, output_filename));
- }
- }
-
- // Get the new filename. Check for already existing uncompressed
- // log filenames and compressed log filenames.
- strftime(tm_buf, sizeof(tm_buf), "%Y-%m-%d", now);
-
- // If the previous log filename has the same date, then increment
- // the file number, otherwise reset it to 0. The first time
- // through, output_filename will be nil.
- if (nil != output_filename && output_filename =~ tm_buf) {
- file_number++;
- } else {
- file_number = 0;
- }
-
- while (1 == 1) {
-
- // Check for the existence of uncompressed and compressed log
- // files. If there is an uncompressed log file but no
- // compressed ones, then compress it in the background. If
- // either an uncompressed or compressed log file exist, then
- // check the next file number.
- output_filename = sprintf("%s/orcallator-%s-%03d", output_directory,
- tm_buf,
- file_number);
- result = stat(output_filename, log_file_stat);
- if (result != -1) {
- exists_uncompressed = 1;
- } else {
- exists_uncompressed = 0;
- }
-
- exists_compressed = 0;
- for (i=0; i<NUMBER_COMPRESS_SUFFIXES; ++i) {
- compressed_filename = sprintf("%s%s", output_filename,
- compression_suffixes[i]);
- result = stat(compressed_filename, log_file_stat);
- if (result != -1) {
- exists_compressed = 1;
- break;
- }
- }
-
- if (nil != compress &&
- 0 != exists_uncompressed &&
- 0 == exists_compressed) {
- system(sprintf(compress, output_filename));
- }
-
- if (0 != exists_uncompressed || 0 != exists_compressed) {
- ++file_number;
- } else {
- break;
- }
- }
-
- // Open the file for appending.
- out_log_fp = fopen(output_filename, "a");
- if (out_log_fp == 0) {
- perror("cannot open output log file");
- exit(1);
- }
-
- // Always write a new header.
- print_header = 1;
- then = now;
- }
-}
-
-int main(int argc, string argv[])
-{
- 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);
- nodename = u[0].nodename;
-
- program_name = argv[0];
-
- // Handle the command line arguments.
- switch (argc) {
- case 1:
- break;
- case 2:
- interval = atoi(argv[1]);
- break;
- default:
- fprintf(stderr, "usage: se [-Defines] %s [interval]\n", program_name);
- fprintf(stderr, "The default interval is %d seconds.\n", SAMPLE_INTERVAL);
- fprintf(stderr, "%s uses the following environmental variables:\n", program_name);
- fprintf(stderr, " OUTDIR directory to write log files, output to stdout if not set\n");
- fprintf(stderr, " WEB_SERVER regex to match web server's name (def = httpd)\n");
- fprintf(stderr, " WEB_SERVER_SECURE regex to match secure web server's name (def = httpsd)\n");
- fprintf(stderr, " WEB_LOG location of web server access log (/httpd/logs/access)\n");
- fprintf(stderr, " GATEWAY special web address to monitor (some.where.com)\n");
- fprintf(stderr, " SEARCHURL regex for search scripts (def = search.cgi)\n");
- fprintf(stderr, " COMPRESSOR compress log files with this command (\"bzip2 -9\")\n");
- fprintf(stderr, "Add these defines to enable monitoring of specific subsystems:\n");
- fprintf(stderr, " -DWATCH_WEB watch web server access logs\n");
- fprintf(stderr, " -DWATCH_PROXY use WEB_LOG as a NCSA style proxy log\n");
- fprintf(stderr, " -DWATCH_SQUID use WEB_LOG as a Squid log\n");
- fprintf(stderr, " -DWATCH_OS includes all of the below:\n");
- fprintf(stderr, " -DWATCH_CPU watch the cpu load, run queue, etc\n");
- fprintf(stderr, " -DWATCH_MUTEX watch the number of mutex spins\n");
- fprintf(stderr, " -DWATCH_NET watch all Ethernet interfaces\n");
- fprintf(stderr, " -DWATCH_TCP watch all the TCP/IP stack\n");
- fprintf(stderr, " -DWATCH_NFS_CLIENT watch NFS client requests\n");
- fprintf(stderr, " -DWATCH_NFS_SERVER watch NFS server requests\n");
- fprintf(stderr, " -DWATCH_MOUNTS watch usage of mount points\n");
- fprintf(stderr, " -DWATCH_DISK watch disk read/write usage\n");
- fprintf(stderr, " -DWATCH_DNLC watch the directory name lookup cache\n");
- fprintf(stderr, " -DWATCH_INODE watch the inode cache\n");
- fprintf(stderr, " -DWATCH_RAM watch memory usage\n");
- fprintf(stderr, " -DWATCH_PAGES watch where pages are allocated\n");
- exit(1);
- break;
- }
-
- // Initialize the various structures.
- initialize();
-
- // Run forever. If WATCH_WEB is defined, then have measure_web()
- // do the sleeping while it is watching the access log file until the
- // next update time for the whole operating system. Also, collect the
- // data from the access log file before printing any output.
- for (;;) {
- // Calculate the next time to sleep to that is an integer multiple of
- // the interval time. Make sure that at least half of the interval
- // passes before waking up.
- now = time(0);
- sleep_till = (now/interval)*interval;
- while (sleep_till < now + interval*0.5) {
- sleep_till += interval;
- }
-
-#ifdef WATCH_WEB
- measure_web(sleep_till);
-#else
- sleep_till_and_count_new_processes(sleep_till);
-#endif
-
- // Get the current time.
- now = time(0);
- tm_now = localtime(&now);
-
- measure_os(now, tm_now);
-
-#ifdef WATCH_WEB
- put_httpd();
-#endif
-
- // Get a file descriptor to write to. Maintains daily output files.
- check_output_log_filename(tm_now);
-
- // Print the output.
- print_output();
- }
- return 0;
-}
-
-initialize()
-{
-#ifdef WATCH_CPU
- int i;
-#endif
-
- // Get the command to compress the log files.
- if (compress == nil || compress == "") {
- compress = nil;
- }
- else {
- compress = sprintf("%s %%s &", compress);
- }
-
-#ifdef WATCH_CPU
- // Initialize the process spawning rate measurement variables.
- // Determine if the kernel can be read to measure the last pid.
- i = open("/dev/kmem", O_RDONLY);
- if (i != -1) {
- close(i);
- can_read_kernel = 1;
- mpid_previous = kvm$mpid;
- mpid_then = gethrtime();
- mpid_current = mpid_previous;
-
- mpid5_then = mpid_then;
- mpid5_previous = mpid_previous;
- mpid5_current = mpid_previous;
- mpid5_rate = 0;
- }
-#endif
-
-#ifdef WATCH_WEB
- // Initialize those variables that were not set with environmental
- // variables.
- if (www_search_url == nil || www_search_url == "") {
- www_search_url = "search.cgi";
- }
-
- if (www_server_proc_name == nil || www_server_proc_name == "") {
- www_server_proc_name = "httpd";
- }
-
- if (www_server_secure_proc_name == nil ||
- www_server_secure_proc_name == "") {
- www_server_secure_proc_name = "httpsd";
- }
-
- if (www_gateway == nil || www_gateway == "" ) {
- www_gateway = "NoGatway";
- www_gatelen = 0;
- }
- else {
- www_gatelen = strlen(www_gateway);
- }
-
- // Initialize the web server watching variables. Move the file pointer
- // to the end of the web access log and note the current time.
- if (www_log_filename != nil) {
- www_log_fp = fopen(www_log_filename, "r");
- www_log_ino = 0;
- www_log_size = 0;
- if (www_log_fp != 0) {
- if (fstat(fileno(www_log_fp), www_log_stat) == 0) {
- www_log_ino = www_log_stat[0].st_ino;
- www_log_size = www_log_stat[0].st_size;
- }
- // Move to the end of the file.
- fseek(www_log_fp, 0, 2);
- }
- }
-
- www_then = gethrtime();
- www5_then = www_then;
-#endif
-
- // Sleep to give the disks a chance to update.
- sleep(DISK_UPDATE_RATE);
-
- // Get the clock tick rate.
- hz = sysconf(_SC_CLK_TCK);
-
- // Get the page size.
- page_size = sysconf(_SC_PAGESIZE);
-
- // Calculate the system boot time.
- boot_time = time(0) - (kstat$misc.clk_intr / hz);
-
- // Perform the first measurement of the system.
- _measure_os();
-}
-
-// Measure the system statistics all at once.
-_measure_os()
-{
- tmp_lr_cpu = lr_cpu$cpu;
- tmp_lr_mutex = lr_mutex$m;
- tmp_lr_net = lr_net$nr;
- tmp_lr_tcp = lr_tcp$tcp;
- tmp_lr_rpcclient = lr_rpcclient$r;
- tmp_lr_disk = lr_disk$dr;
- tmp_lr_dnlc = lr_dnlc$dnlc;
- tmp_lr_inode = lr_inode$inode;
- tmp_lr_ram = lr_ram$ram;
- tmp_lr_swapspace = lr_swapspace$s;
- tmp_lr_kmem = lr_kmem$kmem;
-
- tmp_kstat_misc = kstat$misc;
-#ifdef WATCH_NFS_SERVER
- tmp_nfs = kstat$nfs;
- tmp_rfsproccnt_v2 = kstat$rfsproccnt_v2;
- tmp_rfsproccnt_v3 = kstat$rfsproccnt_v3;
-#endif
-#ifdef WATCH_PAGES
- tmp_kstat_pages = kstat$pages;
-#endif
-#ifdef WATCH_TCP
- tmp_tcp = tcp$tcp;
-#endif
-
-#ifdef USE_KSTAT_IO
- orca_io_info_update();
-#endif
-}
-
-measure_os(long now, tm_t tm_now)
-{
- // Measure the system now.
- _measure_os();
-
- // Take care of miscellaneous measurements.
- measure_misc(now, tm_now);
-
- // Take care of cpu.
-#ifdef WATCH_CPU
- measure_cpu();
-#endif
-
- // Take care of mutexes.
-#ifdef WATCH_MUTEX
- measure_mutex();
-#endif
-
- // If the CPUs or mutexes are being monitored, then output the
- // number online CPUs on the system. The GLOBAL_pvm_ncpus variable
- // is used after it has been updated in _measure_os().
-#if defined(WATCH_CPU) || defined (WATCH_MUTEX)
- put_output("ncpus", sprintf("%5d", GLOBAL_pvm_ncpus));
-#endif
-
- // Take care of mount points.
-#ifdef WATCH_MOUNTS
- measure_mounts();
-#endif
-
- // Take care of the disks.
-#ifdef WATCH_DISK
- measure_disk();
-#endif
-
- // Take care of ram.
-#ifdef WATCH_RAM
- measure_ram();
-#endif
-
- // Take care of the network.
-#ifdef WATCH_NET
- measure_net();
-#endif
-
- // Take care of TCP/IP.
-#ifdef WATCH_TCP
- measure_tcp();
-#endif
-
- // Take care of NFS client statistics.
-#ifdef WATCH_NFS_CLIENT
- measure_nfs_client();
-#endif
-
- // Take care of NFS server statistics.
-#ifdef WATCH_NFS_SERVER
- measure_nfs_server();
-#endif
-
- // Take care of DNLC.
-#ifdef WATCH_DNLC
- measure_dnlc();
-#endif
-
- // Take care of the inode cache.
-#ifdef WATCH_INODE
- measure_inode();
-#endif
-
- // Take care of page allocations.
-#ifdef WATCH_PAGES
- measure_pages();
-#endif
-}
-
-/*
- * State as a character.
- */
-char state_char(int state) {
- switch(state) {
- case ST_WHITE: return 'w'; /* OK states are lower case. */
- case ST_BLUE: return 'b';
- case ST_GREEN: return 'g';
- case ST_AMBER: return 'A'; /* Bad states are upper case to stand out. */
- case ST_RED: return 'R';
- case ST_BLACK: return 'B';
- default: return 'I'; /* Invalid state. */
- }
-}
-
-/*
- * State as a digit.
- */
-int state_digit(int state) {
- switch(state) {
- case ST_WHITE: return 0; /* OK states are zero. */
- case ST_BLUE: return 1;
- case ST_GREEN: return 2;
- case ST_AMBER: return 4; /* Bad states have a non-zero value. */
- case ST_RED: return 8;
- case ST_BLACK: return 16;
- default: return -1; /* Invalid state. */
- }
-}
-
-measure_misc(long now, tm_t tm_now)
-{
- char states[12];
- char tm_buf[16];
- int statetmp;
-
- states = "wwwwwwwwwww";
- strftime(tm_buf, sizeof(tm_buf), "%T", tm_now);
-
- put_output("timestamp ", sprintf("%10d", now));
- put_output("locltime", tm_buf);
- put_output(" uptime", sprintf("%8d", now - boot_time));
-
- statetmp = tmp_lr_disk.state;
- states[0] = state_char(statetmp);
- put_output("state_D", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_net.state;
- states[1] = state_char(statetmp);
- put_output("state_N", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_rpcclient.state;
- states[2] = state_char(statetmp);
- put_output("state_n", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_swapspace.state;
- states[3] = state_char(statetmp);
- put_output("state_s", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_ram.state;
- states[4] = state_char(statetmp);
- put_output("state_r", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_kmem.state;
- states[5] = state_char(statetmp);
- put_output("state_k", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_cpu.state;
- states[6] = state_char(statetmp);
- put_output("state_c", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_mutex.state;
- states[7] = state_char(statetmp);
- put_output("state_m", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_dnlc.state;
- states[8] = state_char(statetmp);
- put_output("state_d", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_inode.state;
- states[9] = state_char(statetmp);
- put_output("state_i", sprintf("%7d", state_digit(statetmp)));
-
- statetmp = tmp_lr_tcp.state;
- states[10] = state_char(statetmp);
- put_output("state_t", sprintf("%7d", state_digit(statetmp)));
-
- put_output("DNnsrkcmdit", states);
-}
-
-// This function puts the program to sleep until the beginning of the
-// sleep_till second (as measured in the number of seconds from the
-// Unix Epoch (00:00:00 UTC, January 1, 1970)) using microsecond sleep
-// intervals to wake from sleep as close to the beginning of the
-// sleep_till second as possible.
-orca_sleep_till(long sleep_till)
-{
- timeval_t now[1];
- long time_to_sleep;
-
- gettimeofday(now, 0);
- time_to_sleep = sleep_till - now[0].tv_sec;
- while (time_to_sleep > 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<tmp_lr_net.net_count; ++i) {
- // Skip unused interfaces.
-// if (GLOBAL_net[i].up == 0) {
-// continue;
-// }
- current_count++;
- put_output(sprintf("%5sIpkt/s", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].ipackets));
- put_output(sprintf("%5sOpkt/s", tmp_lr_net.names[i]),
- 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));
- put_output(sprintf("%5sInDtSz/p", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].idtsize));
- put_output(sprintf("%5sInOvH%%/p", tmp_lr_net.names[i]),
- 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));
- put_output(sprintf("%5sOuDtSz/p", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].odtsize));
- put_output(sprintf("%5sOuOvH%%/p", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].ohdrovhd));
- put_output(sprintf("%5sIErr/s", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].ierrors));
- put_output(sprintf("%5sOErr/s", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].oerrors));
- put_output(sprintf("%5sColl%%", tmp_lr_net.names[i]),
- sprintf("%10.3f", GLOBAL_net[i].collpercent));
- put_output(sprintf("%5sNoCP/s", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].nocanput));
- put_output(sprintf("%5sDefr/s", tmp_lr_net.names[i]),
- sprintf("%11.3f", GLOBAL_net[i].defer));
- }
-
- // If the number of up interfaces changes, then print new headers.
- if (current_count != previous_count) {
- print_header = 1;
- previous_count = current_count;
- }
-}
-#endif
-
-#ifdef WATCH_TCP
-measure_tcp()
-{
- double tmp_tcp_InDtpPkt;
- double tmp_tcp_OuDtpPkt;
- double tmp_tcp_InOvHPct;
- double tmp_tcp_OuOvHPct;
-
- put_output("tcp_Iseg/s", sprintf("%10.3f", tmp_tcp.InDataSegs));
- put_output("tcp_Oseg/s", sprintf("%10.3f", tmp_tcp.OutDataSegs));
- put_output("tcp_InKB/s", sprintf("%10.3f", tmp_tcp.InDataBytes/1024.0));
- put_output("tcp_OuKB/s", sprintf("%10.3f", tmp_tcp.OutDataBytes/1024.0));
- if ( tmp_tcp.InDataSegs == 0.0 ) {
- tmp_tcp_InDtpPkt = 0.0;
- tmp_tcp_InOvHPct = 0.0;
- } else {
- tmp_tcp_InDtpPkt = tmp_tcp.InDataBytes/tmp_tcp.InDataSegs;
- tmp_tcp_InOvHPct = 100 * (40 * tmp_tcp.InDataSegs / (40 * tmp_tcp.InDataSegs + tmp_tcp.InDataBytes));
- }
- put_output("tcp_InDtSz/p", sprintf("%10.3f", tmp_tcp_InDtpPkt));
- put_output("tcp_InOvH%/p", sprintf("%8.3f", tmp_tcp_InOvHPct));
- if ( tmp_tcp.OutDataSegs == 0.0 ) {
- tmp_tcp_OuDtpPkt = 0.0;
- tmp_tcp_OuOvHPct = 0.0;
- } else {
- tmp_tcp_OuDtpPkt = tmp_tcp.OutDataBytes/tmp_tcp.OutDataSegs;
- tmp_tcp_OuOvHPct = 100 * (40 * tmp_tcp.OutDataSegs / (40 * tmp_tcp.OutDataSegs + tmp_tcp.OutDataBytes));
- }
- put_output("tcp_OuDtSz/p", sprintf("%10.3f", tmp_tcp_OuDtpPkt));
- put_output("tcp_OuOvH%/p", sprintf("%8.3f", tmp_tcp_OuOvHPct));
- put_output("tcp_Ret%", sprintf("%8.3f", tmp_tcp.RetransPercent));
- put_output("tcp_Dup%", sprintf("%8.3f", tmp_tcp.InDupPercent));
- put_output("tcp_Icn/s", sprintf("%9.3f", tmp_tcp.PassiveOpens));
- put_output("tcp_Ocn/s", sprintf("%9.3f", tmp_tcp.ActiveOpens));
- put_output("tcp_estb", sprintf("%8lu", tmp_tcp.last.tcpCurrEstab));
- put_output("tcp_Rst/s", sprintf("%9.3f", tmp_tcp.OutRsts));
- put_output("tcp_Atf/s", sprintf("%9.3f", tmp_tcp.AttemptFails));
- put_output("tcp_Ldrp/s", sprintf("%10.3f", tmp_tcp.ListenDrop));
- put_output("tcp_LdQ0/s", sprintf("%10.3f", tmp_tcp.ListenDropQ0));
- put_output("tcp_HOdp/s", sprintf("%10.3f", tmp_tcp.HalfOpenDrop));
-}
-#endif
-
-#ifdef WATCH_NFS_CLIENT
-measure_nfs_client()
-{
- put_output("nfs_call/s", sprintf("%10.3f", tmp_lr_rpcclient.calls));
- put_output("nfs_timo/s", sprintf("%10.3f", tmp_lr_rpcclient.timeouts));
- put_output("nfs_badx/s", sprintf("%10.3f", tmp_lr_rpcclient.badxids));
-}
-#endif
-
-#ifdef WATCH_NFS_SERVER
-measure_nfs_server()
-{
- ulong calls;
- ulong badcalls;
- ulong v2read;
- ulong v2write;
- ulong v3read;
- ulong v3write;
-
- calls = tmp_nfs.calls;
- badcalls = tmp_nfs.badcalls;
- v2read = tmp_rfsproccnt_v2.read;
- v2write = tmp_rfsproccnt_v2.write;
- v3read = tmp_rfsproccnt_v3.read;
- v3write = tmp_rfsproccnt_v3.write;
-
- put_output("nfss_calls", sprintf("%10lu", calls));
- put_output("nfss_bad", sprintf("%8lu", badcalls));
- put_output(" v2reads", sprintf("%8lu", v2read));
- put_output("v2writes", sprintf("%8lu", v2write));
- put_output(" v3reads", sprintf("%8lu", v3read));
- put_output("v3writes", sprintf("%8lu", v3write));
-}
-#endif
-
-#ifdef WATCH_MOUNTS
-measure_mounts()
-{
- statvfs_t vfs_array[1];
- statvfs_t vfs;
- string comment_fmt;
- string kbytes_fmt;
- string inode_fmt;
- string percent_fmt;
- ulong kbytes_used;
- ulong inodes_used;
- double block_factor;
- int comment_length;
- int previous_count = -1;
- int current_count;
-
- current_count = 0;
- // Traverse the mount table to find mounted ufs/vxfs file systems.
- for (mnt$mnt.number$=0; mnt$mnt.number$ != -1; mnt$mnt.number$++) {
- tmp_mnt = mnt$mnt;
- if (tmp_mnt.mnt_fstype == "ufs" || tmp_mnt.mnt_fstype == "vxfs") {
- // Skip locally mounted /cdrom partitions.
- if (tmp_mnt.mnt_mountp =~ "^/cdrom/") {
- continue;
- }
-
- // Skip snapshot file systems to avoid output format changes as
- // they are mounted and unmounted.
- if (tmp_mnt.mnt_mountp =~ "^/snapshots/") {
- continue;
- }
-
- if (statvfs(tmp_mnt.mnt_mountp, vfs_array) == -1) {
- continue;
- }
- vfs = vfs_array[0];
- current_count++;
-
- // Generate the format strings for the comment and for the data.
- comment_fmt = sprintf("mnt%%c_%s", tmp_mnt.mnt_mountp);
- comment_length = strlen(comment_fmt) - 1;
- kbytes_fmt = sprintf("%%%d.0f", comment_length);
- inode_fmt = sprintf("%%%dld", comment_length);
- percent_fmt = sprintf("%%%d.3f", comment_length);
-
- // Calculate the number of 1 kilobyte blocks on the disk.
- block_factor = vfs.f_frsize/1024;
-
- // Capital letters refer to the disk usage in kilobytes. Lower case
- // letters refer to inode usage.
- // C - Capacity of the disk.
- // U - Used capacity.
- // A - Available capacity for non-root users.
- // P - Percent used.
- kbytes_used = vfs.f_blocks - vfs.f_bfree;
- inodes_used = vfs.f_files - vfs.f_ffree;
-
- put_output(sprintf(comment_fmt, 'C'),
- sprintf(kbytes_fmt, block_factor*vfs.f_blocks));
- put_output(sprintf(comment_fmt, 'U'),
- sprintf(kbytes_fmt, block_factor*kbytes_used));
- put_output(sprintf(comment_fmt, 'A'),
- sprintf(kbytes_fmt, block_factor*vfs.f_bavail));
- put_output(sprintf(comment_fmt, 'P'),
- sprintf(percent_fmt,
- 100.0*kbytes_used/(vfs.f_blocks + vfs.f_bavail - vfs.f_bfree)));
-
- put_output(sprintf(comment_fmt, 'c'),
- sprintf(inode_fmt, vfs.f_files));
- put_output(sprintf(comment_fmt, 'u'),
- sprintf(inode_fmt, inodes_used));
- put_output(sprintf(comment_fmt, 'a'),
- sprintf(inode_fmt, vfs.f_favail));
- put_output(sprintf(comment_fmt, 'p'),
- sprintf(percent_fmt,
- 100.0*inodes_used/(vfs.f_files + vfs.f_favail - vfs.f_ffree)));
-
- }
- }
-
- // If the number of mounted filesystems changes, then print new headers.
- if (current_count != previous_count) {
- print_header = 1;
- previous_count = current_count;
- }
-}
-#endif
-
-#ifdef WATCH_DISK
-measure_disk()
-{
- // These two variables are treated as static variables to keep track
- // of any changes to the number of disks and tapes on the system.
- int previous_disk_count = -1;
- int previous_tape_count = -1;
-
- double mean_disk_busy;
- double peak_disk_busy;
- double total_disk_reads;
- double total_disk_writes;
- double total_disk_readk;
- double total_disk_writek;
- int disk_count;
-
- double total_tape_reads;
- double total_tape_writes;
- double total_tape_readk;
- double total_tape_writek;
- int tape_count;
-
- int i;
-
- mean_disk_busy = 0.0;
- peak_disk_busy = 0.0;
- total_disk_reads = 0.0;
- total_disk_writes = 0.0;
- total_disk_readk = 0.0;
- total_disk_writek = 0.0;
- disk_count = 0;
-
- total_tape_reads = 0.0;
- total_tape_writes = 0.0;
- total_tape_readk = 0.0;
- total_tape_writek = 0.0;
- tape_count = 0;
-
-#ifdef USE_KSTAT_IO
- for (i=0; i<ORCA_io_dev_count; ++i) {
- // Record tape drive st devices differently than regular disk devices.
- if (ORCA_io_dev_info[i].short_name =~ "^st.*") {
- tape_count++;
- total_tape_reads += ORCA_io_dev_info[i].reads;
- total_tape_writes += ORCA_io_dev_info[i].writes;
- total_tape_readk += ORCA_io_dev_info[i].kreads;
- total_tape_writek += ORCA_io_dev_info[i].kwrites;
- put_output(sprintf("tape_runp_%s", ORCA_io_dev_info[i].long_name),
- sprintf("%16.5f", ORCA_io_dev_info[i].run_percent));
- continue;
- }
- // Block the listing of floppy drives for now.
- if (ORCA_io_dev_info[i].short_name =~ "^fd.*") {
- continue;
- }
- disk_count++;
- put_output(sprintf("disk_runp_%s", ORCA_io_dev_info[i].long_name),
- sprintf("%16.5f", ORCA_io_dev_info[i].run_percent));
-
- put_output(sprintf("disk_svct_%s", ORCA_io_dev_info[i].long_name),
- sprintf("%16.5f", ORCA_io_dev_info[i].service));
-
- // Comments from Damon Atkins <Damon.Atkins at nabaus.com.au>. 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<GLOBAL_disk_count; ++i) {
- disk_count++;
- put_output(sprintf("disk_runp_%s", GLOBAL_disk[i].info.long_name),
- sprintf("%16.5f", GLOBAL_disk[i].run_percent));
-
- put_output(sprintf("disk_svct_%s", GLOBAL_disk[i].info.long_name),
- sprintf("%16.5f", GLOBAL_disk[i].service));
-
- // Comments from Damon Atkins <Damon.Atkins at nabaus.com.au>. 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<number_regexs; ++i) {
- count_procs_results[i] = 0;
- }
-
- for (p=first_proc(); p.pr_pid != -1; p=next_proc()) {
- for (i=0; i<number_regexs; ++i) {
- if (p.pr_fname =~ regexs[i]) {
- ++count_procs_results[i];
- }
- }
- }
-}
-
-put_httpd()
-{
- string proc_regexs[2];
-
- proc_regexs[0] = www_server_proc_name;
- proc_regexs[1] = www_server_secure_proc_name;
-
- count_procs(sizeof(proc_regexs)/sizeof(proc_regexs[0]), proc_regexs);
-
- put_output("#httpds", sprintf("%7d", count_procs_results[0]));
- put_output("#httpsds", sprintf("%8d", count_procs_results[1]));
- put_output("httpop/s", sprintf("%8.2f", httpops/www_interval));
- put_output("http/p5s", sprintf("%8.2f", httpops5));
- put_output("cndget/s", sprintf("%8.2f", httpop_condgets/www_interval));
- put_output("search/s", sprintf("%8.3f", httpop_searches/www_interval));
- put_output(" cgi/s", sprintf("%8.3f", httpop_cgi_bins/www_interval));
- put_output(" htErr/s", sprintf("%8.3f", httpop_errors/www_interval));
- put_output(" httpb/s", sprintf("%8.0f", dwnld_totalz/www_interval));
- put_output(" %to1KB", sprintf("%8.2f", dtmp*dwnld_size[0]));
- put_output(" %to10KB", sprintf("%8.2f", dtmp*dwnld_size[1]));
- put_output("%to100KB", sprintf("%8.2f", dtmp*dwnld_size[2]));
- put_output(" %to1MB", sprintf("%8.2f", dtmp*dwnld_size[3]));
- put_output("%over1MB", sprintf("%8.2f", dtmp*dwnld_size[4]));
- put_output(www_gateway, sprintf("%8.2f", gateops/www_interval));
-#if WATCH_PROXY || WATCH_SQUID
- put_output(" %indir", sprintf("%8.2f", dtmp * prxy_squid_indirect));
- put_output("%cch_hit", sprintf("%8.2f", dtmp * prxy_squid_cache_hits));
-#ifdef WATCH_PROXY
- put_output("%cch_wrt", sprintf("%8.2f", dtmp * prxy_cache_writes));
- put_output("%cch_unc", sprintf("%8.2f", dtmp * prxy_uncacheable));
-#else
- put_output("%cch_mis", sprintf("%8.2f", dtmp * squid_cache_misses));
- put_output("%cch_req", sprintf("%8.2f", dtmp * squid_icp_requests));
- put_output("%cch_qry", sprintf("%8.2f", dtmp * squid_icp_queries));
-#endif
- put_output(" xfr_t", sprintf("%8.2f", 0.01 * dtmp * www_dwnld_time_sum));
- put_output(" xfr1_t", sprintf("%8.2f", www_dwnld_time_by_size[0]));
- put_output(" xfr10_t", sprintf("%8.2f", www_dwnld_time_by_size[1]));
- put_output("xfr100_t", sprintf("%8.2f", www_dwnld_time_by_size[2]));
- put_output(" xfr1M_t", sprintf("%8.2f", www_dwnld_time_by_size[3]));
- put_output("xfro1M_t", sprintf("%8.2f", www_dwnld_time_by_size[4]));
-#elif WATCH_YAHOO
- put_output(" wprc_t", sprintf("%9.5f", 0.01 * dtmp * www_dwnld_time_sum));
- put_output(" wprc1_t", sprintf("%9.5f", www_dwnld_time_by_size[0]));
- put_output(" wprc10_t", sprintf("%9.5f", www_dwnld_time_by_size[1]));
- put_output("wprc100_t", sprintf("%9.5f", www_dwnld_time_by_size[2]));
- put_output(" wprc1M_t", sprintf("%9.5f", www_dwnld_time_by_size[3]));
- put_output("wprco1M_t", sprintf("%9.5f", www_dwnld_time_by_size[4]));
-#endif
-}
-#endif
+//
+// Orcallator.se, a log generating performance monitor.
+//
+// This program logs many different system quantities to a log file
+// for later processing.
+//
+// Author: Blair Zajac <blair at orcaware.com>.
+//
+// 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 <stdio.se>
+#include <stdlib.se>
+#include <unistd.se>
+#include <string.se>
+#include <time.se>
+#include <kstat.se>
+#include <stat.se>
+#include <utsname.se>
+
+#include <p_iostat_class.se>
+//#include <p_netstat_class.se>
+#include <orca_p_netstat_class.se>
+//#include <p_vmstat_class.se>
+#include <orca_p_vmstat_class.se>
+#include <pure_rules.se>
+#include <live_rules.se>
+#include <mib.se>
+#include <tcp_class.se>
+#include <tcp_rules.se>
+
+#ifdef WATCH_MOUNTS
+#include <mnt_class.se>
+#include <statvfs.se>
+#endif
+
+#if WATCH_CPU || WATCH_WEB
+#include <proc.se>
+
+#ifdef WATCH_CPU
+// This is the maximum pid on Solaris hosts.
+#define DEFAULT_MAXPID 30000
+#include <fcntl.se>
+#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 <sys_kstat.se>
+#include <tapeinfo.se>
+// 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<current_column; ++i) {
+ fprintf(out_log_fp, "%s", data[i]);
+ if (i != current_column-1) {
+ fputc(' ', out_log_fp);
+ }
+ }
+ fputc('\n', out_log_fp);
+ fflush(out_log_fp);
+}
+
+// Flush all of the stored output.
+print_output() {
+ if (print_header != 0) {
+ print_columns(col_comment);
+ print_header = 0;
+ }
+ print_columns(col_data);
+
+ // Save the current number of columns stored and the column names so
+ // that the next set can be compared with to determine if the
+ // headers should be printed again.
+ col_previous_comment = col_comment;
+ previous_number_columns = current_column - 1;
+ current_column = 0;
+}
+
+// Sets out_log_fp to the output file pointer. Creates or appends to
+// the log file if OUTDIR is set, otherwise sets the file pointer to
+// STDOUT. It start a new log file each day. It compresses the
+// 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;
+
+ if (output_directory == nil) {
+ // No output directory so use stdout.
+ if (out_log_fp == 0) {
+ // First time, so print header and set out_log_fp.
+ out_log_fp = stdout;
+ print_header = 1;
+ }
+ return;
+ }
+
+ // Check if a new output log is needed. This happens when the day
+ // changes, if the number of columns changes or if the column
+ // comments change since the last measurement.
+ if (now.tm_yday != then.tm_yday ||
+ previous_number_columns != (current_column - 1)) {
+ need_new_log_file = 1;
+ } else {
+ need_new_log_file = 0;
+ for (i=0; i<current_column; ++i) {
+ if (col_comment[i] != col_previous_comment[i]) {
+ need_new_log_file = 1;
+ break;
+ }
+ }
+ }
+
+ // Maintain daily output log files in OUTDIR.
+ if (need_new_log_file != 0) {
+ // Close and optionally compress the existing output file. The
+ // first time through out_log_fp will be 0.
+ if (out_log_fp != 0) {
+ if (fclose(out_log_fp) != 0) {
+ perror("cannot close output log file");
+ }
+ if (compress != nil) {
+ system(sprintf(compress, output_filename));
+ }
+ }
+
+ // Get the new filename. Check for already existing uncompressed
+ // log filenames and compressed log filenames.
+ strftime(tm_buf, sizeof(tm_buf), "%Y-%m-%d", now);
+
+ // If the previous log filename has the same date, then increment
+ // the file number, otherwise reset it to 0. The first time
+ // through, output_filename will be nil.
+ if (nil != output_filename && output_filename =~ tm_buf) {
+ file_number++;
+ } else {
+ file_number = 0;
+ }
+
+ while (1 == 1) {
+
+ // Check for the existence of uncompressed and compressed log
+ // files. If there is an uncompressed log file but no
+ // compressed ones, then compress it in the background. If
+ // either an uncompressed or compressed log file exist, then
+ // check the next file number.
+ output_filename = sprintf("%s/orcallator-%s-%03d", output_directory,
+ tm_buf,
+ file_number);
+ result = stat(output_filename, log_file_stat);
+ if (result != -1) {
+ exists_uncompressed = 1;
+ } else {
+ exists_uncompressed = 0;
+ }
+
+ exists_compressed = 0;
+ for (i=0; i<NUMBER_COMPRESS_SUFFIXES; ++i) {
+ compressed_filename = sprintf("%s%s", output_filename,
+ compression_suffixes[i]);
+ result = stat(compressed_filename, log_file_stat);
+ if (result != -1) {
+ exists_compressed = 1;
+ break;
+ }
+ }
+
+ if (nil != compress &&
+ 0 != exists_uncompressed &&
+ 0 == exists_compressed) {
+ system(sprintf(compress, output_filename));
+ }
+
+ if (0 != exists_uncompressed || 0 != exists_compressed) {
+ ++file_number;
+ } else {
+ break;
+ }
+ }
+
+ // Open the file for appending.
+ out_log_fp = fopen(output_filename, "a");
+ if (out_log_fp == 0) {
+ perror("cannot open output log file");
+ exit(1);
+ }
+
+ // Always write a new header.
+ print_header = 1;
+ then = now;
+ }
+}
+
+int main(int argc, string argv[])
+{
+ 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);
+ nodename = u[0].nodename;
+
+ program_name = argv[0];
+
+ // Handle the command line arguments.
+ switch (argc) {
+ case 1:
+ break;
+ case 2:
+ interval = atoi(argv[1]);
+ break;
+ default:
+ fprintf(stderr, "usage: se [-Defines] %s [interval]\n", program_name);
+ fprintf(stderr, "The default interval is %d seconds.\n", SAMPLE_INTERVAL);
+ fprintf(stderr, "%s uses the following environmental variables:\n", program_name);
+ fprintf(stderr, " OUTDIR directory to write log files, output to stdout if not set\n");
+ fprintf(stderr, " WEB_SERVER regex to match web server's name (def = httpd)\n");
+ fprintf(stderr, " WEB_SERVER_SECURE regex to match secure web server's name (def = httpsd)\n");
+ fprintf(stderr, " WEB_LOG location of web server access log (/httpd/logs/access)\n");
+ fprintf(stderr, " GATEWAY special web address to monitor (some.where.com)\n");
+ fprintf(stderr, " SEARCHURL regex for search scripts (def = search.cgi)\n");
+ fprintf(stderr, " COMPRESSOR compress log files with this command (\"bzip2 -9\")\n");
+ fprintf(stderr, "Add these defines to enable monitoring of specific subsystems:\n");
+ fprintf(stderr, " -DWATCH_WEB watch web server access logs\n");
+ fprintf(stderr, " -DWATCH_PROXY use WEB_LOG as a NCSA style proxy log\n");
+ fprintf(stderr, " -DWATCH_SQUID use WEB_LOG as a Squid log\n");
+ fprintf(stderr, " -DWATCH_OS includes all of the below:\n");
+ fprintf(stderr, " -DWATCH_CPU watch the cpu load, run queue, etc\n");
+ fprintf(stderr, " -DWATCH_MUTEX watch the number of mutex spins\n");
+ fprintf(stderr, " -DWATCH_NET watch all Ethernet interfaces\n");
+ fprintf(stderr, " -DWATCH_TCP watch all the TCP/IP stack\n");
+ fprintf(stderr, " -DWATCH_NFS_CLIENT watch NFS client requests\n");
+ fprintf(stderr, " -DWATCH_NFS_SERVER watch NFS server requests\n");
+ fprintf(stderr, " -DWATCH_MOUNTS watch usage of mount points\n");
+ fprintf(stderr, " -DWATCH_DISK watch disk read/write usage\n");
+ fprintf(stderr, " -DWATCH_DNLC watch the directory name lookup cache\n");
+ fprintf(stderr, " -DWATCH_INODE watch the inode cache\n");
+ fprintf(stderr, " -DWATCH_RAM watch memory usage\n");
+ fprintf(stderr, " -DWATCH_PAGES watch where pages are allocated\n");
+ exit(1);
+ break;
+ }
+
+ // Initialize the various structures.
+ initialize();
+
+ // Run forever. If WATCH_WEB is defined, then have measure_web()
+ // do the sleeping while it is watching the access log file until the
+ // next update time for the whole operating system. Also, collect the
+ // data from the access log file before printing any output.
+ for (;;) {
+ // Calculate the next time to sleep to that is an integer multiple of
+ // the interval time. Make sure that at least half of the interval
+ // passes before waking up.
+ now = time(0);
+ sleep_till = (now/interval)*interval;
+ while (sleep_till < now + interval*0.5) {
+ sleep_till += interval;
+ }
+
+#ifdef WATCH_WEB
+ measure_web(sleep_till);
+#else
+ sleep_till_and_count_new_processes(sleep_till);
+#endif
+
+ // Get the current time.
+ now = time(0);
+ tm_now = localtime(&now);
+
+ measure_os(now, tm_now);
+
+#ifdef WATCH_WEB
+ put_httpd();
+#endif
+
+ // Get a file descriptor to write to. Maintains daily output files.
+ check_output_log_filename(tm_now);
+
+ // Print the output.
+ print_output();
+ }
+ return 0;
+}
+
+initialize()
+{
+#ifdef WATCH_CPU
+ int i;
+#endif
+
+ // Get the command to compress the log files.
+ if (compress == nil || compress == "") {
+ compress = nil;
+ }
+ else {
+ compress = sprintf("%s %%s &", compress);
+ }
+
+#ifdef WATCH_CPU
+ // Initialize the process spawning rate measurement variables.
+ // Determine if the kernel can be read to measure the last pid.
+ i = open("/dev/kmem", O_RDONLY);
+ if (i != -1) {
+ close(i);
+ can_read_kernel = 1;
+ mpid_previous = kvm$mpid;
+ mpid_then = gethrtime();
+ mpid_current = mpid_previous;
+
+ mpid5_then = mpid_then;
+ mpid5_previous = mpid_previous;
+ mpid5_current = mpid_previous;
+ mpid5_rate = 0;
+ }
+#endif
+
+#ifdef WATCH_WEB
+ // Initialize those variables that were not set with environmental
+ // variables.
+ if (www_search_url == nil || www_search_url == "") {
+ www_search_url = "search.cgi";
+ }
+
+ if (www_server_proc_name == nil || www_server_proc_name == "") {
+ www_server_proc_name = "httpd";
+ }
+
+ if (www_server_secure_proc_name == nil ||
+ www_server_secure_proc_name == "") {
+ www_server_secure_proc_name = "httpsd";
+ }
+
+ if (www_gateway == nil || www_gateway == "" ) {
+ www_gateway = "NoGatway";
+ www_gatelen = 0;
+ }
+ else {
+ www_gatelen = strlen(www_gateway);
+ }
+
+ // Initialize the web server watching variables. Move the file pointer
+ // to the end of the web access log and note the current time.
+ if (www_log_filename != nil) {
+ www_log_fp = fopen(www_log_filename, "r");
+ www_log_ino = 0;
+ www_log_size = 0;
+ if (www_log_fp != 0) {
+ if (fstat(fileno(www_log_fp), www_log_stat) == 0) {
+ www_log_ino = www_log_stat[0].st_ino;
+ www_log_size = www_log_stat[0].st_size;
+ }
+ // Move to the end of the file.
+ fseek(www_log_fp, 0, 2);
+ }
+ }
+
+ www_then = gethrtime();
+ www5_then = www_then;
+#endif
+
+ // Sleep to give the disks a chance to update.
+ sleep(DISK_UPDATE_RATE);
+
+ // Get the clock tick rate.
+ hz = sysconf(_SC_CLK_TCK);
+
+ // Get the page size.
+ page_size = sysconf(_SC_PAGESIZE);
+
+ // Calculate the system boot time.
+ boot_time = time(0) - (kstat$misc.clk_intr / hz);
+
+ // Perform the first measurement of the system.
+ _measure_os();
+}
+
+// Measure the system statistics all at once.
+_measure_os()
+{
+ tmp_lr_cpu = lr_cpu$cpu;
+ tmp_lr_mutex = lr_mutex$m;
+ tmp_lr_net = lr_net$nr;
+ tmp_lr_tcp = lr_tcp$tcp;
+ tmp_lr_rpcclient = lr_rpcclient$r;
+ tmp_lr_disk = lr_disk$dr;
+ tmp_lr_dnlc = lr_dnlc$dnlc;
+ tmp_lr_inode = lr_inode$inode;
+ tmp_lr_ram = lr_ram$ram;
+ tmp_lr_swapspace = lr_swapspace$s;
+ tmp_lr_kmem = lr_kmem$kmem;
+
+ tmp_kstat_misc = kstat$misc;
+#ifdef WATCH_NFS_SERVER
+ tmp_nfs = kstat$nfs;
+ tmp_rfsproccnt_v2 = kstat$rfsproccnt_v2;
+ tmp_rfsproccnt_v3 = kstat$rfsproccnt_v3;
+#endif
+#ifdef WATCH_PAGES
+ tmp_kstat_pages = kstat$pages;
+#endif
+#ifdef WATCH_TCP
+ tmp_tcp = tcp$tcp;
+#endif
+
+#ifdef USE_KSTAT_IO
+ orca_io_info_update();
+#endif
+}
+
+measure_os(long now, tm_t tm_now)
+{
+ // Measure the system now.
+ _measure_os();
+
+ // Take care of miscellaneous measurements.
+ measure_misc(now, tm_now);
+
+ // Take care of cpu.
+#ifdef WATCH_CPU
+ measure_cpu();
+#endif
+
+ // Take care of mutexes.
+#ifdef WATCH_MUTEX
+ measure_mutex();
+#endif
+
+ // If the CPUs or mutexes are being monitored, then output the
+ // number online CPUs on the system. The GLOBAL_pvm_ncpus variable
+ // is used after it has been updated in _measure_os().
+#if defined(WATCH_CPU) || defined (WATCH_MUTEX)
+ put_output("ncpus", sprintf("%5d", GLOBAL_pvm_ncpus));
+#endif
+
+ // Take care of mount points.
+#ifdef WATCH_MOUNTS
+ measure_mounts();
+#endif
+
+ // Take care of the disks.
+#ifdef WATCH_DISK
+ measure_disk();
+#endif
+
+ // Take care of ram.
+#ifdef WATCH_RAM
+ measure_ram();
+#endif
+
+ // Take care of the network.
+#ifdef WATCH_NET
+ measure_net();
+#endif
+
+ // Take care of TCP/IP.
+#ifdef WATCH_TCP
+ measure_tcp();
+#endif
+
+ // Take care of NFS client statistics.
+#ifdef WATCH_NFS_CLIENT
+ measure_nfs_client();
+#endif
+
+ // Take care of NFS server statistics.
+#ifdef WATCH_NFS_SERVER
+ measure_nfs_server();
+#endif
+
+ // Take care of DNLC.
+#ifdef WATCH_DNLC
+ measure_dnlc();
+#endif
+
+ // Take care of the inode cache.
+#ifdef WATCH_INODE
+ measure_inode();
+#endif
+
+ // Take care of page allocations.
+#ifdef WATCH_PAGES
+ measure_pages();
+#endif
+}
+
+/*
+ * State as a character.
+ */
+char state_char(int state) {
+ switch(state) {
+ case ST_WHITE: return 'w'; /* OK states are lower case. */
+ case ST_BLUE: return 'b';
+ case ST_GREEN: return 'g';
+ case ST_AMBER: return 'A'; /* Bad states are upper case to stand out. */
+ case ST_RED: return 'R';
+ case ST_BLACK: return 'B';
+ default: return 'I'; /* Invalid state. */
+ }
+}
+
+/*
+ * State as a digit.
+ */
+int state_digit(int state) {
+ switch(state) {
+ case ST_WHITE: return 0; /* OK states are zero. */
+ case ST_BLUE: return 1;
+ case ST_GREEN: return 2;
+ case ST_AMBER: return 4; /* Bad states have a non-zero value. */
+ case ST_RED: return 8;
+ case ST_BLACK: return 16;
+ default: return -1; /* Invalid state. */
+ }
+}
+
+measure_misc(long now, tm_t tm_now)
+{
+ char states[12];
+ char tm_buf[16];
+ int statetmp;
+
+ states = "wwwwwwwwwww";
+ strftime(tm_buf, sizeof(tm_buf), "%T", tm_now);
+
+ put_output("timestamp ", sprintf("%10d", now));
+ put_output("locltime", tm_buf);
+ put_output(" uptime", sprintf("%8d", now - boot_time));
+
+ statetmp = tmp_lr_disk.state;
+ states[0] = state_char(statetmp);
+ put_output("state_D", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_net.state;
+ states[1] = state_char(statetmp);
+ put_output("state_N", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_rpcclient.state;
+ states[2] = state_char(statetmp);
+ put_output("state_n", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_swapspace.state;
+ states[3] = state_char(statetmp);
+ put_output("state_s", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_ram.state;
+ states[4] = state_char(statetmp);
+ put_output("state_r", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_kmem.state;
+ states[5] = state_char(statetmp);
+ put_output("state_k", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_cpu.state;
+ states[6] = state_char(statetmp);
+ put_output("state_c", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_mutex.state;
+ states[7] = state_char(statetmp);
+ put_output("state_m", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_dnlc.state;
+ states[8] = state_char(statetmp);
+ put_output("state_d", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_inode.state;
+ states[9] = state_char(statetmp);
+ put_output("state_i", sprintf("%7d", state_digit(statetmp)));
+
+ statetmp = tmp_lr_tcp.state;
+ states[10] = state_char(statetmp);
+ put_output("state_t", sprintf("%7d", state_digit(statetmp)));
+
+ put_output("DNnsrkcmdit", states);
+}
+
+// This function puts the program to sleep until the beginning of the
+// sleep_till second (as measured in the number of seconds from the
+// Unix Epoch (00:00:00 UTC, January 1, 1970)) using microsecond sleep
+// intervals to wake from sleep as close to the beginning of the
+// sleep_till second as possible.
+orca_sleep_till(long sleep_till)
+{
+ timeval_t now[1];
+ long time_to_sleep;
+
+ gettimeofday(now, 0);
+ time_to_sleep = sleep_till - now[0].tv_sec;
+ while (time_to_sleep > 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<tmp_lr_net.net_count; ++i) {
+ // Skip unused interfaces.
+// if (GLOBAL_net[i].up == 0) {
+// continue;
+// }
+ current_count++;
+ put_output(sprintf("%5sIpkt/s", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].ipackets));
+ put_output(sprintf("%5sOpkt/s", tmp_lr_net.names[i]),
+ 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));
+ put_output(sprintf("%5sInDtSz/p", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].idtsize));
+ put_output(sprintf("%5sInOvH%%/p", tmp_lr_net.names[i]),
+ 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));
+ put_output(sprintf("%5sOuDtSz/p", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].odtsize));
+ put_output(sprintf("%5sOuOvH%%/p", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].ohdrovhd));
+ put_output(sprintf("%5sIErr/s", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].ierrors));
+ put_output(sprintf("%5sOErr/s", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].oerrors));
+ put_output(sprintf("%5sColl%%", tmp_lr_net.names[i]),
+ sprintf("%10.3f", GLOBAL_net[i].collpercent));
+ put_output(sprintf("%5sNoCP/s", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].nocanput));
+ put_output(sprintf("%5sDefr/s", tmp_lr_net.names[i]),
+ sprintf("%11.3f", GLOBAL_net[i].defer));
+ }
+
+ // If the number of up interfaces changes, then print new headers.
+ if (current_count != previous_count) {
+ print_header = 1;
+ previous_count = current_count;
+ }
+}
+#endif
+
+#ifdef WATCH_TCP
+measure_tcp()
+{
+ double tmp_tcp_InDtpPkt;
+ double tmp_tcp_OuDtpPkt;
+ double tmp_tcp_InOvHPct;
+ double tmp_tcp_OuOvHPct;
+
+ put_output("tcp_Iseg/s", sprintf("%10.3f", tmp_tcp.InDataSegs));
+ put_output("tcp_Oseg/s", sprintf("%10.3f", tmp_tcp.OutDataSegs));
+ put_output("tcp_InKB/s", sprintf("%10.3f", tmp_tcp.InDataBytes/1024.0));
+ put_output("tcp_OuKB/s", sprintf("%10.3f", tmp_tcp.OutDataBytes/1024.0));
+ if ( tmp_tcp.InDataSegs == 0.0 ) {
+ tmp_tcp_InDtpPkt = 0.0;
+ tmp_tcp_InOvHPct = 0.0;
+ } else {
+ tmp_tcp_InDtpPkt = tmp_tcp.InDataBytes/tmp_tcp.InDataSegs;
+ tmp_tcp_InOvHPct = 100 * (40 * tmp_tcp.InDataSegs / (40 * tmp_tcp.InDataSegs + tmp_tcp.InDataBytes));
+ }
+ put_output("tcp_InDtSz/p", sprintf("%10.3f", tmp_tcp_InDtpPkt));
+ put_output("tcp_InOvH%/p", sprintf("%8.3f", tmp_tcp_InOvHPct));
+ if ( tmp_tcp.OutDataSegs == 0.0 ) {
+ tmp_tcp_OuDtpPkt = 0.0;
+ tmp_tcp_OuOvHPct = 0.0;
+ } else {
+ tmp_tcp_OuDtpPkt = tmp_tcp.OutDataBytes/tmp_tcp.OutDataSegs;
+ tmp_tcp_OuOvHPct = 100 * (40 * tmp_tcp.OutDataSegs / (40 * tmp_tcp.OutDataSegs + tmp_tcp.OutDataBytes));
+ }
+ put_output("tcp_OuDtSz/p", sprintf("%10.3f", tmp_tcp_OuDtpPkt));
+ put_output("tcp_OuOvH%/p", sprintf("%8.3f", tmp_tcp_OuOvHPct));
+ put_output("tcp_Ret%", sprintf("%8.3f", tmp_tcp.RetransPercent));
+ put_output("tcp_Dup%", sprintf("%8.3f", tmp_tcp.InDupPercent));
+ put_output("tcp_Icn/s", sprintf("%9.3f", tmp_tcp.PassiveOpens));
+ put_output("tcp_Ocn/s", sprintf("%9.3f", tmp_tcp.ActiveOpens));
+ put_output("tcp_estb", sprintf("%8lu", tmp_tcp.last.tcpCurrEstab));
+ put_output("tcp_Rst/s", sprintf("%9.3f", tmp_tcp.OutRsts));
+ put_output("tcp_Atf/s", sprintf("%9.3f", tmp_tcp.AttemptFails));
+ put_output("tcp_Ldrp/s", sprintf("%10.3f", tmp_tcp.ListenDrop));
+ put_output("tcp_LdQ0/s", sprintf("%10.3f", tmp_tcp.ListenDropQ0));
+ put_output("tcp_HOdp/s", sprintf("%10.3f", tmp_tcp.HalfOpenDrop));
+}
+#endif
+
+#ifdef WATCH_NFS_CLIENT
+measure_nfs_client()
+{
+ put_output("nfs_call/s", sprintf("%10.3f", tmp_lr_rpcclient.calls));
+ put_output("nfs_timo/s", sprintf("%10.3f", tmp_lr_rpcclient.timeouts));
+ put_output("nfs_badx/s", sprintf("%10.3f", tmp_lr_rpcclient.badxids));
+}
+#endif
+
+#ifdef WATCH_NFS_SERVER
+measure_nfs_server()
+{
+ ulong calls;
+ ulong badcalls;
+ ulong v2read;
+ ulong v2write;
+ ulong v3read;
+ ulong v3write;
+
+ calls = tmp_nfs.calls;
+ badcalls = tmp_nfs.badcalls;
+ v2read = tmp_rfsproccnt_v2.read;
+ v2write = tmp_rfsproccnt_v2.write;
+ v3read = tmp_rfsproccnt_v3.read;
+ v3write = tmp_rfsproccnt_v3.write;
+
+ put_output("nfss_calls", sprintf("%10lu", calls));
+ put_output("nfss_bad", sprintf("%8lu", badcalls));
+ put_output(" v2reads", sprintf("%8lu", v2read));
+ put_output("v2writes", sprintf("%8lu", v2write));
+ put_output(" v3reads", sprintf("%8lu", v3read));
+ put_output("v3writes", sprintf("%8lu", v3write));
+}
+#endif
+
+#ifdef WATCH_MOUNTS
+measure_mounts()
+{
+ statvfs_t vfs_array[1];
+ statvfs_t vfs;
+ string comment_fmt;
+ string kbytes_fmt;
+ string inode_fmt;
+ string percent_fmt;
+ ulong kbytes_used;
+ ulong inodes_used;
+ double block_factor;
+ int comment_length;
+ int previous_count = -1;
+ int current_count;
+
+ current_count = 0;
+ // Traverse the mount table to find mounted ufs/vxfs file systems.
+ for (mnt$mnt.number$=0; mnt$mnt.number$ != -1; mnt$mnt.number$++) {
+ tmp_mnt = mnt$mnt;
+ if (tmp_mnt.mnt_fstype == "ufs" || tmp_mnt.mnt_fstype == "vxfs") {
+ // Skip locally mounted /cdrom partitions.
+ if (tmp_mnt.mnt_mountp =~ "^/cdrom/") {
+ continue;
+ }
+
+ // Skip snapshot file systems to avoid output format changes as
+ // they are mounted and unmounted.
+ if (tmp_mnt.mnt_mountp =~ "^/snapshots/") {
+ continue;
+ }
+
+ if (statvfs(tmp_mnt.mnt_mountp, vfs_array) == -1) {
+ continue;
+ }
+ vfs = vfs_array[0];
+ current_count++;
+
+ // Generate the format strings for the comment and for the data.
+ comment_fmt = sprintf("mnt%%c_%s", tmp_mnt.mnt_mountp);
+ comment_length = strlen(comment_fmt) - 1;
+ kbytes_fmt = sprintf("%%%d.0f", comment_length);
+ inode_fmt = sprintf("%%%dld", comment_length);
+ percent_fmt = sprintf("%%%d.3f", comment_length);
+
+ // Calculate the number of 1 kilobyte blocks on the disk.
+ block_factor = vfs.f_frsize/1024;
+
+ // Capital letters refer to the disk usage in kilobytes. Lower case
+ // letters refer to inode usage.
+ // C - Capacity of the disk.
+ // U - Used capacity.
+ // A - Available capacity for non-root users.
+ // P - Percent used.
+ kbytes_used = vfs.f_blocks - vfs.f_bfree;
+ inodes_used = vfs.f_files - vfs.f_ffree;
+
+ put_output(sprintf(comment_fmt, 'C'),
+ sprintf(kbytes_fmt, block_factor*vfs.f_blocks));
+ put_output(sprintf(comment_fmt, 'U'),
+ sprintf(kbytes_fmt, block_factor*kbytes_used));
+ put_output(sprintf(comment_fmt, 'A'),
+ sprintf(kbytes_fmt, block_factor*vfs.f_bavail));
+ put_output(sprintf(comment_fmt, 'P'),
+ sprintf(percent_fmt,
+ 100.0*kbytes_used/(vfs.f_blocks + vfs.f_bavail - vfs.f_bfree)));
+
+ put_output(sprintf(comment_fmt, 'c'),
+ sprintf(inode_fmt, vfs.f_files));
+ put_output(sprintf(comment_fmt, 'u'),
+ sprintf(inode_fmt, inodes_used));
+ put_output(sprintf(comment_fmt, 'a'),
+ sprintf(inode_fmt, vfs.f_favail));
+ put_output(sprintf(comment_fmt, 'p'),
+ sprintf(percent_fmt,
+ 100.0*inodes_used/(vfs.f_files + vfs.f_favail - vfs.f_ffree)));
+
+ }
+ }
+
+ // If the number of mounted filesystems changes, then print new headers.
+ if (current_count != previous_count) {
+ print_header = 1;
+ previous_count = current_count;
+ }
+}
+#endif
+
+#ifdef WATCH_DISK
+measure_disk()
+{
+ // These two variables are treated as static variables to keep track
+ // of any changes to the number of disks and tapes on the system.
+ int previous_disk_count = -1;
+ int previous_tape_count = -1;
+
+ double mean_disk_busy;
+ double peak_disk_busy;
+ double total_disk_reads;
+ double total_disk_writes;
+ double total_disk_readk;
+ double total_disk_writek;
+ int disk_count;
+
+ double total_tape_reads;
+ double total_tape_writes;
+ double total_tape_readk;
+ double total_tape_writek;
+ int tape_count;
+
+ int i;
+
+ mean_disk_busy = 0.0;
+ peak_disk_busy = 0.0;
+ total_disk_reads = 0.0;
+ total_disk_writes = 0.0;
+ total_disk_readk = 0.0;
+ total_disk_writek = 0.0;
+ disk_count = 0;
+
+ total_tape_reads = 0.0;
+ total_tape_writes = 0.0;
+ total_tape_readk = 0.0;
+ total_tape_writek = 0.0;
+ tape_count = 0;
+
+#ifdef USE_KSTAT_IO
+ for (i=0; i<ORCA_io_dev_count; ++i) {
+ // Record tape drive st devices differently than regular disk devices.
+ if (ORCA_io_dev_info[i].short_name =~ "^st.*") {
+ tape_count++;
+ total_tape_reads += ORCA_io_dev_info[i].reads;
+ total_tape_writes += ORCA_io_dev_info[i].writes;
+ total_tape_readk += ORCA_io_dev_info[i].kreads;
+ total_tape_writek += ORCA_io_dev_info[i].kwrites;
+ put_output(sprintf("tape_runp_%s", ORCA_io_dev_info[i].long_name),
+ sprintf("%16.5f", ORCA_io_dev_info[i].run_percent));
+ continue;
+ }
+ // Block the listing of floppy drives for now.
+ if (ORCA_io_dev_info[i].short_name =~ "^fd.*") {
+ continue;
+ }
+ disk_count++;
+ put_output(sprintf("disk_runp_%s", ORCA_io_dev_info[i].long_name),
+ sprintf("%16.5f", ORCA_io_dev_info[i].run_percent));
+
+ put_output(sprintf("disk_svct_%s", ORCA_io_dev_info[i].long_name),
+ sprintf("%16.5f", ORCA_io_dev_info[i].service));
+
+ // Comments from Damon Atkins <Damon.Atkins at nabaus.com.au>. 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<GLOBAL_disk_count; ++i) {
+ disk_count++;
+ put_output(sprintf("disk_runp_%s", GLOBAL_disk[i].info.long_name),
+ sprintf("%16.5f", GLOBAL_disk[i].run_percent));
+
+ put_output(sprintf("disk_svct_%s", GLOBAL_disk[i].info.long_name),
+ sprintf("%16.5f", GLOBAL_disk[i].service));
+
+ // Comments from Damon Atkins <Damon.Atkins at nabaus.com.au>. 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<number_regexs; ++i) {
+ count_procs_results[i] = 0;
+ }
+
+ for (p=first_proc(); p.pr_pid != -1; p=next_proc()) {
+ for (i=0; i<number_regexs; ++i) {
+ if (p.pr_fname =~ regexs[i]) {
+ ++count_procs_results[i];
+ }
+ }
+ }
+}
+
+put_httpd()
+{
+ string proc_regexs[2];
+
+ proc_regexs[0] = www_server_proc_name;
+ proc_regexs[1] = www_server_secure_proc_name;
+
+ count_procs(sizeof(proc_regexs)/sizeof(proc_regexs[0]), proc_regexs);
+
+ put_output("#httpds", sprintf("%7d", count_procs_results[0]));
+ put_output("#httpsds", sprintf("%8d", count_procs_results[1]));
+ put_output("httpop/s", sprintf("%8.2f", httpops/www_interval));
+ put_output("http/p5s", sprintf("%8.2f", httpops5));
+ put_output("cndget/s", sprintf("%8.2f", httpop_condgets/www_interval));
+ put_output("search/s", sprintf("%8.3f", httpop_searches/www_interval));
+ put_output(" cgi/s", sprintf("%8.3f", httpop_cgi_bins/www_interval));
+ put_output(" htErr/s", sprintf("%8.3f", httpop_errors/www_interval));
+ put_output(" httpb/s", sprintf("%8.0f", dwnld_totalz/www_interval));
+ put_output(" %to1KB", sprintf("%8.2f", dtmp*dwnld_size[0]));
+ put_output(" %to10KB", sprintf("%8.2f", dtmp*dwnld_size[1]));
+ put_output("%to100KB", sprintf("%8.2f", dtmp*dwnld_size[2]));
+ put_output(" %to1MB", sprintf("%8.2f", dtmp*dwnld_size[3]));
+ put_output("%over1MB", sprintf("%8.2f", dtmp*dwnld_size[4]));
+ put_output(www_gateway, sprintf("%8.2f", gateops/www_interval));
+#if WATCH_PROXY || WATCH_SQUID
+ put_output(" %indir", sprintf("%8.2f", dtmp * prxy_squid_indirect));
+ put_output("%cch_hit", sprintf("%8.2f", dtmp * prxy_squid_cache_hits));
+#ifdef WATCH_PROXY
+ put_output("%cch_wrt", sprintf("%8.2f", dtmp * prxy_cache_writes));
+ put_output("%cch_unc", sprintf("%8.2f", dtmp * prxy_uncacheable));
+#else
+ put_output("%cch_mis", sprintf("%8.2f", dtmp * squid_cache_misses));
+ put_output("%cch_req", sprintf("%8.2f", dtmp * squid_icp_requests));
+ put_output("%cch_qry", sprintf("%8.2f", dtmp * squid_icp_queries));
+#endif
+ put_output(" xfr_t", sprintf("%8.2f", 0.01 * dtmp * www_dwnld_time_sum));
+ put_output(" xfr1_t", sprintf("%8.2f", www_dwnld_time_by_size[0]));
+ put_output(" xfr10_t", sprintf("%8.2f", www_dwnld_time_by_size[1]));
+ put_output("xfr100_t", sprintf("%8.2f", www_dwnld_time_by_size[2]));
+ put_output(" xfr1M_t", sprintf("%8.2f", www_dwnld_time_by_size[3]));
+ put_output("xfro1M_t", sprintf("%8.2f", www_dwnld_time_by_size[4]));
+#elif WATCH_YAHOO
+ put_output(" wprc_t", sprintf("%9.5f", 0.01 * dtmp * www_dwnld_time_sum));
+ put_output(" wprc1_t", sprintf("%9.5f", www_dwnld_time_by_size[0]));
+ put_output(" wprc10_t", sprintf("%9.5f", www_dwnld_time_by_size[1]));
+ put_output("wprc100_t", sprintf("%9.5f", www_dwnld_time_by_size[2]));
+ put_output(" wprc1M_t", sprintf("%9.5f", www_dwnld_time_by_size[3]));
+ put_output("wprco1M_t", sprintf("%9.5f", www_dwnld_time_by_size[4]));
+#endif
+}
+#endif
Modified: trunk/orca/lib/SE/3.3.1/tapeinfo.se
==============================================================================
--- trunk/orca/lib/SE/3.3.1/tapeinfo.se (original)
+++ trunk/orca/lib/SE/3.3.1/tapeinfo.se Fri Sep 10 10:41:38 2004
@@ -1,277 +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 <stdio.se>
-#include <string.se>
-#include <ctype.se>
-#include <stdlib.se>
-#include <unistd.se>
-#include <kstat.se>
-#include <sysdepend.se>
-#include <dirent.se>
-#include <se_trees.se>
-
-#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/<tape device number>
- 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<count; i++) {
- str2int_put(GLOBAL_tapeinfo_short_tree, GLOBAL_tape_info[i].short_name, i);
- str2int_put(GLOBAL_tapeinfo_long_tree, GLOBAL_tape_info[i].long_name, i);
- }
-
- tapeinfo_inst_initialized = 1;
- return 1;
-}
-
-// Function names must be changed to prevent conflict with diskinfo.se
-
-// use this function during init to map short names (st0) to indexes
-int
-find_tape_inst(string name) // return index into GLOBAL_tape_info
-{
- ulong_t lp;
-
- if (setup_tapeinfo_inst() == 0) {
- return -1;
- }
- lp = str2int_get(GLOBAL_tapeinfo_short_tree, name);
- if (lp == 0) {
- return -1;
- }
- return ((int) *((ulong_t *) lp));
-}
-#define find_tape_short_name find_tape_inst
-
-// use this function to do the reverse mapping from rmt/0
-int
-find_tape_long_name(string name) // return index into GLOBAL_tape_info
-{
- ulong_t lp;
-
- if (setup_tapeinfo_inst() == 0) {
- return -1;
- }
- lp = str2int_get(GLOBAL_tapeinfo_long_tree, name);
- if (lp == 0) {
- return -1;
- }
- return ((int) *((ulong_t *) lp));
-}
-
-// use this function to get the data for an index
-tape_info_t
-tape_info(int i, string name)
-{
- tape_info_t no_info;
-
- if (setup_tapeinfo_inst() == 0) {
- return no_info;
- }
- if (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 <stdio.se>
+#include <string.se>
+#include <ctype.se>
+#include <stdlib.se>
+#include <unistd.se>
+#include <kstat.se>
+#include <sysdepend.se>
+#include <dirent.se>
+#include <se_trees.se>
+
+#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/<tape device number>
+ 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<count; i++) {
+ str2int_put(GLOBAL_tapeinfo_short_tree, GLOBAL_tape_info[i].short_name, i);
+ str2int_put(GLOBAL_tapeinfo_long_tree, GLOBAL_tape_info[i].long_name, i);
+ }
+
+ tapeinfo_inst_initialized = 1;
+ return 1;
+}
+
+// Function names must be changed to prevent conflict with diskinfo.se
+
+// use this function during init to map short names (st0) to indexes
+int
+find_tape_inst(string name) // return index into GLOBAL_tape_info
+{
+ ulong_t lp;
+
+ if (setup_tapeinfo_inst() == 0) {
+ return -1;
+ }
+ lp = str2int_get(GLOBAL_tapeinfo_short_tree, name);
+ if (lp == 0) {
+ return -1;
+ }
+ return ((int) *((ulong_t *) lp));
+}
+#define find_tape_short_name find_tape_inst
+
+// use this function to do the reverse mapping from rmt/0
+int
+find_tape_long_name(string name) // return index into GLOBAL_tape_info
+{
+ ulong_t lp;
+
+ if (setup_tapeinfo_inst() == 0) {
+ return -1;
+ }
+ lp = str2int_get(GLOBAL_tapeinfo_long_tree, name);
+ if (lp == 0) {
+ return -1;
+ }
+ return ((int) *((ulong_t *) lp));
+}
+
+// use this function to get the data for an index
+tape_info_t
+tape_info(int i, string name)
+{
+ tape_info_t no_info;
+
+ if (setup_tapeinfo_inst() == 0) {
+ return no_info;
+ }
+ if (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
More information about the Orca-checkins
mailing list