/* *************************************************************************** * Print statistics average. * * IN: * @curr Index in array for current sample statistics. * @read_from_file Set to TRUE if stats are read from a system activity * data file. * @act_id Activity that can be displayed, or ~0 for all. * Remember that when reading stats from a file, only * one activity can be displayed at a time. *************************************************************************** */ void write_stats_avg(int curr, int read_from_file, unsigned int act_id) { int i; unsigned long long itv, g_itv; static __nr_t cpu_nr = -1; if (cpu_nr < 0) cpu_nr = act[get_activity_position(act, A_CPU)]->nr; /* Interval value in jiffies */ g_itv = get_interval(record_hdr[2].uptime, record_hdr[curr].uptime); if (cpu_nr > 1) itv = get_interval(record_hdr[2].uptime0, record_hdr[curr].uptime0); else itv = g_itv; strncpy(timestamp[curr], _("Average:"), TIMESTAMP_LEN); timestamp[curr][TIMESTAMP_LEN - 1] = '\0'; strcpy(timestamp[!curr], timestamp[curr]); /* Test stdout */ TEST_STDOUT(STDOUT_FILENO); 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)) { /* Display current average activity statistics */ (*act[i]->f_print_avg)(act[i], 2, curr, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } if (read_from_file) { /* * Reset number of lines printed only if we read stats * from a system activity file. */ avg_count = 0; } }
/* *************************************************************************** * 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"); } }
/* *************************************************************************** * Print system statistics. * * IN: * @curr Index in array for current sample statistics. * @read_from_file Set to TRUE if stats are read from a system activity * data file. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @reset Set to TRUE if last_uptime variable should be * reinitialized (used in next_slice() function). * @act_id Activity that can be displayed or ~0 for all. * Remember that when reading stats from a file, only * one activity can be displayed at a time. * * OUT: * @cnt Number of remaining lines to display. * * RETURNS: * 1 if stats have been successfully displayed, and 0 otherwise. *************************************************************************** */ int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start, int use_tm_end, int reset, unsigned int act_id) { int i; unsigned long long itv, g_itv; static int cross_day = 0; static __nr_t cpu_nr = -1; if (cpu_nr < 0) cpu_nr = act[get_activity_position(act, A_CPU)]->nr; /* Check time (1) */ if (read_from_file) { if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0, reset, interval)) /* Not close enough to desired interval */ return 0; } /* Set previous timestamp */ if (set_record_timestamp_string(!curr, timestamp[!curr], 16)) return 0; /* Set current timestamp */ if (set_record_timestamp_string(curr, timestamp[curr], 16)) return 0; /* Check if we are beginning a new day */ if (use_tm_start && record_hdr[!curr].ust_time && (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) && (record_hdr[curr].hour < record_hdr[!curr].hour)) { cross_day = 1; } if (cross_day) { /* * This is necessary if we want to properly handle something like: * sar -s time_start -e time_end with * time_start(day D) > time_end(day D+1) */ rectime.tm_hour +=24; } /* Check time (2) */ if (use_tm_start && (datecmp(&rectime, &tm_start) < 0)) /* it's too soon... */ return 0; /* Get interval values */ get_itv_value(&record_hdr[curr], &record_hdr[!curr], cpu_nr, &itv, &g_itv); /* Check time (3) */ if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) { /* It's too late... */ *cnt = 0; return 0; } avg_count++; /* Test stdout */ TEST_STDOUT(STDOUT_FILENO); 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)) { /* Display current activity statistics */ (*act[i]->f_print)(act[i], !curr, curr, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } return 1; }
/* *************************************************************************** * Print system statistics. * * IN: * @curr Index in array for current sample statistics. * @read_from_file Set to TRUE if stats are read from a system activity * data file. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @reset Set to TRUE if last_uptime variable should be * reinitialized (used in next_slice() function). * @act_id Activity that can be displayed or ~0 for all. * Remember that when reading stats from a file, only * one activity can be displayed at a time. * @reset_cd TRUE if static cross_day variable should be reset * (see below). * * OUT: * @cnt Number of remaining lines to display. * * RETURNS: * 1 if stats have been successfully displayed, and 0 otherwise. *************************************************************************** */ int write_stats(int curr, int read_from_file, long *cnt, int use_tm_start, int use_tm_end, int reset, unsigned int act_id, int reset_cd) { int i; unsigned long long itv, g_itv; static int cross_day = 0; static __nr_t cpu_nr = -1; if (cpu_nr < 0) cpu_nr = act[get_activity_position(act, A_CPU, EXIT_IF_NOT_FOUND)]->nr; if (reset_cd) { /* * cross_day is a static variable that is set to 1 when the first * record of stats from a new day is read from a unique data file * (in the case where the file contains data from two consecutive * days). When set to 1, every following records timestamp will * have its hour value increased by 24. * Yet when a new activity (being read from the file) is going to * be displayed, we start reading the file from the beginning * again, and so cross_day should be reset in this case. */ cross_day = 0; } /* Check time (1) */ if (read_from_file) { if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0, reset, interval)) /* Not close enough to desired interval */ return 0; } /* Set previous timestamp */ if (set_record_timestamp_string(!curr, timestamp[!curr], 16)) return 0; /* Set current timestamp */ if (set_record_timestamp_string(curr, timestamp[curr], 16)) return 0; /* Check if we are beginning a new day */ if (use_tm_start && record_hdr[!curr].ust_time && (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) && (record_hdr[curr].hour < record_hdr[!curr].hour)) { cross_day = 1; } if (cross_day) { /* * This is necessary if we want to properly handle something like: * sar -s time_start -e time_end with * time_start(day D) > time_end(day D+1) */ rectime.tm_hour +=24; } /* Check time (2) */ if (use_tm_start && (datecmp(&rectime, &tm_start) < 0)) /* it's too soon... */ return 0; /* Get interval values */ get_itv_value(&record_hdr[curr], &record_hdr[!curr], cpu_nr, &itv, &g_itv); /* Check time (3) */ if (use_tm_end && (datecmp(&rectime, &tm_end) > 0)) { /* It's too late... */ *cnt = 0; return 0; } avg_count++; /* Test stdout */ TEST_STDOUT(STDOUT_FILENO); 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)) { /* Display current activity statistics */ (*act[i]->f_print)(act[i], !curr, curr, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } return 1; }
/* *************************************************************************** * Display activity records for textual (XML-like) formats. * * IN: * @curr Index in array for current sample statistics. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @reset Set to TRUE if last_uptime should be reinitialized * (used in next_slice() function). * @tab Number of tabulations to print. * @cpu_nr Number of processors. * @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. * * OUT: * @cnt Set to 0 to indicate that no other lines of stats * should be displayed. * * RETURNS: * 1 if stats have been successfully displayed. *************************************************************************** */ int write_textual_stats(int curr, int use_tm_start, int use_tm_end, int reset, long *cnt, int tab, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime) { int i; unsigned long long dt, itv, g_itv; char cur_date[32], cur_time[32]; static int cross_day = FALSE; /* Fill timestamp structure (rectime) for current record */ sadf_get_record_timestamp_struct(curr, rectime, loctime); /* * Check time (1). * For this first check, we use the time interval entered on * the command line. This is equivalent to sar's option -i which * selects records at seconds as close as possible to the number * specified by the interval parameter. */ if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0, reset, interval)) /* Not close enough to desired interval */ return 0; /* Check if we are beginning a new day */ if (use_tm_start && record_hdr[!curr].ust_time && (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) && (record_hdr[curr].hour < record_hdr[!curr].hour)) { cross_day = TRUE; } if (cross_day) { /* * This is necessary if we want to properly handle something like: * sar -s time_start -e time_end with * time_start(day D) > time_end(day D+1) */ loctime->tm_hour += 24; } /* Check time (2) */ if (use_tm_start && (datecmp(loctime, &tm_start) < 0)) /* it's too soon... */ return 0; /* Get interval values */ get_itv_value(&record_hdr[curr], &record_hdr[!curr], cpu_nr, &itv, &g_itv); /* Check time (3) */ if (use_tm_end && (datecmp(loctime, &tm_end) > 0)) { /* It's too late... */ *cnt = 0; return 0; } dt = itv / HZ; /* Correct rounding error for dt */ if ((itv % HZ) >= (HZ / 2)) { dt++; } /* Set date and time strings for current record */ set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime); if (*fmt[f_position]->f_timestamp) { (*fmt[f_position]->f_timestamp)(&tab, F_BEGIN, cur_date, cur_time, !PRINT_TRUE_TIME(flags), dt); } if (format == F_XML_OUTPUT) { tab++; } /* Display textual statistics */ for (i = 0; i < NR_ACT; i++) { /* This code is not generic at all...! */ if (format == F_JSON_OUTPUT) { /* JSON output */ if (CLOSE_MARKUP(act[i]->options) || (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) { if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) { printf(","); if (*fmt[f_position]->f_timestamp) { (*fmt[f_position]->f_timestamp)(&tab, F_MAIN, cur_date, cur_time, !PRINT_TRUE_TIME(flags), dt); } } (*act[i]->f_json_print)(act[i], curr, tab, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } else { /* XML output */ if (CLOSE_MARKUP(act[i]->options) || (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) { (*act[i]->f_xml_print)(act[i], curr, tab, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } } if (*fmt[f_position]->f_timestamp) { (*fmt[f_position]->f_timestamp)(&tab, F_END, cur_date, cur_time, !PRINT_TRUE_TIME(flags), dt); } return 1; }
/* *************************************************************************** * Display *one* sample of statistics for one or several activities, * checking that all conditions are met before printing (time start, time * end, interval). Current record should be a record of statistics (R_STATS), * not a special one (R_RESTART or R_COMMENT). * * IN: * @curr Index in array for current sample statistics. * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @reset Set to TRUE if last_uptime should be reinitialized * (used in next_slice() function). * @parm Pointer on parameters depending on output format * (eg.: number of tabulations to print). * @cpu_nr Number of processors. * @rectime Structure where timestamp (expressed in local time * or in UTC depending on whether options -T/-t have * been used or not) has been saved for current record. * @loctime Structure where timestamp (expressed in local time) * has been saved for current record. * @reset_cd TRUE if static cross_day variable should be reset. * @act_id Activity to display (only for formats where * activities are displayed one at a time) or * ALL_ACTIVITIES for all. * * OUT: * @cnt Set to 0 to indicate that no other lines of stats * should be displayed. * * RETURNS: * 1 if stats have been successfully displayed. *************************************************************************** */ int generic_write_stats(int curr, int use_tm_start, int use_tm_end, int reset, long *cnt, void *parm, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime, int reset_cd, unsigned int act_id) { int i; unsigned long long dt, itv, g_itv; char cur_date[32], cur_time[32], *pre = NULL; static int cross_day = FALSE; if (reset_cd) { /* * See note in sar.c. * NB: Reseting cross_day is needed only if datafile * may be rewinded (eg. in db or ppc output formats). */ cross_day = 0; } /* * Check time (1). * For this first check, we use the time interval entered on * the command line. This is equivalent to sar's option -i which * selects records at seconds as close as possible to the number * specified by the interval parameter. */ if (!next_slice(record_hdr[2].uptime0, record_hdr[curr].uptime0, reset, interval)) /* Not close enough to desired interval */ return 0; /* Check if we are beginning a new day */ if (use_tm_start && record_hdr[!curr].ust_time && (record_hdr[curr].ust_time > record_hdr[!curr].ust_time) && (record_hdr[curr].hour < record_hdr[!curr].hour)) { cross_day = TRUE; } if (cross_day) { /* * This is necessary if we want to properly handle something like: * sar -s time_start -e time_end with * time_start(day D) > time_end(day D+1) */ loctime->tm_hour += 24; } /* Check time (2) */ if (use_tm_start && (datecmp(loctime, &tm_start) < 0)) /* it's too soon... */ return 0; /* Get interval values */ get_itv_value(&record_hdr[curr], &record_hdr[!curr], cpu_nr, &itv, &g_itv); /* Check time (3) */ if (use_tm_end && (datecmp(loctime, &tm_end) > 0)) { /* It's too late... */ *cnt = 0; return 0; } dt = itv / HZ; /* Correct rounding error for dt */ if ((itv % HZ) >= (HZ / 2)) { dt++; } /* Set date and time strings for current record */ set_record_timestamp_string(flags, &record_hdr[curr], cur_date, cur_time, 32, rectime); if (*fmt[f_position]->f_timestamp) { pre = (char *) (*fmt[f_position]->f_timestamp)(parm, F_BEGIN, cur_date, cur_time, dt, &file_hdr, flags); } /* Display statistics */ for (i = 0; i < NR_ACT; i++) { if ((act_id != ALL_ACTIVITIES) && (act[i]->id != act_id)) continue; if ((TEST_MARKUP(fmt[f_position]->options) && CLOSE_MARKUP(act[i]->options)) || (IS_SELECTED(act[i]->options) && (act[i]->nr > 0))) { if (format == F_JSON_OUTPUT) { /* JSON output */ int *tab = (int *) parm; if (IS_SELECTED(act[i]->options) && (act[i]->nr > 0)) { if (*fmt[f_position]->f_timestamp) { (*fmt[f_position]->f_timestamp)(tab, F_MAIN, cur_date, cur_time, dt, &file_hdr, flags); } } (*act[i]->f_json_print)(act[i], curr, *tab, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } else if (format == F_XML_OUTPUT) { /* XML output */ int *tab = (int *) parm; (*act[i]->f_xml_print)(act[i], curr, *tab, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } else if (format == F_SVG_OUTPUT) { /* SVG output */ struct svg_parm *svg_p = (struct svg_parm *) parm; svg_p->dt = (unsigned long) dt; (*act[i]->f_svg_print)(act[i], curr, F_MAIN, svg_p, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv, &record_hdr[curr]); } else { /* Other output formats: db, ppc */ (*act[i]->f_render)(act[i], (format == F_DB_OUTPUT), pre, curr, NEED_GLOBAL_ITV(act[i]->options) ? g_itv : itv); } } } if (*fmt[f_position]->f_timestamp) { (*fmt[f_position]->f_timestamp)(parm, F_END, cur_date, cur_time, dt, &file_hdr, flags); } return 1; }