/* IBM_PROLOG_BEGIN_TAG */ /* This is an automatically generated prolog. */ /* */ /* perf720 src/perf/perfagent/usr/samples/perfagent/server/SpmiLogger.c 1.12 */ /* */ /* */ /* */ /* OBJECT CODE ONLY SOURCE MATERIALS */ /* */ /* COPYRIGHT International Business Machines Corp. 1992,1994 */ /* 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 * create_headers * 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. 1992,1993,1994 * 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/SpmiLogger.c, perfagent, perf420 3/7/95 17:11:24"; /* * EXECUTION NOTES: * SpmiLogger 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 just contain the path names of the metrics * of interest. The path names and descriptions of metrics can be * acquired from the SpmiPeek program. The following is an example of what * the metrics input file should look like if the user were interested in * the CPU's kernel info, the size of real memory, and the number of defined * statistic sets: * * CPU/cpu0/kern * Mem/Real/size * Spmi/statsets * * The Usage statement is as follows: * SpmiLogger {-f infile|-m|-mf infile} [-i seconds] [-o outfile [-s|-t]] * [-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 -s will convert the output data into a Spreadsheet format. * The -t will convert the output data into a tab separated format. * The -b will start SpmiLogger at the specified time. The start time should * be within 24 hours. If the start time is incorrect then SpmiLogger * will begin execution immediately. * The -e will stop SpmiLogger 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 SpmiLogger 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 SpmiStatSet *statset; 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, formatflag = PLAIN, 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 (statset) if (SpmiFreeStatSet(statset)) { printf("ERROR: SpmiFreeStatSet 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); } /*============================ create_headers() ===========================*/ /* This function traverses the statset to make the headers which display */ /* the names of the metrics in the set. This is the standard output */ /* format. */ /*=========================================================================*/ void create_headers() { struct SpmiStatVals *statval1; struct SpmiStat *spmistat; char tmp_array[100]; int pathlen, statlen, length; /* determine if the statset is valid */ if (SpmiGetStatSet(statset, TRUE) != 0) { printf("ERROR: SpmiGetStatSet Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } switch (formatflag) { case SPREAD: strcpy(context, "\"Timestamp\" "); break; case TAB: strcpy(context, "Timestamp\t"); break; case PLAIN: default: strcpy(context, "Timestamp "); strcpy(statistic, " "); break; } /* traverse the stat set to create a header which displays */ /* the names of the metrics. */ statval1 = SpmiFirstVals(statset); while (statval1 != NULL) { sprintf(tmp_array, "%s", SpmiStatGetPath(statval1->context, statval1->stat, 0)); if (strlen(SpmiStatGetPath(statval1->context,statval1->stat, 0)) == 0) { printf("ERROR: SpmiStatGetPath Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } switch (formatflag) { case TAB: strcat(context, tmp_array); strcat(context, "\t"); break; case SPREAD: strcat(context, "\""); strcat(context, tmp_array); strcat(context, "\" "); break; case PLAIN: default: spmistat = SpmiGetStat(statval1->stat); if (spmistat == NULL) { printf("ERROR: SpmiGetStat Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } pathlen = strlen(tmp_array); statlen = strlen(spmistat->name); length = pathlen - statlen; /* format the arrays so only the first 10 chars of the name is */ /* shown, this is done to conserve screen space */ if (length > 10) { strncat(context, blanks, 1); strncat(context, tmp_array, 10); } else { strncat(context, blanks, (11 - length)); strncat(context, tmp_array, length); } if (statlen > 10) { strncat(statistic, blanks, 1); strncat(statistic, spmistat->name, 10); } else { strncat(statistic, blanks, 11 - statlen); strcat(statistic, spmistat->name); } break; } statval1 = SpmiNextVals(statset, statval1); } switch (formatflag) { case TAB: case SPREAD: fprintf(out_file, "%s\n", header_line); fprintf(out_file, "%s\n", context); break; } return; } /*=========================== 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 statset to get the stat values and write */ /* the values to the selected output file and format. */ /*=========================================================================*/ void get_stats() { struct SpmiStatVals *statval1; float spmivalue; 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 statset is valid */ if (SpmiGetStatSet(statset, TRUE) != 0) { if (++errors > 10) { printf("ERROR: SpmiGetStatSet Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } } /* output the headers every 20 lines */ if ((counter == 20) && !formatflag) { fprintf(out_file, "\n\n"); fprintf(out_file, "%s\n", context); fprintf(out_file, "%s\n", statistic); counter = 1; } /* output a timestamp */ gettimeofday(&atid, NULL); format_time((char *)t1, (time_t *)&atid.tv_sec); switch(formatflag) { case TAB: fprintf(out_file, "%s\t", t1); break; case SPREAD: fprintf(out_file, "\"%s\"", t1); break; case PLAIN: default: fprintf(out_file, "%s", t1); break; } /* traverse the stat set */ statval1 = SpmiFirstVals(statset); while (statval1 != NULL) { spmivalue = SpmiGetValue(statset, statval1); if (spmivalue < 0.0) { /* maybe we just lost a connection */ switch (formatflag) { case TAB: fprintf(out_file, " -\t"); break; case SPREAD: fprintf(out_file, "\" -\""); break; case PLAIN: default: fprintf(out_file, " -"); break; } } else { /* output the statistic values */ switch(formatflag) { case TAB: fprintf(out_file, "%10.2f\t", spmivalue); break; case SPREAD: case PLAIN: default: fprintf(out_file, "%10.2f ", spmivalue); break; } } statval1 = SpmiNextVals(statset, statval1); } fprintf(out_file, "\n"); ++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. */ /*========================================================================*/ void add_stats() { SpmiCxHdl cxhdl; if ((cxhdl = SpmiPathGetCx(context, NULL)) == NULL) { printf("ERROR: SpmiPathGetCx Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } if (SpmiPathAddSetStat(statset, statistic, cxhdl) == NULL) { printf("ERROR: SpmiPathAddSetStat 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) char *stat_inp; #else void parse_name(char *stat_inp) #endif { char *stat_out; stat_out = strtok(stat_inp, "/"); 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]; while ((fscanf(in_file, "%s", &stat_inp)!=EOF) && (stat_counter <= 28)) { parse_name((char *)&stat_inp); add_stats(); } fclose(in_file); return; } /*============================ read_input() ==============================*/ /* Read statistic names from user input. */ /*========================================================================*/ void read_input() { char stat_inp[128]; if (stat_counter == 28) { printf("\nMaximum of 28 Statistics May Be Entered.\n"); return; } printf("\nEnter Full Path Name of Stat, 99 to end: "); scanf("%s", &stat_inp); while(strcmp(stat_inp, "99") && (stat_counter <= 28)) { parse_name((char *)&stat_inp); add_stats(); if (stat_counter <= 28) { printf("\nEnter Full Path Name of Stat: "); scanf("%s", &stat_inp); } 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, SpmiLogger 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 SpmiLogger 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: SpmiLogger 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 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:st")) != 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 's': /* Spreadsheet output */ if (formatflag) errflag++; formatflag = SPREAD; break; case 't': /* tab separated output */ if (formatflag) errflag++; formatflag = TAB; break; case '?': errflag++; break; } } if( (formatflag && !outflag) || (!fileflag && !manflag) ) errflag++; if (errflag) { printf("Usage: SpmiLogger {-f infile|-m|-mf infile} [-i seconds] [-o outfile [-s|-t]]\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(" -s Spreadsheet format.\n"); printf(" -t Tab separated format.\n"); printf(" -b Start SpmiLogger 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 SpmiLogger 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"); 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; statset = SpmiCreateStatSet(); if (statset == NULL) { printf("ERROR: SpmiCreateStatSet Failed.\n"); if (strlen(SpmiErrmsg)) printf("%s", SpmiErrmsg); must_exit(); } uname(&uname_struct); if (formatflag == SPREAD) sprintf(header_line, "\"Metrics Provided By Hostname: %s\"", uname_struct.nodename); else 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) { create_headers(); 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(); }