/* *************************************************************************** * Display the field list (used eg. in database format). * * IN: * @act_d Activity to display, or ~0 for all. *************************************************************************** */ void list_fields(unsigned int act_id) { int i, j; unsigned int msk; char *hl; char hline[HEADER_LINE_LEN] = ""; printf("# hostname;interval;timestamp"); for (i = 0; i < NR_ACT; i++) { if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id)) continue; if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) { if (!HAS_MULTIPLE_OUTPUTS(act[i]->options)) { printf(";%s", act[i]->hdr_line); if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) { printf("[...]"); } } else { msk = 1; strncpy(hline, act[i]->hdr_line, HEADER_LINE_LEN - 1); hline[HEADER_LINE_LEN - 1] = '\0'; for (hl = strtok(hline, "|"); hl; hl = strtok(NULL, "|"), msk <<= 1) { if ((hl != NULL) && ((act[i]->opt_flags & 0xff) & msk)) { if (strchr(hl, '&')) { j = strcspn(hl, "&"); if ((act[i]->opt_flags & 0xff00) & (msk << 8)) { /* Display whole header line */ *(hl + j) = ';'; printf(";%s", hl); } else { /* Display only the first part of the header line */ *(hl + j) = '\0'; printf(";%s", hl); } *(hl + j) = '&'; } else { printf(";%s", hl); } if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) { printf("[...]"); } } } } } } printf("\n"); }
/* *************************************************************************** * Display the "timestamp" part of the report (db and ppc format). * * IN: * @fmt Output format (F_DB_OUTPUT or F_PPC_OUTPUT). * @file_hdr System activity file standard header. * @cur_date Date string of current record. * @cur_time Time string of current record. * @utc True if @cur_time is expressed in UTC. * @itv Interval of time with preceding record. * * RETURNS: * Pointer on the "timestamp" string. *************************************************************************** */ char *print_dbppc_timestamp(int fmt, struct file_header *file_hdr, char *cur_date, char *cur_time, int utc, unsigned long long itv) { int isdb = (fmt == F_DB_OUTPUT); static char pre[80]; char temp[80]; /* This substring appears on every output line, preformat it here */ snprintf(pre, 80, "%s%s%lld%s", file_hdr->sa_nodename, seps[isdb], itv, seps[isdb]); if (strlen(cur_date)) { snprintf(temp, 80, "%s%s ", pre, cur_date); } else { strcpy(temp, pre); } snprintf(pre, 80, "%s%s%s", temp, cur_time, strlen(cur_date) && utc ? " UTC" : ""); pre[79] = '\0'; if (DISPLAY_HORIZONTALLY(flags)) { printf("%s", pre); } return pre; }
/* *************************************************************************** * write_mech_stats() - * Replace the old write_stats_for_ppc() and write_stats_for_db(), * making it easier for them to remain in sync and print the same data. * * IN: * @curr Index in array for current sample statistics. * @dt Interval of time in seconds. * @itv Interval of time in jiffies. * @g_itv Interval of time in jiffies multiplied by the number of * processors. * @cur_date Date string for current record. * @cur_time Time string for current record. * @act_id Activity to display, or ~0 for all. *************************************************************************** */ void write_mech_stats(int curr, unsigned long dt, unsigned long long itv, unsigned long long g_itv, char *cur_date, char *cur_time, unsigned int act_id) { int i; char pre[80], temp[80]; /* Text at beginning of each line */ int isdb = (format == F_DB_OUTPUT); /* This substring appears on every output line, preformat it here */ snprintf(pre, 80, "%s%s%ld%s", file_hdr.sa_nodename, seps[isdb], dt, seps[isdb]); if (strlen(cur_date)) { snprintf(temp, 80, "%s%s ", pre, cur_date); } else { strcpy(temp, pre); } snprintf(pre, 80, "%s%s%s", temp, cur_time, strlen(cur_date) && !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags) ? " UTC" : ""); pre[79] = '\0'; if (DISPLAY_HORIZONTALLY(flags)) { printf("%s", pre); } for (i = 0; i < NR_ACT; i++) { if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id)) continue; if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) { (*act[i]->f_render)(act[i], isdb, pre, curr, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } if (DISPLAY_HORIZONTALLY(flags)) { printf("\n"); } }
/* *************************************************************************** * Display the field list (used eg. in database format). * * IN: * @act_d Activity to display, or ~0 for all. *************************************************************************** */ void list_fields(unsigned int act_id) { int i; unsigned int msk; char *hl; char hline[HEADER_LINE_LEN]; printf("# hostname;interval;timestamp"); for (i = 0; i < NR_ACT; i++) { if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id)) continue; if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) { if (!HAS_MULTIPLE_OUTPUTS(act[i]->options)) { printf(";%s", act[i]->hdr_line); if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) { printf("[...]"); } } else { msk = 1; strcpy(hline, act[i]->hdr_line); for (hl = strtok(hline, "|"); hl; hl = strtok(NULL, "|"), msk <<= 1) { if ((hl != NULL) && (act[i]->opt_flags & msk)) { printf(";%s", hl); if ((act[i]->nr > 1) && DISPLAY_HORIZONTALLY(flags)) { printf("[...]"); } } } } } } printf("\n"); }
/* *************************************************************************** * Display the "timestamp" part of the report (db format). * * IN: * @parm Pointer on specific parameters (unused here). * @action Action expected from current function. * @cur_date Date string of current record. * @cur_time Time string of current record. * @itv Interval of time with preceding record. * @file_hdr System activity file standard header. * @flags Flags for common options. * * RETURNS: * Pointer on the "timestamp" string. *************************************************************************** */ __tm_funct_t print_db_timestamp(void *parm, int action, char *cur_date, char *cur_time, unsigned long long itv, struct file_header *file_hdr, unsigned int flags) { int utc = !PRINT_LOCAL_TIME(flags) && !PRINT_TRUE_TIME(flags); if (action & F_BEGIN) { return print_dbppc_timestamp(F_DB_OUTPUT, file_hdr, cur_date, cur_time, utc, itv); } if (action & F_END) { if (DISPLAY_HORIZONTALLY(flags)) { printf("\n"); } } return NULL; }
/* *************************************************************************** * Display activities for non textual formats. * * IN: * @ifd File descriptor of input file. * @file_actlst List of (known or unknown) activities in file. * @cpu_nr Number of processors for current activity data file. * @rectime Structure where timestamp (expressed in local time or in UTC * depending on whether option -t has been used or not) can be * saved for current record. * @loctime Structure where timestamp (expressed in local time) can be * saved for current record. *************************************************************************** */ void main_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime) { int i, p; int curr = 1, rtype; int eosaf = TRUE, reset = FALSE; long cnt = 1; off_t fpos; /* Read system statistics from file */ do { /* * If this record is a special (RESTART or COMMENT) one, print it and * (try to) get another one. */ do { if (sa_fread(ifd, &record_hdr[0], RECORD_HEADER_SIZE, SOFT_SIZE)) /* End of sa data file */ return; rtype = record_hdr[0].record_type; if ((rtype == R_RESTART) || (rtype == R_COMMENT)) { sadf_print_special(0, tm_start.use, tm_end.use, rtype, ifd, rectime, loctime); } else { /* * OK: Previous record was not a special one. * So read now the extra fields. */ read_file_stat_bunch(act, 0, ifd, file_hdr.sa_nr_act, file_actlst); sadf_get_record_timestamp_struct(0, rectime, loctime); } } while ((rtype == R_RESTART) || (rtype == R_COMMENT) || (tm_start.use && (datecmp(loctime, &tm_start) < 0)) || (tm_end.use && (datecmp(loctime, &tm_end) >= 0))); /* Save the first stats collected. Will be used to compute the average */ copy_structures(act, id_seq, record_hdr, 2, 0); /* Set flag to reset last_uptime variable. Should be done after a LINUX RESTART record */ reset = TRUE; /* Save current file position */ if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) { perror("lseek"); exit(2); } /* Read and write stats located between two possible Linux restarts */ if (DISPLAY_HORIZONTALLY(flags)) { /* * If stats are displayed horizontally, then all activities * are printed on the same line. */ rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, ALL_ACTIVITIES, &reset, file_actlst, cpu_nr, rectime, loctime); } else { /* For each requested activity... */ for (i = 0; i < NR_ACT; i++) { if (!id_seq[i]) continue; if ((p = get_activity_position(act, id_seq[i])) < 0) { /* Should never happen */ PANIC(1); } if (!IS_SELECTED(act[p]->options)) continue; if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) { rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, act[p]->id, &reset, file_actlst, cpu_nr, rectime, loctime); } else { unsigned int optf, msk; optf = act[p]->opt_flags; for (msk = 1; msk < 0x10; msk <<= 1) { if (act[p]->opt_flags & msk) { act[p]->opt_flags &= msk; rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, act[p]->id, &reset, file_actlst, cpu_nr, rectime, loctime); act[p]->opt_flags = optf; } } } } } if (!cnt) { /* Go to next Linux restart, if possible */ do { eosaf = sa_fread(ifd, &record_hdr[curr], RECORD_HEADER_SIZE, SOFT_SIZE); rtype = record_hdr[curr].record_type; if (!eosaf && (rtype != R_RESTART) && (rtype != R_COMMENT)) { read_file_stat_bunch(act, curr, ifd, file_hdr.sa_nr_act, file_actlst); } else if (!eosaf && (rtype == R_COMMENT)) { /* This was a COMMENT record: print it */ sadf_print_special(curr, tm_start.use, tm_end.use, R_COMMENT, ifd, rectime, loctime); } } while (!eosaf && (rtype != R_RESTART)); } /* The last record we read was a RESTART one: Print it */ if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) { sadf_print_special(curr, tm_start.use, tm_end.use, R_RESTART, ifd, rectime, loctime); } } while (!eosaf); }
/* *************************************************************************** * Display file contents in selected format (logic #2). * Logic #2: Grouped by activity. Sorted by timestamp. Stop on RESTART * records. * Formats: ppc, CSV * * IN: * @ifd File descriptor of input file. * @file_actlst List of (known or unknown) activities in file. * @cpu_nr Number of processors for current activity data file. * @rectime Structure where timestamp (expressed in local time or in UTC * depending on whether options -T/-t have been used or not) can * be saved for current record. * @loctime Structure where timestamp (expressed in local time) can be * saved for current record. * @file Name of file being read. * @file_magic file_magic structure filled with file magic header data. *************************************************************************** */ void logic2_display_loop(int ifd, struct file_activity *file_actlst, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime, char *file, struct file_magic *file_magic) { int i, p; int curr = 1, rtype; int eosaf = TRUE, reset = FALSE; long cnt = 1; off_t fpos; /* Read system statistics from file */ do { /* * If this record is a special (RESTART or COMMENT) one, print it and * (try to) get another one. */ do { if (read_next_sample(ifd, IGNORE_NOTHING, 0, file, &rtype, 0, file_magic, file_actlst, rectime, loctime)) /* End of sa data file */ return; } while ((rtype == R_RESTART) || (rtype == R_COMMENT) || (tm_start.use && (datecmp(loctime, &tm_start) < 0)) || (tm_end.use && (datecmp(loctime, &tm_end) >= 0))); /* Save the first stats collected. Used for example in next_slice() function */ copy_structures(act, id_seq, record_hdr, 2, 0); /* Set flag to reset last_uptime variable. Should be done after a LINUX RESTART record */ reset = TRUE; /* Save current file position */ if ((fpos = lseek(ifd, 0, SEEK_CUR)) < 0) { perror("lseek"); exit(2); } /* Read and write stats located between two possible Linux restarts */ if (DISPLAY_HORIZONTALLY(flags)) { /* * If stats are displayed horizontally, then all activities * are printed on the same line. */ rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, ALL_ACTIVITIES, &reset, file_actlst, cpu_nr, rectime, loctime, file, file_magic); } else { /* For each requested activity... */ for (i = 0; i < NR_ACT; i++) { if (!id_seq[i]) continue; p = get_activity_position(act, id_seq[i], EXIT_IF_NOT_FOUND); if (!IS_SELECTED(act[p]->options)) continue; if (!HAS_MULTIPLE_OUTPUTS(act[p]->options)) { rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, act[p]->id, &reset, file_actlst, cpu_nr, rectime, loctime, file, file_magic); } else { unsigned int optf, msk; optf = act[p]->opt_flags; for (msk = 1; msk < 0x100; msk <<= 1) { if ((act[p]->opt_flags & 0xff) & msk) { act[p]->opt_flags &= (0xffffff00 + msk); rw_curr_act_stats(ifd, fpos, &curr, &cnt, &eosaf, act[p]->id, &reset, file_actlst, cpu_nr, rectime, loctime, file, file_magic); act[p]->opt_flags = optf; } } } } } if (!cnt) { /* Go to next Linux restart, if possible */ do { eosaf = read_next_sample(ifd, IGNORE_RESTART | DONT_READ_VOLATILE, curr, file, &rtype, 0, file_magic, file_actlst, rectime, loctime); } while (!eosaf && (rtype != R_RESTART)); } /* * The last record we read was a RESTART one: Print it. * NB: Unlike COMMENTS records (which are displayed for each * activity), RESTART ones are only displayed once. */ if (!eosaf && (record_hdr[curr].record_type == R_RESTART)) { print_special_record(&record_hdr[curr], flags, &tm_start, &tm_end, R_RESTART, ifd, rectime, loctime, file, 0, file_magic, &file_hdr, act, fmt[f_position]); } } while (!eosaf); }