From 81748fb1a7a798f8006c251b67671d8dbd97ad6a Mon Sep 17 00:00:00 2001 From: Sebastien GODARD Date: Sun, 22 May 2016 10:53:07 +0200 Subject: [PATCH] SVG: Add "oneday" option This option (to be used with sadf's switch -O) tells sadf to display graph data over a period of 24 hours. Hours are still printed in UTC by default, use switch -T to print them in local time and get a time window going from 00H to 00H, eg.: sadf -g -T -O oneday -- -A > out.svg Signed-off-by: Sebastien GODARD --- sa.h | 13 +++++++++---- sadf.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- svg_stats.c | 45 +++++++++++++++++++++++++++++++++------------ 3 files changed, 87 insertions(+), 19 deletions(-) diff --git a/sa.h b/sa.h index e9476c3..edcfb71 100644 --- a/sa.h +++ b/sa.h @@ -99,6 +99,7 @@ #define S_F_PREFD_TIME_OUTPUT 0x00008000 #define S_F_SVG_SKIP 0x00010000 #define S_F_SVG_AUTOSCALE 0x00020000 +#define S_F_SVG_ONE_DAY 0x00040000 #define WANT_SINCE_BOOT(m) (((m) & S_F_SINCE_BOOT) == S_F_SINCE_BOOT) #define WANT_SA_ROTAT(m) (((m) & S_F_SA_ROTAT) == S_F_SA_ROTAT) @@ -118,6 +119,7 @@ #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 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 AO_F_NULL 0x00000000 @@ -195,6 +197,7 @@ #define K_SKIP_EMPTY "skipempty" #define K_AUTOSCALE "autoscale" +#define K_ONEDAY "oneday" /* Groups of activities */ #define G_DEFAULT 0x00 @@ -281,10 +284,12 @@ /* Structure for SVG specific parameters */ struct svg_parm { - unsigned long dt; - unsigned long ust_time_ref; - int graph_no; - int restart; + unsigned long dt; /* Interval of time for current sample */ + unsigned long ust_time_ref; /* X axis start time in seconds since the epoch */ + unsigned long ust_time_end; /* X axis end time in seconds since the epoch */ + unsigned long ust_time_first; /* Time (in seconds since the epoch) for first sample */ + int graph_no; /* Total number of views already displayed */ + int restart; /* TRUE if we have just met a RESTART record */ }; diff --git a/sadf.c b/sadf.c index 54e724b..0939cd9 100644 --- a/sadf.c +++ b/sadf.c @@ -448,6 +448,36 @@ void list_fields(unsigned int act_id) printf("\n"); } +/* + *************************************************************************** + * Determine the time (expressed in seconds since the epoch) used as the + * origin on X axis for SVG graphs. If S_F_SVG_ONE_DAY is set, then origin + * will be the beginning of current day (00:00:00) else it will be the time + * of the first sample collected. + * + * RETURNS: + * Time origin on X axis (expressed in seconds since the epoch). + *************************************************************************** + */ +time_t get_time_ref(void) +{ + struct tm *ltm; + time_t t; + + if (DISPLAY_ONE_DAY(flags)) { + ltm = localtime((time_t *) &(record_hdr[2].ust_time)); + + /* Move back to midnight */ + ltm->tm_sec = ltm->tm_min = ltm->tm_hour = 0; + + t = mktime(ltm); + if (t != -1) + return t; + } + + return record_hdr[2].ust_time; +} + /* *************************************************************************** * Compute the number of SVG graphs to display. Each activity selected may @@ -571,7 +601,6 @@ int get_svg_graph_nr(int ifd, char *file, struct file_magic *file_magic, return tot_g_nr; } - /* *************************************************************************** * Display *one* sample of statistics for one or several activities, @@ -855,7 +884,7 @@ void rw_curr_act_stats(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf, * @eosaf Set to TRUE if EOF (end of file) has been reached. * @reset Set to TRUE if last_uptime variable should be * reinitialized (used in next_slice() function). - * @g_nr Total number of graphs displayed (including current activity). + * @g_nr Total number of views displayed (including current activity). *************************************************************************** */ void display_curr_act_graphs(int ifd, off_t fpos, int *curr, long *cnt, int *eosaf, @@ -886,7 +915,8 @@ void display_curr_act_graphs(int ifd, off_t fpos, int *curr, long *cnt, int *eos copy_structures(act, id_seq, record_hdr, !*curr, 2); parm.graph_no = *g_nr; - parm.ust_time_ref = record_hdr[2].ust_time; + parm.ust_time_ref = get_time_ref(); + parm.ust_time_first = record_hdr[2].ust_time; parm.restart = TRUE; *cnt = count; @@ -937,6 +967,15 @@ void display_curr_act_graphs(int ifd, off_t fpos, int *curr, long *cnt, int *eos *reset = TRUE; + /* Determine X axis end value */ + if (DISPLAY_ONE_DAY(flags) && + (parm.ust_time_ref + (3600 * 24) > record_hdr[!*curr].ust_time)) { + parm.ust_time_end = parm.ust_time_ref + (3600 * 24); + } + else { + parm.ust_time_end = record_hdr[!*curr].ust_time; + } + /* Actually display graphs for current activity */ (*act[p]->f_svg_print)(act[p], *curr, F_END, &parm, 0, &record_hdr[!*curr]); @@ -1506,6 +1545,9 @@ int main(int argc, char **argv) else if (!strcmp(t, K_AUTOSCALE)) { flags |= S_F_SVG_AUTOSCALE; } + else if (!strcmp(t, K_ONEDAY)) { + flags |= S_F_SVG_ONE_DAY; + } else { usage(argv[0]); } diff --git a/svg_stats.c b/svg_stats.c index 7e08185..c1ff5de 100644 --- a/svg_stats.c +++ b/svg_stats.c @@ -570,17 +570,20 @@ double ygrid(double lmax, int *dp) * IN: * @timestart First data timestamp (X coordinate of the first data point). * @timeend Last data timestamp (X coordinate of the last data point). + * @v_gridnr Number of vertical lines to display. Its value is normally + * SVG_V_GRIDNR, except when option "oneday" is used, in which + * case it is set to 12. * * RETURNS: * Value between two vertical lines. *************************************************************************** */ -long int xgrid(unsigned long timestart, unsigned long timeend) +long int xgrid(unsigned long timestart, unsigned long timeend, int v_gridnr) { - if ((timeend - timestart) <= SVG_V_GRIDNR) + if ((timeend - timestart) <= v_gridnr) return 1; else - return ((timeend - timestart) / SVG_V_GRIDNR); + return ((timeend - timestart) / v_gridnr); } /* @@ -625,8 +628,10 @@ void free_graphs(char **out, int *outsize, double *spmin, double *spmax) * @spmax Array containing max values for graphs. * @out Pointer on array of chars for each graph definition. * @outsize Size of array of chars for each graph definition. - * @svg_p SVG specific parameters: Current graph number (.@graph_no) - * and time used for the X axis origin (.@ust_time_ref). + * @svg_p SVG specific parameters: Current graph number (.@graph_no), + * time for the first sample of stats (.@ust_time_first), and + * times used as start and end values on the X axis + * (.@ust_time_ref and .@ust_time_end). * @record_hdr Pointer on record header of current stats sample. *************************************************************************** */ @@ -638,6 +643,7 @@ void draw_activity_graphs(int g_nr, int g_type, char *title[], char *g_title[], struct tm rectime; char *out_p; int i, j, dp, pos = 0, views_nr = 0; + int v_gridnr; unsigned int asfactor[16]; long int k; double lmax, xfactor, yfactor, ypos, gmin, gmax; @@ -681,7 +687,7 @@ void draw_activity_graphs(int g_nr, int g_type, char *title[], char *g_title[], * At least two samples are needed. * And a min and max value should have been found. */ - if ((record_hdr->ust_time == svg_p->ust_time_ref) || + if ((record_hdr->ust_time == svg_p->ust_time_first) || (*(spmin + pos) == DBL_MAX) || (*(spmax + pos) == -DBL_MIN)) { /* No data found */ printf("No data\n", @@ -778,18 +784,33 @@ void draw_activity_graphs(int g_nr, int g_type, char *title[], char *g_title[], } while (ypos * j <= lmax); - k = xgrid(svg_p->ust_time_ref, record_hdr->ust_time); - xfactor = (double) SVG_G_XSIZE / (record_hdr->ust_time - svg_p->ust_time_ref); + /* Set number of vertical lines to 12 when option "oneday" is used */ + v_gridnr = DISPLAY_ONE_DAY(flags) ? 12 : SVG_V_GRIDNR; + + k = xgrid(svg_p->ust_time_ref, svg_p->ust_time_end, v_gridnr); + xfactor = (double) SVG_G_XSIZE / (svg_p->ust_time_end - svg_p->ust_time_ref); stamp.ust_time = svg_p->ust_time_ref; /* Only ust_time field needs to be set. TRUE_TIME not allowed */ - for (j = 0; (j <= SVG_V_GRIDNR) && (stamp.ust_time <= record_hdr->ust_time); j++) { + + for (j = 0; (j <= v_gridnr) && (stamp.ust_time <= svg_p->ust_time_end); j++) { sa_get_record_timestamp_struct(flags, &stamp, &rectime, NULL); set_record_timestamp_string(flags, &stamp, NULL, cur_time, 32, &rectime); printf("\n", k * j, k * j, -SVG_G_YSIZE, xfactor); - printf("%s\n", - (long) (k * j * xfactor), (long) (k * j * xfactor), cur_time); + /* + * NB: We may have tm_min != 0 if we have more than 24H worth of data in one datafile. + * In this case, we should rather display the exact time instead of only the hour. + */ + if (DISPLAY_ONE_DAY(flags) && (rectime.tm_min == 0)) { + printf("%2dH\n", + (long) (k * j * xfactor) - 8, rectime.tm_hour); + } + else { + printf("%s\n", + (long) (k * j * xfactor), (long) (k * j * xfactor), cur_time); + } stamp.ust_time += k; } if (!PRINT_LOCAL_TIME(flags)) { -- 2.40.0