/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* perf720 src/perf/perfagent/usr/samples/perfagent/server/SpmiHotlog.c 1.2 */ /* */ /* */ /* */ /* OBJECT CODE ONLY SOURCE MATERIALS */ /* */ /* COPYRIGHT International Business Machines Corp. 1996,1998 */ /* All Rights Reserved */ /* */ /* The source code for this program is not published or otherwise */ /* divested of its trade secrets, irrespective of what has been */ /* deposited with the U.S. Copyright Office. */ /* */ /* IBM_PROLOG_END_TAG */ /* * COMPONENT_NAME: PERFAGENT * * FUNCTIONS: add_stats * get_stats * main * must_exit * parse_name * read_file * read_input * set_up_start * set_up_end * format_time * * ORIGINS: 30 * * * (C) COPYRIGHT International Business Machines Corp. 1996 * All Rights Reserved * Licensed Materials - Property of IBM * US Government Users Restricted Rights - Use, duplication or * disclosure restricted by GSA ADP Schedule Contract with IBM Corp. * * NOTICE TO USERS OF THE SOURCE CODE EXAMPLES * * THE SOURCE CODE EXAMPLES PROVIDED BY IBM ARE ONLY INTENDED TO ASSIST IN THE * DEVELOPMENT OF A WORKING SOFTWARE PROGRAM. THE SOURCE CODE EXAMPLES DO NOT * FUNCTION AS WRITTEN: ADDITIONAL CODE IS REQUIRED. IN ADDITION, THE SOURCE * CODE EXAMPLES MAY NOT COMPILE AND/OR BIND SUCCESSFULLY AS WRITTEN. * * INTERNATIONAL BUSINESS MACHINES CORPORATION PROVIDES THE SOURCE CODE * EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, "AS IS" WITHOUT * WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT * LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE * OF THE SOURCE CODE EXAMPLES, BOTH INDIVIDUALLY AND AS ONE OR MORE GROUPS, * IS WITH YOU. SHOULD ANY PART OF THE SOURCE CODE EXAMPLES PROVE * DEFECTIVE, YOU (AND NOT IBM OR AN AUTHORIZED RISC System/6000* WORKSTATION * DEALER) ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING, REPAIR OR * CORRECTION. * * IBM does not warrant that the contents of the source code examples, whether * individually or as one or more groups, will meet your requirements or that * the source code examples are error-free. * * IBM may make improvements and/or changes in the source code examples at * any time. * * Changes may be made periodically to the information in the source code * examples; these changes may be reported, for the sample device drivers * included herein, in new editions of the examples. * * References in the source code examples to IBM products, programs, or * services do not imply that IBM intends to make these available in all * countries in which IBM operates. Any reference to an IBM licensed * program in the source code examples is not intended to state or imply * that only IBM's licensed program may be used. Any functionally equivalent * program may be used. * * RISC System/6000 is a trademark of International Business Machines * Corporation. * */ static char *Sccs_id = "@(#)17 1.10 src/perf/perfagent/usr/samples/perfagent/server/SpmiHotlog.c, perfagent, perf420 3/7/95 17:11:24"; /* * EXECUTION NOTES: * SpmiHotlog is a program which will display a set of metrics that is * input to the program either through a file or manually. The output can * also be saved to an output file instead of displaying to the screen. * The output can also be saved in a Lotus type import format. * * The input file should contain the path names of peer sets of the metrics * to be monitored. The path names and descriptions of metrics can be * acquired from the SpmiPeek program. Note that the path names of peer sets * lack the lowest level context name. For example, the peer metrics "xfer" * for a machine with three disks might be: * * Disk/hdisk0/xfer * Disk/hdisk1/xfer * Disk/hdisk2/xfer * * The corresponding peer set path name is: * * Disk/xfer * * Following the peer metrics path name, you can specify up-to 4 parameters * that will control how this program monitors hot metrics. The values * and their defaults are: * * Value No Description Default * -------- ------------------------------------------- ------- * 1 The maximum number of responses to return 2 * * 2 The threshold that determines if response Metric max value * is generated; negative value means thet a divided by 2; * metric qualifies if its value is less than * the numeric value of threshold. * * 3 Determines how to generate data feeds: 1 * 0 = never * 1 = according to threshold * 2 = always * * 4 Determines if exceptions/traps generated. 0 * 0 = neither * 1 = exceptions only * 2 = traps only * 3 = both exceptions and traps * * The Usage statement is as follows: * SpmiHotlog {-f infile|-m|-mf infile} [-i seconds] [-o outfile] * [-b hhmm] [-e hh.mm] * The -f indicates the input file which contains a list of metrics * you wish to monitor. * The -m allows you to input metrics manually. You will be prompted * for the metrics you wish to monitor. * The -i allows you to input a delay in seconds between metrics readings. * The default is two seconds. * The -o indicates the output file. * The -b will start SpmiHotlog at the specified time. The start time should * be within 24 hours. If the start time is incorrect then SpmiHotlog * will begin execution immediately. * The -e will stop SpmiHotlog after the specified interval. Anything after * the decimal point is considered minutes and everything before the * decimal point is considered hours. You could conceivably end after * 120 minutes which could be input either as 0.120, or 2.0 * There is a maximum of 24 hours. * If no begin and end times are specified, then SpmiHotlog will run for * the next 12 hours. * */ #include #include #include #include #include #include #include #include #define PLAIN 0 #define TAB 1 #define SPREAD 2 extern char SpmiErrmsg[]; extern int SpmiErrno; struct SpmiHotSet *hotset; char context[600], statistic[300], header_line[50], *blanks = " ", *ofile, *ifile; FILE *in_file, *out_file; int stat_counter = 0, manflag = 0, fileflag = 0, outflag = 0, delay = 2, run_time = 43200, /* default of 12 hours */ start_log = 0, sleep_secs; /*============================== must_exit() ==============================*/ /* This function is used to clean up memory after the program receives a */ /* signal to terminate execution. */ /*=========================================================================*/ void must_exit() { if (hotset) if (SpmiFreeHotSet(hotset)) { printf("ERROR: SpmiFreeHotSet Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); } SpmiExit(); if (SpmiErrno) { printf("ERROR: SpmiExit Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); } if (outflag) fclose(out_file); exit(0); } /*=========================== format_time() ===============================*/ /* This function takes an input of the time of the reading and then formats*/ /* the time for output to the out file. */ /*=========================================================================*/ #ifdef _NO_PROTO void format_time(t1, seconds) char *t1; time_t *seconds; #else void format_time(char *t1, time_t *seconds) #endif { struct tm *t2; char month[3], day[3], year[5]; char hour[3], min[3], sec[3]; t2 = localtime(seconds); if ((t2->tm_mon + 1) < 10) sprintf(month, "0%d", (t2->tm_mon + 1)); else sprintf(month, "%d", (t2->tm_mon + 1)); if (t2->tm_mday < 10) sprintf(day, "0%d", t2->tm_mday); else sprintf(day, "%d", t2->tm_mday); sprintf(year, "%d", 1900 + t2->tm_year); if (t2->tm_hour < 10) sprintf(hour, "0%d", t2->tm_hour); else sprintf(hour, "%d", t2->tm_hour); if (t2->tm_min < 10) sprintf(min, "0%d", t2->tm_min); else sprintf(min, "%d", t2->tm_min); if (t2->tm_sec < 10) sprintf(sec, "0%d", t2->tm_sec); else sprintf(sec, "%d", t2->tm_sec); sprintf(t1, "%s/%s/%s %s:%s:%s", year, month, day, hour, min, sec); return; } /*============================= get_stats() ===============================*/ /* This function traverses the hotset to get the stat values and write */ /* the values to the selected output file and format. */ /*=========================================================================*/ void get_stats() { struct SpmiHotVals *hotval; struct SpmiStat *stat; int index; float value; char *name; int counter = 20; char t1[25]; struct timeval atid; int errors = 0; /* execute this loop until a terminate signal is received */ while (1) { /* determine if the hotset is valid */ if (SpmiGetHotSet(hotset, TRUE) != 0) { if (++errors > 10) { printf("ERROR: SpmiGetHotSet Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } } /* output a timestamp */ gettimeofday(&atid, NULL); format_time((char *)t1, (time_t *)&atid.tv_sec); /* traverse the hotset */ hotval = SpmiNextHotItem(hotset, NULL, &index, &value, &name); while (hotval != NULL) { /* output the statistic values */ stat = SpmiGetStat(hotval->stat); fprintf(out_file, "%s, %s/%s/%s=%1.2f, threshold=%d\n", t1, hotval->path, name, stat->name, value, hotval->threshold); hotval = SpmiNextHotItem(hotset, hotval, &index, &value, &name); } ++counter; /* sleep until next statistic read */ sleep(delay); --run_time; if (!run_time) must_exit(); } return; } /*============================ add_stats() ===============================*/ /* Add the metrics to the stat set. */ /*========================================================================*/ #ifdef _NO_PROTO void add_stats(max, threshold, feed, excp) int max; int threshold; int feed; int excp; #else void add_stats(int max, int threshold, int feed, int excp) #endif { SpmiCxHdl cxhdl; struct SpmiStat *stat; struct SpmiCxLink *cxlink; struct SpmiCx *cx; struct SpmiStatLink *statlink; if ((cxhdl = SpmiPathGetCx(context, NULL)) == NULL) { printf("ERROR: SpmiPathGetCx Failed for %s.\n", context); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } if (threshold == -1) threshold = stat->max / 2; if (max == -1) max = 2; if (SpmiAddSetHot(hotset, statistic, cxhdl, max, threshold, 10, feed, excp, 9, 9) == NULL) { printf("ERROR: SpmiAddSetHot for %s Failed.\n", statistic); if (strlen(SpmiErrmsg)) printf("%s\n", SpmiErrmsg); must_exit(); } ++stat_counter; return; } /*============================= parse_name() =============================*/ /* This function is used to traverse the name of the input statistic to */ /* separate the context from the statistic. */ /*========================================================================*/ #ifdef _NO_PROTO void parse_name(stat_inp, max, threshold, feed, excp) char *stat_inp; int *max; int *threshold; int *feed; int *excp; #else void parse_name(char *stat_inp, int *max, int *threshold, int *feed, int *excp) #endif { char stat_work[256]; char *stat_out; char *s; if (s = strtok(stat_inp, " ,\n")) { strcpy(stat_work, s); if (s = strtok(NULL, " ,\n")) *max = atoi(s); else *max = -1; if (s = strtok(NULL, " ,\n")) *threshold = atoi(s); else *threshold = -1; if (s = strtok(NULL, " ,\n")) *feed = atoi(s); else *feed = SiHotThreshold; if (s = strtok(NULL, " ,\n")) *excp = atoi(s); else *excp = SiHotNoException; } stat_out = strtok(stat_work, "/"); strcpy(context, stat_out); statistic[0] = '\0'; while (stat_out) { stat_out = strtok(NULL, "/"); if (stat_out) { if (statistic[0]) { strcat(context, "/"); strcat(context, statistic); } strcpy(statistic, stat_out); } } return; } /*============================= read_file() ==============================*/ /* Read the statistic names from the input file. */ /*========================================================================*/ void read_file() { char stat_inp[128]; int max; int threshold; int feed; int excp; while (fgets(stat_inp, sizeof(stat_inp), in_file) && stat_counter <= 28) { parse_name((char *)&stat_inp, &max, &threshold, &feed, &excp); add_stats(max, threshold, feed, excp); } fclose(in_file); return; } /*============================ read_input() ==============================*/ /* Read statistic names from user input. */ /*========================================================================*/ void read_input() { char stat_inp[128]; int max; int threshold; int feed; int excp; if (stat_counter == 28) { printf("\nMaximum of 28 Statistics May Be Entered.\n"); return; } printf("\nWhen the last peer set has been entered, key 99."); printf("\nEnter peer path name [max [threshold [feed [exception]]]]: "); while (gets(stat_inp) && stat_counter <= 28) { if (!strcmp(stat_inp, "99")) break; parse_name((char *)&stat_inp, &max, &threshold, &feed, &excp); add_stats(max, threshold, feed, excp); if (stat_counter <= 28) printf("\nEnter peer path name [max [threshold [feed [exception]]]]: "); else printf("\nMaximum of 28 Statistics May Be Entered.\n"); } /* end while loop */ return; } /*=========================== set_up_start() =============================*/ /* This function determines the number of seconds until the user's */ /* desired time. If an invalid time is input, SpmiHotlog will begin */ /* collecting data immediately. */ /*========================================================================*/ void set_up_start() { char *start_time; char hr[3], minute[3]; int hour, min; struct timeval timer; struct timezone tzone; struct tm *current_time; extern char *optarg; start_time = optarg; hr[0] = *start_time; start_time++; if (*start_time == NULL) return; hr[1] = *start_time; start_time++; if (*start_time == NULL) return; minute[0] = *start_time; start_time++; if (*start_time == NULL) return; minute[1] = *start_time; hour = atoi(hr); min = atoi(minute); if ((hour < 0) || (hour > 23) || (min < 0) || (min > 59)) return; gettimeofday(&timer, &tzone); current_time = localtime((time_t *)&timer.tv_sec); start_log++; /* special condition */ if ((current_time->tm_hour == hour) && (current_time->tm_min > min)) { sleep_secs = (24 * 3600); sleep_secs -= ((current_time->tm_min - min) * 60); return; } if (current_time->tm_hour > hour) /* tomorrow */ sleep_secs = (24 * 3600) - ((current_time->tm_hour - hour) * 3600); else sleep_secs = (hour - current_time->tm_hour) * 3600; if (current_time->tm_min > min) sleep_secs -= ((current_time->tm_min - min) * 60); else sleep_secs += ((min - current_time->tm_min) * 60); return; } /* end set_up_start */ /*=========================== set_up_end() ===============================*/ /* This function determines the number of seconds SpmiHotlog will execute.*/ /*========================================================================*/ int set_up_end() { char *end_time; char *fracp, *intp; int frac_part, int_part; end_time = optarg; if (end_time[0] == '.') { intp = "0"; fracp = strtok(end_time, "."); } else { intp = strtok(end_time, "."); fracp = strtok(NULL, "."); } int_part = atoi(intp); frac_part = atoi(fracp); if ((int_part < 0.0) || (frac_part < 0.0)) return(1); else run_time = (int_part * 3600) + (frac_part * 60); if (run_time > 86400) /* 24 hours max */ { printf("ERROR: SpmiHotlog can only execute for a\n"); printf(" maximum of 24 hours.\n"); must_exit(); } return(0); } /* set_up_end */ /*================================ main() ============================*/ #ifdef _NO_PROTO main(argc, argv) int argc; char **argv; #else main(int argc, char **argv) #endif { extern char *optarg; int errflag = 0; int explainflag = 0; int spmierr=0; int c; struct utsname uname_struct; /* Initialize SPMI interface */ if ((spmierr = SpmiInit(15)) != 0) { printf("ERROR: Unable to initialize SPMI interface.\n"); printf("%s", SpmiErrmsg); exit(-98); } /* setup interrupt signals */ #ifdef _NO_PROTO signal(SIGINT, (void(*)())must_exit); signal(SIGTERM, (void(*)())must_exit); signal(SIGSEGV, (void(*)())must_exit); signal(SIGQUIT, (void(*)())must_exit); #else signal(SIGINT, (void(*)(int))must_exit); signal(SIGTERM, (void(*)(int))must_exit); signal(SIGSEGV, (void(*)(int))must_exit); signal(SIGQUIT, (void(*)(int))must_exit); #endif /* _NO_PROTO */ while ((c = getopt(argc, argv, "b:e:f:i:mo:x")) != EOF) { switch (c) { case 'b': /* start time */ set_up_start(); break; case 'e': /* end time */ errflag += set_up_end(); break; case 'f': /* input file */ fileflag++; ifile = optarg; break; case 'i': /* delay */ delay = atoi(optarg); if (delay <= 0) { printf("ERROR: Interval cannot be zero or \n"); printf(" less than zero.\n"); must_exit(); } break; case 'm': /* manual input */ manflag++; break; case 'o': /* output file */ outflag++; ofile = optarg; break; case 'x': explainflag++; break; } } if(!fileflag && !manflag) errflag++; if (errflag && !explainflag) { printf("Usage: SpmiHotlog {-f infile|-m|-mf infile} [-i seconds] [-o outfile]\n"); printf(" [-b hhmm] [-e hh.mm]\n"); printf(" Flags: -f Input file which contains metrics list.\n"); printf(" -m Manual input of metrics.\n"); printf(" -i Delay between metrics readings.\n"); printf(" Default = two seconds\n"); printf(" -o Output file.\n"); printf(" -b Start SpmiHotlog at a specified time.\n"); printf(" hh = Hour in 24 hour time\n"); printf(" mm = Minutes\n"); printf(" Default = Current time\n"); printf(" -e Stop SpmiHotlog after the specified interval.\n"); printf(" hh = Number of hours to execute\n"); printf(" mm = Number of minutes to execute\n"); printf(" Default = 12 hours, Max = 24 hours\n"); printf(" -x Print explanation of input line format.\n"); must_exit(); } if (explainflag) { printf("The input file should contain the path names of peer sets of the\n"); printf("metrics to be monitored. Note that the path names of peer sets\n"); printf("lack the lowest level context name. For example, the peer metrics\n"); printf("\"xfer\" for a machine with three disks might be:\n"); printf(" Disk/hdisk0/xfer\n"); printf(" Disk/hdisk1/xfer\n"); printf(" Disk/hdisk2/xfer\n"); printf("The corresponding peer set path name is:\n"); printf(" Disk/xfer\n\n"); printf("Following the peer metrics path name, you can specify up-to 4\n"); printf("parameters that will control how this program monitors hot metrics:\n\n"); printf("Value No Description Default\n"); printf("-------- ------------------------------------------- -------\n"); printf(" 1 The maximum number of responses to return 2\n\n"); printf(" 2 The threshold that determines if response Metric max value\n"); printf(" is generated; negative value means thet a divided by 2;\n"); printf(" metric qualifies if its value is less than\n"); printf(" the numeric value of threshold.\n\n"); printf(" 3 Determines how to generate data feeds: 1\n"); printf(" 0 = never, 1 = according to threshold\n"); printf(" 2 = always\n\n"); printf(" 4 Determines if exceptions/traps generated. 0\n"); printf(" 0 = neither, 1 = exceptions only\n"); printf(" 2 = traps only, 3 = both exceptions and traps\n"); must_exit(); } out_file = NULL; if (outflag) { out_file = fopen(ofile, "w"); if (out_file == NULL) { printf("ERROR: Unable to open output file.\n"); printf(" Exiting program.\n"); must_exit(); } } else out_file = stdout; if (fileflag) { in_file = fopen(ifile, "r"); if (in_file == NULL) { printf("ERROR: Unable to open input file.\n"); printf(" Exiting program.\n"); must_exit(); } } /* set up time counter */ run_time = run_time / delay; hotset = SpmiCreateHotSet(); if (hotset == NULL) { printf("ERROR: SpmiCreateHotSet Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } uname(&uname_struct); sprintf(header_line, "Metrics Provided By Hostname: %s", uname_struct.nodename); if (manflag) read_input(); if (fileflag) read_file(); /* Display stats info */ if (stat_counter != 0) { if (start_log) sleep(sleep_secs); get_stats(); /* access metrics */ } else { printf("ERROR: No metrics were input.\n"); printf(" Exiting program.\n"); } /* Exit Spmi Interface */ must_exit(); }