From: Sebastien GODARD Date: Sat, 13 Apr 2019 09:28:35 +0000 (+0200) Subject: sadf: PCP: Save RESTART records in PCP archive X-Git-Tag: v12.1.4~6 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=45e412cdc03cb7951c6d6414328ab65c14193bd8;p=sysstat sadf: PCP: Save RESTART records in PCP archive Signed-off-by: Sebastien GODARD --- diff --git a/format.c b/format.c index 64c578a..37dce19 100644 --- a/format.c +++ b/format.c @@ -156,11 +156,11 @@ struct report_format raw_fmt = { struct report_format pcp_fmt = { .id = F_PCP_OUTPUT, .options = FO_HEADER_ONLY + FO_LOCAL_TIME + FO_NO_TRUE_TIME + - FO_ITEM_LIST, + FO_ITEM_LIST + FO_FULL_ORDER, .f_header = print_pcp_header, .f_statistics = print_pcp_statistics, .f_timestamp = print_pcp_timestamp, - .f_restart = NULL, + .f_restart = print_pcp_restart, .f_comment = NULL, .f_display = logic1_display_loop }; diff --git a/sa.h b/sa.h index 9d6f1b8..52ad70b 100644 --- a/sa.h +++ b/sa.h @@ -1033,7 +1033,8 @@ struct report_format { /* * This function displays the restart messages. */ - __printf_funct_t (*f_restart) (int *, int, char *, char *, int, struct file_header *); + __printf_funct_t (*f_restart) (int *, int, char *, char *, int, + struct file_header *, struct record_header *); /* * This function displays the comments. */ @@ -1045,6 +1046,7 @@ struct report_format { struct tm *, struct tm *, void *); }; + /* Possible actions for functions used to display reports */ #define F_BEGIN 0x01 #define F_MAIN 0x02 @@ -1390,7 +1392,7 @@ void print_report_hdr void print_sar_comment (int *, int, char *, char *, int, char *, struct file_header *); __printf_funct_t print_sar_restart - (int *, int, char *, char *, int, struct file_header *); + (int *, int, char *, char *, int, struct file_header *, struct record_header *); int print_special_record (struct record_header *, unsigned int, struct tstamp *, struct tstamp *, int, int, struct tm *, struct tm *, char *, int, struct file_magic *, diff --git a/sa_common.c b/sa_common.c index 08f097a..7941efa 100644 --- a/sa_common.c +++ b/sa_common.c @@ -2908,7 +2908,7 @@ int print_special_record(struct record_header *record_hdr, unsigned int l_flags, if (*ofmt->f_restart) { (*ofmt->f_restart)(&tab, F_MAIN, cur_date, cur_time, !PRINT_LOCAL_TIME(l_flags) && - !PRINT_TRUE_TIME(l_flags), file_hdr); + !PRINT_TRUE_TIME(l_flags), file_hdr, record_hdr); } } else if (rtype == R_COMMENT) { diff --git a/sadf.c b/sadf.c index e19cb85..fe3062c 100644 --- a/sadf.c +++ b/sadf.c @@ -1022,6 +1022,7 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, { int curr, rtype, tab = 0; int eosaf, next, reset = FALSE; + int ign_flag = IGNORE_COMMENT + IGNORE_RESTART; long cnt = 1; char *pcparchive = (char *) dparm; @@ -1031,7 +1032,6 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, /* No record to display */ return; } - /* Save current file position */ seek_file_position(ifd, DO_SAVE); @@ -1041,6 +1041,20 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, &file_hdr, act, id_seq, file_actlst); } + if (ORDER_ALL_RECORDS(fmt[f_position]->options)) { + ign_flag = IGNORE_NOTHING; + + /* RESTART and COMMENTS records will be immediately processed */ + if (*fmt[f_position]->f_restart) { + (*fmt[f_position]->f_restart)(&tab, F_BEGIN, NULL, NULL, FALSE, + &file_hdr, NULL); + } + if (DISPLAY_COMMENT(flags) && (*fmt[f_position]->f_comment)) { + (*fmt[f_position]->f_comment)(&tab, F_BEGIN, NULL, NULL, 0, NULL, + &file_hdr); + } + } + /* Process activities */ if (*fmt[f_position]->f_statistics) { (*fmt[f_position]->f_statistics)(&tab, F_BEGIN, act, id_seq); @@ -1049,11 +1063,11 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, do { /* * If this record is a special (RESTART or COMMENT) one, - * skip it and try to read the next record in file. + * process it then try to read the next record in file. */ do { - eosaf = read_next_sample(ifd, IGNORE_COMMENT | IGNORE_RESTART, 0, - file, &rtype, tab, file_magic, file_actlst, + eosaf = read_next_sample(ifd, ign_flag, 0, file, + &rtype, tab, file_magic, file_actlst, rectime, loctime, UEOF_STOP); } while (!eosaf && ((rtype == R_RESTART) || (rtype == R_COMMENT) || @@ -1069,8 +1083,8 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, if (!eosaf) { do { - eosaf = read_next_sample(ifd, IGNORE_COMMENT | IGNORE_RESTART, curr, - file, &rtype, tab, file_magic, file_actlst, + eosaf = read_next_sample(ifd, ign_flag, curr, file, + &rtype, tab, file_magic, file_actlst, rectime, loctime, UEOF_CONT); if (!eosaf && (rtype != R_COMMENT) && (rtype != R_RESTART)) { @@ -1097,8 +1111,8 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, if (!cnt) { /* Go to next Linux restart, if possible */ do { - eosaf = read_next_sample(ifd, IGNORE_COMMENT | IGNORE_RESTART, curr, - file, &rtype, tab, file_magic, file_actlst, + eosaf = read_next_sample(ifd, ign_flag, curr, file, + &rtype, tab, file_magic, file_actlst, rectime, loctime, UEOF_CONT); } while (!eosaf && (rtype != R_RESTART)); @@ -1112,13 +1126,29 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, (*fmt[f_position]->f_statistics)(&tab, F_END, act, id_seq); } + if (ign_flag == IGNORE_NOTHING) { + /* + * RESTART and COMMENT records have already been processed. + * Display possible trailing data then terminate. + */ + if (*fmt[f_position]->f_restart) { + (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, + FALSE, &file_hdr, NULL); + } + if (DISPLAY_COMMENT(flags) && (*fmt[f_position]->f_comment)) { + (*fmt[f_position]->f_comment)(&tab, F_END, NULL, NULL, 0, NULL, + &file_hdr); + } + goto terminate; + } + /* Rewind file */ seek_file_position(ifd, DO_RESTORE); /* Process now RESTART entries to display restart messages */ if (*fmt[f_position]->f_restart) { (*fmt[f_position]->f_restart)(&tab, F_BEGIN, NULL, NULL, FALSE, - &file_hdr); + &file_hdr, NULL); } do { @@ -1129,7 +1159,7 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, while (!eosaf); if (*fmt[f_position]->f_restart) { - (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr); + (*fmt[f_position]->f_restart)(&tab, F_END, NULL, NULL, FALSE, &file_hdr, NULL); } /* Rewind file */ @@ -1154,6 +1184,7 @@ void logic1_display_loop(int ifd, char *file, struct file_activity *file_actlst, } } +terminate: /* Print header trailer */ if (*fmt[f_position]->f_header) { (*fmt[f_position]->f_header)(&tab, F_END, pcparchive, file_magic, diff --git a/sadf.h b/sadf.h index 7e96abd..6736792 100644 --- a/sadf.h +++ b/sadf.h @@ -102,6 +102,12 @@ */ #define FO_ITEM_LIST 0x200 +/* + * Indicate that all the records, including RESTART and COMMENT ones, + * should be displayed in order of time. + */ +#define FO_FULL_ORDER 0x400 + #define SET_LC_NUMERIC_C(m) (((m) & FO_LC_NUMERIC_C) == FO_LC_NUMERIC_C) #define ACCEPT_HEADER_ONLY(m) (((m) & FO_HEADER_ONLY) == FO_HEADER_ONLY) #define ACCEPT_BAD_FILE_FORMAT(m) (((m) & FO_BAD_FILE_FORMAT) == FO_BAD_FILE_FORMAT) @@ -112,6 +118,7 @@ #define TEST_MARKUP(m) (((m) & FO_TEST_MARKUP) == FO_TEST_MARKUP) #define REJECT_TRUE_TIME(m) (((m) & FO_NO_TRUE_TIME) == FO_NO_TRUE_TIME) #define CREATE_ITEM_LIST(m) (((m) & FO_ITEM_LIST) == FO_ITEM_LIST) +#define ORDER_ALL_RECORDS(m) (((m) & FO_FULL_ORDER) == FO_FULL_ORDER) /* @@ -127,15 +134,17 @@ void convert_file * Prototypes used to display restart messages */ __printf_funct_t print_db_restart - (int *, int, char *, char *, int, struct file_header *); + (int *, int, char *, char *, int, struct file_header *, struct record_header *); __printf_funct_t print_ppc_restart - (int *, int, char *, char *, int, struct file_header *); + (int *, int, char *, char *, int, struct file_header *, struct record_header *); __printf_funct_t print_xml_restart - (int *, int, char *, char *, int, struct file_header *); + (int *, int, char *, char *, int, struct file_header *, struct record_header *); __printf_funct_t print_json_restart - (int *, int, char *, char *, int, struct file_header *); + (int *, int, char *, char *, int, struct file_header *, struct record_header *); __printf_funct_t print_raw_restart - (int *, int, char *, char *, int, struct file_header *); + (int *, int, char *, char *, int, struct file_header *, struct record_header *); +__printf_funct_t print_pcp_restart + (int *, int, char *, char *, int, struct file_header *, struct record_header *); /* * Prototypes used to display comments diff --git a/sadf_misc.c b/sadf_misc.c index 8d07038..10e575d 100644 --- a/sadf_misc.c +++ b/sadf_misc.c @@ -47,6 +47,53 @@ extern char *seps[]; extern int palette; extern unsigned int svg_colors[][SVG_COL_PALETTE_SIZE]; +/* + *************************************************************************** + * Flush data to PCP archive. + * + * IN: + * @record_hdr Record header for current sample. + * @flags Flags for common options. + *************************************************************************** + */ +void pcp_write_data(struct record_header *record_hdr, unsigned int flags) +{ +#ifdef HAVE_PCP + int rc; + struct tm lrectime; + unsigned long long utc_sec = record_hdr->ust_time; + static long long delta_utc = LONG_MAX; + + if (!PRINT_LOCAL_TIME(flags)) { + if (delta_utc == LONG_MAX) { + /* Convert a time_t value from local time to UTC */ + if (gmtime_r((const time_t *) &(record_hdr->ust_time), &lrectime)) { + utc_sec = mktime(&lrectime); + delta_utc = utc_sec - record_hdr->ust_time; + } + } + else { + /* + * Once pmiWrite() has been called (after the first stats sample), + * subsequent mktime() calls will not give the same result with + * the same input data. So compute a time shift that will be used + * for the next samples. + * We should (really) be careful if pmiWrite() was to be used sooner + * than for the first stats sample (e.g. if we want to save a + * LINUX RESTART record heading the file). + */ + utc_sec += delta_utc; + } + } + + /* Write data to PCP archive */ + if ((rc = pmiWrite(utc_sec, 0)) < 0) { + fprintf(stderr, "PCP: pmiWrite: %s\n", pmiErrStr(rc)); + exit(4); + } +#endif +} + /* *************************************************************************** * Display restart messages (database and ppc formats). @@ -85,10 +132,12 @@ void print_dbppc_restart(char *cur_date, char *cur_time, int utc, char sep, * @cur_time Time string of current restart message. * @utc True if @cur_time is expressed in UTC. * @file_hdr System activity file standard header. + * @record_hdr Current record header (unused here). *************************************************************************** */ __printf_funct_t print_db_restart(int *tab, int action, char *cur_date, - char *cur_time, int utc, struct file_header *file_hdr) + char *cur_time, int utc, struct file_header *file_hdr, + struct record_header *record_hdr) { /* Actions F_BEGIN and F_END ignored */ if (action == F_MAIN) { @@ -107,10 +156,12 @@ __printf_funct_t print_db_restart(int *tab, int action, char *cur_date, * @cur_time Time string of current restart message. * @utc True if @cur_time is expressed in UTC. * @file_hdr System activity file standard header. + * @record_hdr Current record header (unused here). *************************************************************************** */ __printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date, - char *cur_time, int utc, struct file_header *file_hdr) + char *cur_time, int utc, struct file_header *file_hdr, + struct record_header *record_hdr) { /* Actions F_BEGIN and F_END ignored */ if (action == F_MAIN) { @@ -129,13 +180,15 @@ __printf_funct_t print_ppc_restart(int *tab, int action, char *cur_date, * @cur_time Time string of current restart message. * @utc True if @cur_time is expressed in UTC. * @file_hdr System activity file standard header. + * @record_hdr Current record header (unused here). * * OUT: * @tab Number of tabulations. *************************************************************************** */ __printf_funct_t print_xml_restart(int *tab, int action, char *cur_date, - char *cur_time, int utc, struct file_header *file_hdr) + char *cur_time, int utc, struct file_header *file_hdr, + struct record_header *record_hdr) { if (action & F_BEGIN) { xprintf((*tab)++, ""); @@ -161,13 +214,15 @@ __printf_funct_t print_xml_restart(int *tab, int action, char *cur_date, * @cur_time Time string of current restart message. * @utc True if @cur_time is expressed in UTC. * @file_hdr System activity file standard header. + * @record_hdr Current record header (unused here). * * OUT: * @tab Number of tabulations. *************************************************************************** */ __printf_funct_t print_json_restart(int *tab, int action, char *cur_date, - char *cur_time, int utc, struct file_header *file_hdr) + char *cur_time, int utc, struct file_header *file_hdr, + struct record_header *record_hdr) { static int sep = FALSE; @@ -206,10 +261,12 @@ __printf_funct_t print_json_restart(int *tab, int action, char *cur_date, * @cur_time Time string of current restart message. * @utc True if @cur_time is expressed in UTC. * @file_hdr System activity file standard header. + * @record_hdr Current record header (unused here). *************************************************************************** */ __printf_funct_t print_raw_restart(int *tab, int action, char *cur_date, - char *cur_time, int utc, struct file_header *file_hdr) + char *cur_time, int utc, struct file_header *file_hdr, + struct record_header *record_hdr) { /* Actions F_BEGIN and F_END ignored */ if (action == F_MAIN) { @@ -222,6 +279,59 @@ __printf_funct_t print_raw_restart(int *tab, int action, char *cur_date, } } +/* + *************************************************************************** + * Display restart messages (PCP format). + * + * IN: + * @tab Number of tabulations (unused here). + * @action Action expected from current function. + * @cur_date Date string of current restart message (unused here). + * @cur_time Time string of current restart message (unused here). + * @utc True if @cur_time is expressed in UTC (unused here). + * @file_hdr System activity file standard header. + * @record_hdr Current record header. + *************************************************************************** + */ +__printf_funct_t print_pcp_restart(int *tab, int action, char *cur_date, char *cur_time, + int utc, struct file_header *file_hdr, + struct record_header *record_hdr) +{ +#ifdef HAVE_PCP + static int def_metrics = FALSE; + int rc; + char buf[64]; + + if (action & F_BEGIN) { + if (!def_metrics) { + pmiAddMetric("system.restart.count", + PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, + pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE)); + + pmiAddMetric("system.restart.ncpu", + PM_IN_NULL, PM_TYPE_U32, PM_INDOM_NULL, PM_SEM_DISCRETE, + pmiUnits(0, 0, 1, 0, 0, PM_COUNT_ONE)); + + def_metrics = TRUE; + } + } + if (action & F_MAIN) { + if ((rc = pmiPutValue("system.restart.count", NULL, "1")) < 0) { + fprintf(stderr, "PCP: pmiPutValue 1: %s\n", pmiErrStr(rc)); + } + + snprintf(buf, sizeof(buf), "%u", + file_hdr->sa_cpu_nr > 1 ? file_hdr->sa_cpu_nr - 1 : 1); + if ((rc = pmiPutValue("system.restart.ncpu", NULL, buf)) < 0) { + fprintf(stderr, "PCP: pmiPutValue 2: %s\n", pmiErrStr(rc)); + } + + /* Write data to PCP archive */ + pcp_write_data(record_hdr, flags); + } +#endif /* HAVE_PCP */ +} + /* *************************************************************************** * Display comments (database and ppc formats). @@ -853,7 +963,7 @@ __tm_funct_t print_raw_timestamp(void *parm, int action, char *cur_date, * @itv Interval of time with preceding record (unused here). * @record_hdr Record header for current sample. * @file_hdr System activity file standard header (unused here). - * @flags Flags for common options (unused here). + * @flags Flags for common options. * * RETURNS: * Pointer on the "timestamp" string. @@ -864,42 +974,10 @@ __tm_funct_t print_pcp_timestamp(void *parm, int action, char *cur_date, struct record_header *record_hdr, struct file_header *file_hdr, unsigned int flags) { -#ifdef HAVE_PCP - int rc; - struct tm lrectime; - unsigned long long utc_sec = record_hdr->ust_time; - static long long delta_utc = LONG_MAX; - if (action & F_END) { - if (!PRINT_LOCAL_TIME(flags)) { - if (delta_utc == LONG_MAX) { - /* Convert a time_t value from local time to UTC */ - if (gmtime_r((const time_t *) &(record_hdr->ust_time), &lrectime)) { - utc_sec = mktime(&lrectime); - delta_utc = utc_sec - record_hdr->ust_time; - } - } - else { - /* - * Once pmiWrite() has been called (after the first stats sample), - * subsequent mktime() calls will not give the same result with - * the same input data. So compute a time shift that will be used - * for the next samples. - * We should (really) be careful if pmiWrite() was to be used sooner - * than for the first stats sample (e.g. if we want to save a - * LINUX RESTART record heading the file). - */ - utc_sec += delta_utc; - } - } - - /* Write data to PCP archive */ - if ((rc = pmiWrite(utc_sec, 0)) < 0) { - fprintf(stderr, "PCP: pmiWrite: %s\n", pmiErrStr(rc)); - exit(4); - } + pcp_write_data(record_hdr, flags); } -#endif + return NULL; } diff --git a/sar.c b/sar.c index e19b115..b7315ae 100644 --- a/sar.c +++ b/sar.c @@ -602,10 +602,12 @@ int sa_read(void *buffer, size_t size) * @cur_time Time string of current restart message. * @utc True if @cur_time is expressed in UTC (unused here). * @file_hdr System activity file standard header. + * @record_hdr Current record header (unused here). *************************************************************************** */ __printf_funct_t print_sar_restart(int *tab, int action, char *cur_date, char *cur_time, - int utc, struct file_header *file_hdr) + int utc, struct file_header *file_hdr, + struct record_header *record_hdr) { char restart[64];