act_sar.o: activity.c sa.h pr_stats.h
$(CC) -o $@ -c $(CFLAGS) -DSOURCE_SAR $(DFLAGS) $<
-act_sadf.o: activity.c sa.h rndr_stats.h xml_stats.h json_stats.h svg_stats.h
+act_sadf.o: activity.c sa.h rndr_stats.h xml_stats.h json_stats.h svg_stats.h raw_stats.h
$(CC) -o $@ -c $(CFLAGS) -DSOURCE_SADF $(DFLAGS) $<
rd_stats.o: rd_stats.c common.h rd_stats.h ioconf.h sysconfig.h
svg_stats.o: svg_stats.c sa.h sadf.h ioconf.h sysconfig.h svg_stats.h
+raw_stats.o: raw_stats.c sa.h sadf.h ioconf.h sysconfig.h raw_stats.h
+
sa_wrap.o: sa_wrap.c sa.h rd_stats.h count.h rd_sensors.h prealloc.h
format_sadf.o: format.c sadf.h
sadf.o: sadf.c sadf.h version.h sa.h common.h ioconf.h sysconfig.h
-sadf: sadf.o act_sadf.o format_sadf.o sadf_misc.o sa_conv.o rndr_stats.o xml_stats.o json_stats.o svg_stats.o sa_common.o libsyscom.a
+sadf: sadf.o act_sadf.o format_sadf.o sadf_misc.o sa_conv.o rndr_stats.o xml_stats.o json_stats.o svg_stats.o raw_stats.o sa_common.o libsyscom.a
iostat.o: iostat.c iostat.h version.h common.h ioconf.h sysconfig.h rd_stats.h count.h
#include "xml_stats.h"
#include "json_stats.h"
#include "svg_stats.h"
+#include "raw_stats.h"
#endif
/*
.f_xml_print = xml_print_cpu_stats,
.f_json_print = json_print_cpu_stats,
.f_svg_print = svg_print_cpu_stats,
+ .f_raw_print = raw_print_cpu_stats,
.name = "A_CPU",
.g_nr = 1,
#endif
.f_xml_print = xml_print_pcsw_stats,
.f_json_print = json_print_pcsw_stats,
.f_svg_print = svg_print_pcsw_stats,
+ .f_raw_print = raw_print_pcsw_stats,
.name = "A_PCSW",
.g_nr = 2,
#endif
.f_comment = NULL
};
+/*
+ * Raw output.
+ */
+struct report_format raw_fmt = {
+ .id = F_RAW_OUTPUT,
+ .options = FO_GROUPED_STATS + FO_LOCAL_TIME + FO_SEC_EPOCH,
+ .f_header = NULL,
+ .f_statistics = NULL,
+ .f_timestamp = print_raw_timestamp,
+ .f_restart = print_raw_restart,
+ .f_comment = print_raw_comment
+};
+
/*
* Array of output formats.
*/
&xml_fmt,
&json_fmt,
&conv_fmt,
- &svg_fmt
+ &svg_fmt,
+ &raw_fmt
};
#endif
--- /dev/null
+/*
+ * raw_stats.c: Functions used by sar to display statistics in raw format.
+ * (C) 1999-2017 by Sebastien GODARD (sysstat <at> orange.fr)
+ *
+ ***************************************************************************
+ * This program is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU General Public License as published by the *
+ * Free Software Foundation; either version 2 of the License, or (at your *
+ * option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without the implied warranty of MERCHANTABILITY *
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
+ * for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License along *
+ * with this program; if not, write to the Free Software Foundation, Inc., *
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA *
+ ***************************************************************************
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include "sa.h"
+#include "ioconf.h"
+#include "raw_stats.h"
+
+extern unsigned int flags;
+
+
+/*
+ ***************************************************************************
+ * Display current field name.
+ *
+ * IN:
+ * @hdr_line On the first call, complete header line, containing all the
+ * metric names. In each subsequent call, must be NULL.
+ * @pos Index in @hdr_line string, 0 being the first one (headers
+ * are delimited by the '|' character).
+ ***************************************************************************
+ */
+char *pfield(char *hdr_line, int pos)
+{
+ char hline[HEADER_LINE_LEN] = "";
+ static char field[HEADER_LINE_LEN] = "";
+ static int idx = 0;
+ char *hl;
+ int i, j = 0;
+
+ if (hdr_line) {
+ strncpy(hline, hdr_line, HEADER_LINE_LEN - 1);
+ hline[HEADER_LINE_LEN - 1] = '\0';
+ idx = 0;
+
+ for (hl = strtok(hline, "|"); hl && (pos > 0); hl = strtok(NULL, "|"), pos--);
+ if (!hl) {
+ /* Bad @pos arg given to function */
+ strcpy(field, "");
+ return field;
+ }
+ if (strchr(hl, '&')) {
+ j = strcspn(hl, "&");
+ *(hl + j) = ';';
+ }
+ strcpy(field, hl);
+ }
+
+ /* Display current field */
+ if (strchr(field + idx, ';')) {
+ j = strcspn(field + idx, ";");
+ *(field + idx + j) = '\0';
+ }
+ i = idx;
+ idx += j + 1;
+
+ return field + i;
+}
+
+/*
+ ***************************************************************************
+ * Display field values.
+ *
+ * IN:
+ * @valp Field's value from previous statistics sample.
+ * @valc Field's value from current statistics sample.
+ ***************************************************************************
+ */
+void pval(unsigned long long valp, unsigned long long valc)
+{
+ printf("%llu>%llu", valp, valc);
+ if (DISPLAY_HINTS(flags)) {
+ if (valc < valp) {
+ /* Field's value has decreased */
+ printf(" [DEC]");
+ }
+ }
+}
+
+/*
+ ***************************************************************************
+ * Display CPU statistics in raw format.
+ *
+ * IN:
+ * @a Activity structure with statistics.
+ * @timestr Time for current statistics sample.
+ * @curr Index in array for current statistics sample.
+ ***************************************************************************
+ */
+__print_funct_t raw_print_cpu_stats(struct activity *a, char *timestr, int curr)
+{
+ int i;
+ struct stats_cpu *scc, *scp;
+
+ for (i = 0; (i < a->nr) && (i < a->bitmap->b_size + 1); i++) {
+
+ /*
+ * The size of a->buf[...] CPU structure may be different from the default
+ * sizeof(struct stats_cpu) value if data have been read from a file!
+ * That's why we don't use a syntax like:
+ * scc = (struct stats_cpu *) a->buf[...] + i;
+ */
+ scc = (struct stats_cpu *) ((char *) a->buf[curr] + i * a->msize);
+ scp = (struct stats_cpu *) ((char *) a->buf[!curr] + i * a->msize);
+
+ /*
+ * Note: a->nr is in [1, NR_CPUS + 1].
+ * Bitmap size is provided for (NR_CPUS + 1) CPUs.
+ * Anyway, NR_CPUS may vary between the version of sysstat
+ * used by sadc to create a file, and the version of sysstat
+ * used by sar to read it...
+ */
+
+ /* Should current CPU (including CPU "all") be displayed? */
+ if (!(a->bitmap->b_array[i >> 3] & (1 << (i & 0x07))))
+ /* No */
+ continue;
+
+ /* Yes: Display it */
+ printf("%s %s:%d", timestr,
+ pfield(a->hdr_line, DISPLAY_CPU_ALL(a->opt_flags)), i - 1);
+
+ if (DISPLAY_HINTS(flags) && i) {
+ if ((scc->cpu_user + scc->cpu_nice + scc->cpu_sys +
+ scc->cpu_iowait + scc->cpu_idle + scc->cpu_steal +
+ scc->cpu_hardirq + scc->cpu_softirq) == 0) {
+ /* CPU is offline */
+ printf(" [OFF]");
+ }
+ else {
+ if (!get_per_cpu_interval(scc, scp)) {
+ /* CPU is tickless */
+ printf(" [TLS]");
+ }
+ }
+ }
+
+ if (DISPLAY_CPU_DEF(a->opt_flags)) {
+ printf(" %s:", pfield(NULL, 0));
+ pval(scp->cpu_user, scc->cpu_user);
+ printf(" %s:", pfield(NULL, 0));
+ pval(scp->cpu_nice, scc->cpu_nice);
+ printf(" %s:", pfield(NULL, 0));
+ pval(scp->cpu_sys + scp->cpu_hardirq + scp->cpu_softirq,
+ scc->cpu_sys + scc->cpu_hardirq + scc->cpu_softirq);
+ printf(" %s:", pfield(NULL, 0));
+ pval(scp->cpu_iowait, scc->cpu_iowait);
+ printf(" %s:", pfield(NULL, 0));
+ pval(scp->cpu_steal, scc->cpu_steal);
+ printf(" %s:", pfield(NULL, 0));
+ pval(scp->cpu_idle, scc->cpu_idle);
+ }
+ else if (DISPLAY_CPU_ALL(a->opt_flags)) {
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_user - scp->cpu_guest, scc->cpu_user - scc->cpu_guest);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_nice - scp->cpu_guest_nice, scc->cpu_nice - scc->cpu_guest_nice);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_sys, scc->cpu_sys);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_iowait, scc->cpu_iowait);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_steal, scc->cpu_steal);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_hardirq, scc->cpu_hardirq);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_softirq, scc->cpu_softirq);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_guest, scc->cpu_guest);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_guest_nice, scc->cpu_guest_nice);
+ printf(" %s:", pfield(NULL, 1));
+ pval(scp->cpu_idle, scc->cpu_idle);
+ }
+ printf("\n");
+ }
+}
+
+/*
+ ***************************************************************************
+ * Display tasks creation and context switches statistics in raw format.
+ *
+ * IN:
+ * @a Activity structure with statistics.
+ * @timestr Time for current statistics sample.
+ * @curr Index in array for current sample statistics.
+ ***************************************************************************
+ */
+__print_funct_t raw_print_pcsw_stats(struct activity *a, char *timestr, int curr)
+{
+ struct stats_pcsw
+ *spc = (struct stats_pcsw *) a->buf[curr],
+ *spp = (struct stats_pcsw *) a->buf[!curr];
+
+ printf("%s %s:", timestr, pfield(a->hdr_line, 0));
+ pval(spp->processes, spc->processes);
+ printf(" %s:", pfield(NULL, 0));
+ pval(spp->context_switch, spc->context_switch);
+ printf("\n");
+}
--- /dev/null
+/*
+ * raw_stats.h: Include file used to display statistics in raw format.
+ * (C) 1999-2017 by Sebastien Godard (sysstat <at> orange.fr)
+ */
+
+#ifndef _RAW_STATS_H
+#define _RAW_STATS_H
+
+#include "common.h"
+
+/*
+ ***************************************************************************
+ * Prototypes for functions used to display statistics in raw format.
+ ***************************************************************************
+ */
+
+__print_funct_t raw_print_cpu_stats
+ (struct activity *, char *, int);
+__print_funct_t raw_print_pcsw_stats
+ (struct activity *, char *, int);
+
+#endif /* _RAW_STATS_H */
#define S_F_LOCAL_TIME 0x00004000
#define S_F_PREFD_TIME_OUTPUT 0x00008000
#define S_F_SVG_SKIP 0x00010000
+/* Same value as S_F_SVG_SKIP above. Used for a different output format */
+#define S_F_RAW_SHOW_HINTS 0x00010000
#define S_F_SVG_AUTOSCALE 0x00020000
#define S_F_SVG_ONE_DAY 0x00040000
#define S_F_SVG_SHOW_IDLE 0x00080000
#define PRINT_LOCAL_TIME(m) (((m) & S_F_LOCAL_TIME) == S_F_LOCAL_TIME)
#define USE_PREFD_TIME_OUTPUT(m) (((m) & S_F_PREFD_TIME_OUTPUT) == S_F_PREFD_TIME_OUTPUT)
#define SKIP_EMPTY_VIEWS(m) (((m) & S_F_SVG_SKIP) == S_F_SVG_SKIP)
+#define DISPLAY_HINTS(m) (((m) & S_F_RAW_SHOW_HINTS) == S_F_RAW_SHOW_HINTS)
#define AUTOSCALE_ON(m) (((m) & S_F_SVG_AUTOSCALE) == S_F_SVG_AUTOSCALE)
#define DISPLAY_ONE_DAY(m) (((m) & S_F_SVG_ONE_DAY) == S_F_SVG_ONE_DAY)
#define DISPLAY_IDLE(m) (((m) & S_F_SVG_SHOW_IDLE) == S_F_SVG_SHOW_IDLE)
#define K_AUTOSCALE "autoscale"
#define K_ONEDAY "oneday"
#define K_SHOWIDLE "showidle"
+#define K_SHOWHINTS "showhints"
/* Groups of activities */
#define G_DEFAULT 0x00
*/
__print_funct_t (*f_svg_print) (struct activity *, int, int, struct svg_parm *,
unsigned long long, struct record_header *);
+ /*
+ * This function is used by sadf to display activity statistics in raw format.
+ */
+ __print_funct_t (*f_raw_print) (struct activity *, char *, int);
/*
* Header string displayed by sadf -d.
* Header lines for each output (for activities with multiple outputs) are
&record_hdr[curr]);
}
+ else if (format == F_RAW_OUTPUT) {
+ /* Raw output */
+ (*act[i]->f_raw_print)(act[i], pre, curr);
+ }
+
else {
/* Other output formats: db, ppc */
(*act[i]->f_render)(act[i], (format == F_DB_OUTPUT), pre, curr,
* Display file contents in selected format (logic #2).
* Logic #2: Grouped by activity. Sorted by timestamp. Stop on RESTART
* records.
- * Formats: ppc, CSV
+ * Formats: ppc, CSV, raw
*
* IN:
* @ifd File descriptor of input file.
}
else if (!strcmp(argv[opt], "-O")) {
- /* Parse SVG options */
+ /* Parse output options */
if (!argv[++opt] || sar_options) {
usage(argv[0]);
}
else if (!strcmp(t, K_SHOWIDLE)) {
flags |= S_F_SVG_SHOW_IDLE;
}
+ else if (!strcmp(t, K_SHOWHINTS)) {
+ flags |= S_F_RAW_SHOW_HINTS;
+ }
else {
usage(argv[0]);
}
format = F_PPC_OUTPUT;
break;
+ case 'r':
+ if (format) {
+ usage(argv[0]);
+ }
+ format = F_RAW_OUTPUT;
+ break;
+
case 'T':
flags |= S_F_LOCAL_TIME;
break;
*/
/* Number of output formats */
-#define NR_FMT 7
+#define NR_FMT 8
/* Output formats */
#define F_DB_OUTPUT 1
#define F_JSON_OUTPUT 5
#define F_CONV_OUTPUT 6
#define F_SVG_OUTPUT 7
+#define F_RAW_OUTPUT 8
/* Format options */
(int *, int, char *, char *, int, struct file_header *, unsigned int);
__printf_funct_t print_sar_restart
(int *, int, char *, char *, int, struct file_header *, unsigned int);
+__printf_funct_t print_raw_restart
+ (int *, int, char *, char *, int, struct file_header *, unsigned int);
/*
* Prototypes used to display comments
(int *, int, char *, char *, int, char *, struct file_header *);
__printf_funct_t print_sar_comment
(int *, int, char *, char *, int, char *, struct file_header *);
+__printf_funct_t print_raw_comment
+ (int *, int, char *, char *, int, char *, struct file_header *);
/*
* Prototypes used to display the statistics part of the report
(void *, int, char *, char *, unsigned long long, struct file_header *, unsigned int);
__tm_funct_t print_json_timestamp
(void *, int, char *, char *, unsigned long long, struct file_header *, unsigned int);
+__tm_funct_t print_raw_timestamp
+ (void *, int, char *, char *, unsigned long long, struct file_header *, unsigned int);
/*
* Prototypes used to display the report header
}
}
+/*
+ ***************************************************************************
+ * Display restart messages (raw format).
+ *
+ * IN:
+ * @tab Number of tabulations (unused here).
+ * @action Action expected from current function.
+ * @cur_date Date string of current restart message.
+ * @cur_time Time string of current restart message.
+ * @utc True if @cur_time is expressed in UTC.
+ * @file_hdr System activity file standard header (unused here).
+ * @cpu_nr CPU count associated with restart mark.
+ ***************************************************************************
+ */
+__printf_funct_t print_raw_restart(int *tab, int action, char *cur_date,
+ char *cur_time, int utc, struct file_header *file_hdr,
+ unsigned int cpu_nr)
+{
+ /* Actions F_BEGIN and F_END ignored */
+ if (action == F_MAIN) {
+ printf("%s", cur_time);
+ if (strlen(cur_date) && utc) {
+ printf(" UTC");
+ }
+ printf("\tLINUX-RESTART\t(%d CPU)\n", cpu_nr > 1 ? cpu_nr - 1 : 1);
+ }
+}
+
/*
***************************************************************************
* Display comments (database and ppc formats).
}
}
+/*
+ ***************************************************************************
+ * Display comments (raw format).
+ *
+ * IN:
+ * @tab Number of tabulations (unused here).
+ * @action Action expected from current function.
+ * @cur_date Date string of current restart message.
+ * @cur_time Time string of current restart message.
+ * @utc True if @cur_time is expressed in UTC.
+ * @comment Comment to display.
+ * @file_hdr System activity file standard header (unused here).
+ ***************************************************************************
+ */
+__printf_funct_t print_raw_comment(int *tab, int action, char *cur_date,
+ char *cur_time, int utc, char *comment,
+ struct file_header *file_hdr)
+{
+ /* Actions F_BEGIN and F_END ignored */
+ if (action & F_MAIN) {
+ printf("%s", cur_time);
+ if (strlen(cur_date) && utc) {
+ printf(" UTC");
+ }
+ printf("\tCOM %s\n", comment);
+ }
+}
+
/*
***************************************************************************
* Display the "statistics" part of the report (XML format).
return NULL;
}
+/*
+ ***************************************************************************
+ * Display the "timestamp" part of the report (raw 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 (unused here).
+ * @file_hdr System activity file standard header (unused here).
+ * @flags Flags for common options.
+ *
+ * RETURNS:
+ * Pointer on the "timestamp" string.
+ ***************************************************************************
+ */
+__tm_funct_t print_raw_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);
+ static char pre[80];
+
+ if (action & F_BEGIN) {
+ snprintf(pre, 80, "%s%s", cur_time, strlen(cur_date) && utc ? " UTC" : "");
+ pre[79] = '\0';
+ return pre;
+ }
+
+ return NULL;
+}
+
/*
***************************************************************************
* Display the header of the report (XML format).