/* *************************************************************************** * 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; }
/* *************************************************************************** * Write system statistics. * * IN: * @curr Index in array for current sample statistics. * @reset Set to TRUE if last_uptime variable should be * reinitialized (used in next_slice() function). * @use_tm_start Set to TRUE if option -s has been used. * @use_tm_end Set to TRUE if option -e has been used. * @act_id Activities to display. * @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. * * OUT: * @cnt Set to 0 to indicate that no other lines of stats * should be displayed. * * RETURNS: * 1 if a line of stats has been displayed, and 0 otherwise. *************************************************************************** */ int write_parsable_stats(int curr, int reset, long *cnt, int use_tm_start, int use_tm_end, unsigned int act_id, __nr_t cpu_nr, struct tm *rectime, struct tm *loctime) { unsigned long long dt, itv, g_itv; char cur_date[32], cur_time[32]; static int cross_day = FALSE; /* * 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; /* Fill timestamp structure for current record */ sadf_get_record_timestamp_struct(curr, rectime, loctime); /* 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 current timestamp string */ set_record_timestamp_string(curr, cur_date, cur_time, 32, rectime); write_mech_stats(curr, dt, itv, g_itv, cur_date, cur_time, act_id); 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; }