Skip to content

Commit

Permalink
sadf: Add new output format: raw (part 1)
Browse files Browse the repository at this point in the history
Add a new output format to sadf to display statistics saved in a binary
data file in raw format. Counters values are displayed "as is", without
trying to calculate an average value over the elapsed time interval.
This is something I have selfishly wanted to have for a long time now,
mainly for debugging purpose.
This first patch adds all the necessary global functions, and implements
the raw format only for CPU and task creation/system switching
statistics.

Signed-off-by: Sebastien GODARD <sysstat@users.noreply.github.com>
  • Loading branch information
sysstat committed Dec 18, 2016
1 parent ee98c70 commit 526bf49
Show file tree
Hide file tree
Showing 9 changed files with 388 additions and 6 deletions.
6 changes: 4 additions & 2 deletions Makefile.in
Expand Up @@ -187,7 +187,7 @@ act_sadc.o: activity.c sa.h rd_stats.h rd_sensors.h
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
Expand All @@ -214,6 +214,8 @@ json_stats.o: json_stats.c sa.h sadf.h ioconf.h sysconfig.h json_stats.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
Expand Down Expand Up @@ -253,7 +255,7 @@ sar: sar.o act_sar.o format_sar.o sa_common.o pr_stats.o libsyscom.a

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

Expand Down
3 changes: 3 additions & 0 deletions activity.c
Expand Up @@ -35,6 +35,7 @@
#include "xml_stats.h"
#include "json_stats.h"
#include "svg_stats.h"
#include "raw_stats.h"
#endif

/*
Expand Down Expand Up @@ -92,6 +93,7 @@ struct activity cpu_act = {
.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
Expand Down Expand Up @@ -128,6 +130,7 @@ struct activity pcsw_act = {
.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
Expand Down
16 changes: 15 additions & 1 deletion format.c
Expand Up @@ -127,6 +127,19 @@ struct report_format svg_fmt = {
.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.
*/
Expand All @@ -137,7 +150,8 @@ struct report_format *fmt[NR_FMT] = {
&xml_fmt,
&json_fmt,
&conv_fmt,
&svg_fmt
&svg_fmt,
&raw_fmt
};
#endif

Expand Down
222 changes: 222 additions & 0 deletions raw_stats.c
@@ -0,0 +1,222 @@
/*
* 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");
}
22 changes: 22 additions & 0 deletions raw_stats.h
@@ -0,0 +1,22 @@
/*
* 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 */
8 changes: 8 additions & 0 deletions sa.h
Expand Up @@ -99,6 +99,8 @@
#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
Expand All @@ -121,6 +123,7 @@
#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)
Expand Down Expand Up @@ -206,6 +209,7 @@
#define K_AUTOSCALE "autoscale"
#define K_ONEDAY "oneday"
#define K_SHOWIDLE "showidle"
#define K_SHOWHINTS "showhints"

/* Groups of activities */
#define G_DEFAULT 0x00
Expand Down Expand Up @@ -691,6 +695,10 @@ struct activity {
*/
__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
Expand Down

0 comments on commit 526bf49

Please sign in to comment.