Discussion:
[PATCH 2/2] version3, Add time stamp collection to operf and opreport,
(too old to reply)
Carl E. Love
2016-03-23 16:02:50 UTC
Permalink
Raw Message
Updated version 3, OProfile Time stamp processing support

Version 3, fixed trailing white space, extra blank lines. Removed gnuplot
and created a C program, generate_svg.c to draw the graphs using svn. The
plot_time_stamps.sh scrip was removed. the utils/process_time_stamps.prl
was updated to work with the generate_svg.c program.

Version 2
This patch adds two scripts for processing and plotting the time stamp
data collected by operf. The primary script is in utils/plot_time_stamps.sh
This script calls the perl script utils/processs_time_stamps.prl that does
the majority of the data processing.

The first version only supported plotting the time stamps for a profile
collected on a single event. This version adds support for plotting the
events when collecting multiple events at a time. It also includes some
fixes for issues in the original patch found while adding the multiple
event plotting support.

Signed-off-by: Carl Love <***@us.ibm.com>
---
doc/Makefile.am | 3 +-
utils/Makefile.am | 4 +-
utils/generate_svg.c | 1071 +++++++++++++++++++++++++++++++++++++++++
utils/process_time_stamps.prl | 829 +++++++++++++++++++++++++++++++
4 files changed, 1905 insertions(+), 2 deletions(-)
create mode 100644 utils/generate_svg.c
create mode 100755 utils/process_time_stamps.prl

diff --git a/doc/Makefile.am b/doc/Makefile.am
index 43a7781..9a87835 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -20,7 +20,8 @@ man_MANS = \

if BUILD_FOR_PERF_EVENT
man_MANS += operf.1 \
- ocount.1
+ ocount.1 \
+ plot_time_stamps.1
endif

htmldir = $(prefix)/share/doc/oprofile
diff --git a/utils/Makefile.am b/utils/Makefile.am
index 408dc54..9e8439e 100644
--- a/utils/Makefile.am
+++ b/utils/Makefile.am
@@ -7,7 +7,9 @@ AM_LDFLAGS = @OP_LDFLAGS@

LIBS=@POPT_LIBS@ @LIBERTY_LIBS@

-bin_PROGRAMS = ophelp op-check-perfevents
+bin_PROGRAMS = ophelp op-check-perfevents generate_svg
+
+bin_SCRIPTS = process_time_stamps.prl

op_check_perfevents_SOURCES = op_perf_events_checker.c
op_check_perfevents_CPPFLAGS = ${AM_CFLAGS} @PERF_EVENT_FLAGS@
diff --git a/utils/generate_svg.c b/utils/generate_svg.c
new file mode 100644
index 0000000..67ba952
--- /dev/null
+++ b/utils/generate_svg.c
@@ -0,0 +1,1071 @@
+/*
+ * generate_svg.c
+ *
+ * This program takes a data file consisting of the X values in the first
+ * column, then multiple Y data set values in the subsequent columns and
+ * plots the data. The header of the data file is expected to contain the
+ * axis title, graph title, command to make a line or bar graph, etc. The
+ * program generates svg commands to plot the data in the specified type of
+ * graph.
+ *
+ * Read the file COPYING
+ *
+ * Created on: March 15, 2016
+ * Author Carl Love ***@us.ibm.com
+ * (C) Copyright IBM Corp. 2016
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sched.h>
+#include <link.h>
+#include <float.h>
+#include <limits.h>
+
+#define TRUE 1
+#define FALSE 0
+#define DEBUG FALSE
+
+#define MAX_X_AXIS_TICKS 14
+#define MAX_Y_AXIS_TICKS 12
+
+#define SVG_WIDTH 12 // changing these affects entire graph/text scaling
+#define SVG_HEIGHT 6
+
+#define GRAPH_WIDTH (SVG_WIDTH*100 - Y_AXIS_WIDTH - X_AXIS_SPACER)
+#define GRAPH_HEIGHT (SVG_HEIGHT*100 - X_AXIS_LEGEND - X_AXIS_VALUES - TITLE_HEIGHT - BIN_SIZE_SPACER - LEGEND_SPACER)
+
+#define BOX_WIDTH SVG_WIDTH*100+10
+#define BOX_HEIGHT SVG_HEIGHT*100+10
+
+#define TITLE_HEIGHT 12
+#define TITLE_SPACER 12
+#define Y_AXIS_WIDTH 75
+#define Y_AXIS_SPACER 10
+#define X_AXIS_SPACER 2
+#define X_AXIS_VALUES 20
+#define X_AXIS_LEGEND 20
+
+#define X_AXIS_TITLE_LEN 131
+#define Y_AXIS_TITLE_LEN 50
+#define INPUT_LINE_LEN 200 // must be at least as large as the longest title length
+
+#define X_AXIS_FONT_SIZE 7
+#define Y_AXIS_FONT_SIZE 7
+
+// can get 130 26pt characters in GRAPH_WIDTH
+#define AXIS_TITLE_CHAR_WIDTH GRAPH_WIDTH/130
+#define X_TITLE_FONT_SIZE 12
+#define Y_TITLE_FONT_SIZE 12
+
+
+// can get 80 40pt characters in GRAPH_WIDTH
+#define TITLE_FONT_SIZE 18
+#define TITLE_CHAR_WIDTH GRAPH_WIDTH/80
+
+#define BIN_SIZE_SPACER 16
+#define LEGEND_SPACER 2
+#define LEGEND_HEIGHT 16
+#define LEGEND_TITLE_LEN 50
+#define LEGEND_FONT_SIZE 11
+#define LINE_INFO_LENGTH 10
+
+/* assumed number of characters in number plus value separator. */
+#define EST_DATA_VALUE_SIZE 15
+
+#define LINE_WIDTH "2"
+#define BAR_WIDTH "3"
+
+/* types of graphs supported */
+#define LINE_GRAPH 0
+#define BAR_GRAPH 1
+
+#define OUTPUT_FILE_NAME_LEN 100
+/* NOTE: INPUTFILE must match $DEFAULT_OUTPUT_DATA_FILE in
+ * process_time_stamps.prl
+*/
+#define INPUTFILE "__workload_tm_data.dat__"
+
+struct data_file_info_st {
+ char graph_title[X_AXIS_TITLE_LEN];
+ char x_axis_title[X_AXIS_TITLE_LEN];
+ char y_axis_title[Y_AXIS_TITLE_LEN];
+ char **event_names;
+ int number_events;
+ int number_bins;
+ double *x_array;
+ long **y_array;
+ double min_x_value, max_x_value;
+ double start_time, end_time; //User specified a subset of the data
+ long min_y_value, max_y_value;
+ int graph_type;
+ char plot_file_name[OUTPUT_FILE_NAME_LEN];
+ int graph_width;
+ int number_x_ticks;
+ double x_bin_size;
+};
+
+void generate_header(FILE *fp, struct data_file_info_st *data_file_info) {
+ float scale_by = 1.0;
+ int box_width = BOX_WIDTH;
+
+ /* Setup the size of the box needed for the graph and the legend */
+ fprintf(fp, "<?xml version=\"1.0\"?>\n");
+ fprintf(fp, "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\"\n");
+ fprintf(fp, " \"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\">\n");
+
+ data_file_info->graph_width = GRAPH_WIDTH;
+ data_file_info->number_x_ticks = MAX_X_AXIS_TICKS;
+
+ if (data_file_info->number_bins > 200) {
+ /* The width of the graph was setup assuming the default of 200 bins on
+ * the X-axis. If the user specified more then 200 bins, increase the
+ * width of the graph and adjust the number of ticks on the x-axis.
+ */
+ scale_by = ((float)data_file_info->number_bins - 200)/200.0;
+ data_file_info->graph_width += scale_by * GRAPH_WIDTH;
+ data_file_info->number_x_ticks += (int)(scale_by * MAX_X_AXIS_TICKS);
+ box_width += (int)(scale_by * (float)GRAPH_WIDTH);
+ }
+
+ fprintf(fp, "<svg width=\"%d\" height=\"%d\" viewBox=\"0 0 %d %d\">\n",
+ box_width,
+ BOX_HEIGHT + BIN_SIZE_SPACER
+ + data_file_info->number_events * LEGEND_HEIGHT,
+ data_file_info->graph_width,
+ BOX_HEIGHT + BIN_SIZE_SPACER
+ + data_file_info->number_events * LEGEND_HEIGHT);
+
+ fprintf(fp, "<title>Lines</title>\n");
+ fprintf(fp, "<desc>Line examples</desc>\n\n");
+}
+
+void get_axis_scale(long int input_magnitude, long int *magnitude, char *format) {
+ /* Given the magnitude of the input value, setup the format string with the
+ * appropriate magnitude value, K, M, G in the format string. The returned
+ * magnitude corresponds to the amount the values need to be scaled by for
+ * the format specifier.
+ */
+ if ( input_magnitude < 1000) {
+ *magnitude = 1;
+ strcpy(format, "%3.2f");
+ }
+
+ if ((input_magnitude >= 1000) && (input_magnitude < 1000000)) {
+ *magnitude = 1000;
+ strcpy(format, "%3.2fK");
+ }
+
+ if ((input_magnitude >= 1000000) && (input_magnitude < 1000000000)) {
+ *magnitude = 1000000;
+ strcpy(format, "%3.2fM");
+ }
+
+ if ((input_magnitude >= 1000000000) && (input_magnitude < 1000000000000)) {
+ *magnitude = 1000000000;
+ strcpy(format, "%3.2fG");
+ }
+
+ if ((input_magnitude >= 1000000000000) && ( input_magnitude < 1000000000000000)) {
+ *magnitude = 1000000000;
+ strcpy(format, "%3.2fT");
+ }
+
+ if (input_magnitude >= 1000000000000000) {
+ *magnitude = 1000000000000;
+ strcpy(format, "%4.3fP");
+ }
+}
+
+float calculate_increment(double max_value, double min_value,
+ int max_ticks, int *num_intervals,
+ long int *magnitude) {
+ /* Given the max and min values on the axis, determine the
+ * delta value for each increment on the axis given the
+ * number of intervals on the axis.
+ */
+
+ int done = FALSE;
+ float tick_increment;
+
+ *magnitude = 1;
+ tick_increment = (max_value - min_value)/(max_ticks + 1);
+
+#if DEBUG
+ printf("calculate_increment: max_value = %f, min_value = %f\n",
+ max_value, min_value);
+ printf("calculate_increment: max_ticks = %d, tick_increment = %f\n\n",
+ max_ticks, tick_increment);
+#endif
+
+ if (tick_increment < 0) {
+ fprintf(stdout, "%s line %d: ERROR tick_increment is negative. \n",
+ __FILE__,__LINE__);
+ exit(-1);
+ }
+
+ while (!done) {
+ if (max_value < 10 * (*magnitude)) {
+ done = TRUE;
+ break;
+ }
+ *magnitude = *magnitude * 10;
+ }
+
+ /* Calculated tick increment with MAX + 1 so we can print one
+ * more tick mark above the max value. Need to increment num intervals
+ * by one.
+ */
+ *num_intervals = ((max_value - min_value) / tick_increment) + 1;
+
+#if DEBUG
+ printf("calculate_increment: num_intervals = %d\n\n", *num_intervals);
+#endif
+ return tick_increment;
+}
+
+float draw_x_axis(FILE *fp, struct data_file_info_st *data) {
+ /* The routine draws the X-axis and lables. It also calculates the
+ * the spacing on the screen for an increment of 1 on the X-axis
+ * scale. The unit screen spacing value is passed back for use
+ * in the data graphing function.
+ */
+
+ int i;
+ int num_x_intervals;
+ float x_tick_increment;
+ float x_tick_space, length_x_axis = 0;
+ long int magnitude;
+ long int x_magnitude;
+ char format[10], str[10];
+
+ /* calculate the X axis tick interval and number of intervals. */
+ x_tick_increment = calculate_increment(data->max_x_value,
+ data->min_x_value,
+ data->number_x_ticks,
+ &num_x_intervals, &x_magnitude);
+
+#if DEBUG
+ printf("num_x_intervals = %d, x_tick_increment = %f, x_magnitude = %ld\n",
+ num_x_intervals, x_tick_increment, x_magnitude);
+#endif
+
+ /* Calculate tick spacing for x axis, note, increment of the value
+ * was based on num intervals + 1 so need to repeat here.
+ */
+ x_tick_space = (float)data->graph_width/(float)(num_x_intervals + 1);
+
+ /* Determine X-axis label */
+ get_axis_scale(x_magnitude, &magnitude, format);
+
+ fprintf(fp," <!-- Draw X-axis -->\n");
+
+ /* Print one more x-axis interval past max value */
+ for (i = 0; i <= num_x_intervals; i++) {
+ fprintf(fp, "<svg>\n");
+
+ length_x_axis = (float)Y_AXIS_WIDTH + ((float)i * x_tick_space);
+
+ fprintf(fp, " <line x%d=\"%f\" y%d=\"%d\" x%d=\"%f\" y%d=\"%d\"\n",
+ 1, length_x_axis, 1, GRAPH_HEIGHT + TITLE_HEIGHT,
+ 2, length_x_axis, 2, GRAPH_HEIGHT + TITLE_HEIGHT + 10);
+
+ fprintf(fp, " style=\"stroke-width: 1; stroke: black;\"/>\n");
+ fprintf(fp, "</svg>\n\n");
+
+ sprintf(str, format,
+ (data->start_time + data->min_x_value
+ + ((float)i*x_tick_increment))/(float)magnitude);
+
+ fprintf(fp, "<text x=\"%f\" y=\"%d\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">%s</text>\n\n",
+ length_x_axis, GRAPH_HEIGHT + TITLE_HEIGHT + X_AXIS_VALUES,
+ X_AXIS_FONT_SIZE, str);
+ }
+
+ fprintf(fp, " <line x1=\"%d\" y1=\"%d\" x2=\"%f\" y2=\"%d\"\n",
+ Y_AXIS_WIDTH, GRAPH_HEIGHT + TITLE_HEIGHT,
+ length_x_axis, GRAPH_HEIGHT + TITLE_HEIGHT);
+
+ fprintf(fp, " style=\"stroke-width: 1; stroke: black;\"/>\n");
+
+ fprintf(fp," <!-- print X-axis title -->\n");
+
+ fprintf(fp, "<text x=\"%f\" y=\"%d\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">%s</text>\n\n",
+ (float)(Y_AXIS_WIDTH + data->graph_width/2
+ - (strlen(data->x_axis_title) * AXIS_TITLE_CHAR_WIDTH)/2),
+ GRAPH_HEIGHT + TITLE_HEIGHT + X_AXIS_VALUES + X_AXIS_LEGEND,
+ X_TITLE_FONT_SIZE, data->x_axis_title);
+
+ return (x_tick_space/x_tick_increment);
+}
+
+float draw_y_axis(FILE *fp, struct data_file_info_st *data) {
+ /* The routine draws the Y-axis and lables. It also calculates the
+ * the spacing on the screen for an increment of 1 on the Y-axis
+ * scale. The unit screen spacing value is passed back for use
+ * in the data graphing function.
+ */
+
+ int i;
+ int num_y_intervals;
+ float y_tick_space, length_y_axis = 0;
+ float y_tick_increment;
+ long int magnitude;
+ long int y_magnitude;
+ char format[10], str[10];
+
+ /* calculate the Y axis tick interval and number of intervals. */
+ y_tick_increment = calculate_increment((double)data->max_y_value,
+ (double)data->min_y_value,
+ MAX_Y_AXIS_TICKS,
+ &num_y_intervals, &y_magnitude);
+
+#if DEBUG
+ printf("num_y_intervals = %d, y_tick_increment = %f, y_magnitude = %ld\n",
+ num_y_intervals, y_tick_increment, y_magnitude);
+#endif
+
+ /* Calculate tick spacing for y axis, note, increment of the value
+ * was based on num intervals + 1 so need to repeat here.
+ */
+ y_tick_space = (float)GRAPH_HEIGHT/(float)(num_y_intervals + 1);
+
+ get_axis_scale(y_magnitude, &magnitude, format);
+
+ fprintf(fp," <!-- Draw Y-axis -->\n");
+
+ /* Print one more y-axis location past max value */
+ for (i = 0; i <= num_y_intervals; i++) {
+ fprintf(fp, "<svg>\n");
+
+ length_y_axis = (float)i * y_tick_space;
+
+ fprintf(fp, " <line x%d=\"%d\" y%d=\"%f\" x%d=\"%d\" y%d=\"%f\"\n",
+ 1, Y_AXIS_WIDTH - 10,
+ 1, (float)GRAPH_HEIGHT + TITLE_HEIGHT - length_y_axis,
+ 2, Y_AXIS_WIDTH,
+ 2, (float)GRAPH_HEIGHT + TITLE_HEIGHT - length_y_axis);
+
+ fprintf(fp, " style=\"stroke-width: 1; stroke: black;\"/>\n");
+ fprintf(fp, "</svg>\n\n");
+
+ sprintf(str, format,
+ data->min_y_value + ((float)i * y_tick_increment)/(float)magnitude);
+
+ fprintf(fp, "<text x=\"%d\" y=\"%f\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">%s</text>\n\n",
+ 0, GRAPH_HEIGHT + TITLE_HEIGHT - length_y_axis,
+ Y_AXIS_FONT_SIZE, str);
+ }
+
+ fprintf(fp, " <line x1=\"%d\" y1=\"%d\" x2=\"%d\" y2=\"%f\"\n",
+ Y_AXIS_WIDTH,
+ GRAPH_HEIGHT + TITLE_HEIGHT,
+ Y_AXIS_WIDTH,
+ ((float)GRAPH_HEIGHT + TITLE_HEIGHT -length_y_axis));
+
+ fprintf(fp, " style=\"stroke-width: 1; stroke: black;\"/>\n");
+
+ fprintf(fp," <!-- print Y-axis title -->\n");
+
+ fprintf(fp, "<text x=\"%d\" y=\"%d\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">%s</text>\n\n",
+ 0,
+ TITLE_HEIGHT + Y_AXIS_SPACER,
+ Y_TITLE_FONT_SIZE,
+ data->y_axis_title);
+
+ return (y_tick_space/y_tick_increment);
+}
+
+/* NOTE: If you add more colors to get_line_info() you must
+ * adjust MAX_COLORS to be the total number of colors supported.
+ */
+#define MAX_COLORS 32
+
+void get_line_info(int line_number, char *line_color) {
+
+ switch (line_number % MAX_COLORS) {
+ case 0:
+ strcpy(line_color, "#000000"); // black
+ break;
+ case 1:
+ strcpy(line_color, "#FF0000"); // red
+ break;
+ case 2:
+ strcpy(line_color, "#00FFFF"); // aqua
+ break;
+ case 3:
+ strcpy(line_color, "#FFE4C4"); // bisque
+ break;
+ case 4:
+ strcpy(line_color, "#0000FF"); // blue
+ break;
+ case 5:
+ strcpy(line_color, "#A52A2A"); // brown
+ break;
+ case 6:
+ strcpy(line_color, "#DEB887"); // burlywood
+ break;
+ case 7:
+ strcpy(line_color, "#5F9EA0"); // cadetblue
+ break;
+ case 8:
+ strcpy(line_color, "#7FFF00"); // cartreuse
+ break;
+ case 9:
+ strcpy(line_color, "#D2691E"); // chocolate
+ break;
+ case 10:
+ strcpy(line_color, "#FF7F50"); // coral
+ break;
+ case 11:
+ strcpy(line_color, "#6495ED"); // cornflowerblue
+ break;
+ case 12:
+ strcpy(line_color, "#DC143C"); // crimson
+ break;
+ case 13:
+ strcpy(line_color, "#008B8B"); // darkcyan
+ break;
+ case 14:
+ strcpy(line_color, "#B8860B"); // darkgoldenrod
+ break;
+ case 15:
+ strcpy(line_color, "#008000"); // green
+ break;
+ case 16:
+ strcpy(line_color, "#ADFF2F"); // greenyellow
+ break;
+ case 17:
+ strcpy(line_color, "#FF69B4"); // hotpink
+ break;
+ case 18:
+ strcpy(line_color, "#7CFC00"); // lawngreend
+ break;
+ case 19:
+ strcpy(line_color, "#20B2AA"); // lightseagreen
+ break;
+ case 20:
+ strcpy(line_color, "#87CEFA"); // lightskyblue
+ break;
+ case 21:
+ strcpy(line_color, "#778899"); // lightslategray
+ break;
+ case 22:
+ strcpy(line_color, "#32CD32"); // limegreen
+ break;
+ case 23:
+ strcpy(line_color, "#4B0082"); // indigo
+ break;
+ case 24:
+ strcpy(line_color, "#00FF00"); // lime
+ break;
+ case 25:
+ strcpy(line_color, "#FAF0E6"); // linen
+ break;
+ case 26:
+ strcpy(line_color, "#8A2BE2"); // blueviolet
+ break;
+ case 27:
+ strcpy(line_color, "#FF00FF"); // magenta
+ break;
+ case 28:
+ strcpy(line_color, "#800000"); // maroon
+ break;
+ case 29:
+ strcpy(line_color, "#7B68EE"); // mediumslateblue
+ break;
+ case 30:
+ strcpy(line_color, "#48D1CC"); // mediumturquoise
+ break;
+ case 31:
+ strcpy(line_color, "#FFFFFF"); // black
+ break;
+ default:
+ strcpy(line_color, "black");
+ }
+}
+
+void generate_lines(FILE *fp,
+ float x_unit_space, float y_unit_space,
+ struct data_file_info_st *data) {
+
+ /* This function draws the line graph */
+
+ int i, line_number;
+ char line_color[LINE_INFO_LENGTH];
+ char line_stroke_width[LINE_INFO_LENGTH];
+
+ /* Set the line_stroke_width for a line */
+ strcpy(line_stroke_width, LINE_WIDTH);
+
+ for (line_number = 0; line_number < data->number_events; line_number++) {
+ get_line_info(line_number, line_color);
+
+ fprintf(fp, "\n <g style=\"stroke-width: %s; stroke: %s; fill: none;\">\n",
+ line_stroke_width, line_color);
+
+ fprintf(fp," <!-- Graph line %d -->\n", line_number);
+
+ /* Start line, move to first point on the screen. The location on the
+ * screen is the delta axis value (axis value minus the minimum axis
+ * value) times the spacing on the screen per unit axis value.
+ */
+ fprintf(fp, " <path d=\"M %f,%f ",
+ (data->x_array[0] - data->min_x_value) * x_unit_space
+ + (float)Y_AXIS_WIDTH,
+ (float)(GRAPH_HEIGHT + TITLE_HEIGHT)
+ - (float)((data->y_array[0][line_number] - data->min_y_value)
+ * y_unit_space));
+
+ for(i = 1; i < data->number_bins; i++) {
+ fprintf(fp, "L %f,%f ",
+ (data->x_array[i] - data->min_x_value) * x_unit_space
+ + (float)Y_AXIS_WIDTH,
+ (float)(GRAPH_HEIGHT + TITLE_HEIGHT)
+ - ((float)(data->y_array[i][line_number] - data->min_y_value)
+ * y_unit_space));
+ }
+ fprintf(fp, "\"/>\n </g>\n");
+ }
+}
+
+void generate_bars(FILE *fp,
+ float x_unit_space, float y_unit_space,
+ struct data_file_info_st *data) {
+
+
+ /* This function draws the bar graph */
+ int i, line_number;
+ char line_color[LINE_INFO_LENGTH];
+ char line_stroke_width[LINE_INFO_LENGTH];
+ float x_pos, y_start, y_pos, y_end;
+ long y_sum;
+
+ fprintf(fp," <!-- Graph bars -->\n");
+
+ /* Set the line_stroke_width to make it a bar */
+ strcpy(line_stroke_width, BAR_WIDTH);
+
+ for(i = 1; i < data->number_bins; i++) {
+
+ x_pos = (data->x_array[i] - data->min_x_value) * x_unit_space
+ + (float)Y_AXIS_WIDTH;
+
+ y_start = (float)(GRAPH_HEIGHT + TITLE_HEIGHT);
+ y_pos = y_start;
+ y_sum = 0;
+
+ for (line_number = 0; line_number < data->number_events; line_number++) {
+ /* Note, min_y_value was set to zero to get the relative bar
+ * heights correct.
+ */
+ get_line_info(line_number, line_color);
+ y_sum += (float)data->y_array[i][line_number];
+ y_end = y_start - y_sum * y_unit_space;
+
+ fprintf(fp, "<svg>\n");
+ fprintf(fp, " <line x%d=\"%f\" y%d=\"%f\" x%d=\"%f\" y%d=\"%f\"\n",
+ 1, x_pos, 1, y_pos,
+ 2, x_pos, 2, y_end);
+
+ fprintf(fp, " style=\"stroke-width: %s; stroke: %s;\"/>\n",
+ line_stroke_width, line_color);
+ fprintf(fp, "</svg>\n\n");
+
+ y_pos = y_end;
+ }
+ }
+}
+
+void generate_legend_title(FILE *fp, struct data_file_info_st *data) {
+ int i;
+ char line_color[LINE_INFO_LENGTH];
+ char line_stroke_width[LINE_INFO_LENGTH];
+
+ strcpy(line_stroke_width, LINE_WIDTH);
+
+ fprintf(fp," <!-- print graph title -->\n");
+
+ fprintf(fp, "<text x=\"%f\" y=\"%d\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">%s</text>\n\n",
+ (float)(Y_AXIS_WIDTH + data->graph_width/2
+ - (strlen(data->graph_title) * TITLE_CHAR_WIDTH)/2),
+ TITLE_HEIGHT + TITLE_SPACER,
+ TITLE_FONT_SIZE, data->graph_title);
+
+
+ fprintf(fp," <!-- print bin size -->\n");
+ fprintf(fp, "<text x=\"%d\" y=\"%d\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">X-axis bin in size %f</text>\n",
+ 20,
+ BOX_HEIGHT + LEGEND_SPACER,
+ LEGEND_FONT_SIZE, data->x_bin_size);
+
+ fprintf(fp," <!-- print graph legends -->\n");
+
+ for( i = 0; i < data->number_events; i++) {
+
+ get_line_info(i, line_color);
+
+ fprintf(fp, " <line x%d=\"%d\" y%d=\"%d\" x%d=\"%d\" y%d=\"%d\"\n",
+ 1, 0,
+ 1, BOX_HEIGHT + BIN_SIZE_SPACER + 2*LEGEND_SPACER + i*LEGEND_HEIGHT,
+ 2, Y_AXIS_WIDTH,
+ 2, BOX_HEIGHT + BIN_SIZE_SPACER + 2*LEGEND_SPACER
+ + i*LEGEND_HEIGHT);
+
+ fprintf(fp, " style=\"stroke-width: %s; stroke: %s;\"/>\n",
+ line_stroke_width, line_color);
+
+ fprintf(fp, "<text x=\"%f\" y=\"%d\" style=\"font-family: sans-serif; font-size: %dpt; \n stroke: none; fill: black;\">%s</text>\n\n",
+ (float)(1.5 * Y_AXIS_WIDTH),
+ BOX_HEIGHT + BIN_SIZE_SPACER + 2*LEGEND_SPACER + i*LEGEND_HEIGHT,
+ LEGEND_FONT_SIZE, data->event_names[i]);
+ }
+}
+
+void generate_end(FILE *fp) {
+ fprintf(fp, "</svg>\n"); // end of <svg viewbox
+}
+
+void read_data_file(char *input_file_name,
+ struct data_file_info_st *data_file_info){
+
+ FILE *fp;
+ char line[INPUT_LINE_LEN];
+ char *line_p = line;
+ char *data_line_orig, *data_line;
+
+ int i, j, err, num_chars;
+ size_t line_size = INPUT_LINE_LEN, data_line_size=0;
+ long y_value_sum;
+
+ fp = fopen(input_file_name, "r");
+ if (fp == NULL) {
+ fprintf(stdout, "%s line %d: ERROR failed to open input file %s\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* Format of the data file input consists of the following strings:
+ * ts_plot_file=<plot output file string>
+ * start_time=<integer> // user specified start time
+ * end_time=<integer> // user specified end time
+ * bin_size=<float> // value of the x-axis bin width.
+ * xlabel=<label string>
+ * ylabel=<label string>
+ * title=<title string>
+ * graph_type=<integer>
+ * number events=<integer>
+ * number bins=<integer>
+ * event=<event name> // repeats for number events
+ * X[0] \t Y[0][0] \t ... \t Y[0][events-1]
+ * X[1] \t Y[1][0] \t ... \t Y[1][events-1]
+ * ....
+ * X[bins-1] \t Y[bins-1][events-1] \t ... \t Y[bins-1][events-1]
+ *
+ * If the user specified a start and end time, then the perl script will
+ * ignore all samples before the start time and after the end time. So
+ * bin 0 contains the samples from start_time to start_time + bin_size.
+ * So, when we graph the data, we need to account for the fact that the
+ * time of the first bin is 0 but the actual the start time is "start_time".
+ */
+
+ /* read final plot file name */
+ memset(data_file_info->plot_file_name, 0, OUTPUT_FILE_NAME_LEN);
+
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("ts_plot_file=", line, 13) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the output plot file name from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ line[strcspn(line, "\n")] = 0; // remove carriage return
+ strncpy(data_file_info->plot_file_name, &line[strcspn(line, "=")+1],
+ X_AXIS_TITLE_LEN-1);
+
+
+ /* read the start time */
+ /* Note, if the user didn't specify the start time it will be 0 */
+ line_p = line; /* reset pointer */
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("start_time=", line, 11) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the start time from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read number at position following the equals sign */
+ data_file_info->start_time = strtod(&line[11], &line_p);
+
+
+ /* read the end_time */
+ /* Note, if the user didn't specify the end time it will be -1 */
+ line_p = line; /* reset pointer */
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("end_time=", line, 9) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the end time from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read number at position following the equals sign */
+ data_file_info->end_time = strtod(&line[9], &line_p);
+
+
+ /* read the bin_size */
+ line_p = line; /* reset pointer */
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("bin_size=", line, 9) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the bin_size from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read number at position following the equals sign */
+ data_file_info->x_bin_size = strtod(&line[9], &line_p);
+
+
+ /* read xlabel */
+ line_p = line; /* reset pointer */
+ memset(data_file_info->x_axis_title, 0, X_AXIS_TITLE_LEN);
+
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("xlabel=", line_p, 7) != 0) ||(num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the X label from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ line[strcspn(line, "\n")] = 0; // remove carriage return
+ strncpy(data_file_info->x_axis_title, &line[strcspn(line, "=")+1],
+ X_AXIS_TITLE_LEN-1);
+
+
+ /* read ylabel */
+ memset(data_file_info->y_axis_title, 0, Y_AXIS_TITLE_LEN);
+
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("ylabel=", line, 7) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the Y label from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ line[strcspn(line, "\n")] = 0; // remove carriage return
+ strncpy(data_file_info->y_axis_title, &line[strcspn(line, "=")+1],
+ Y_AXIS_TITLE_LEN-1);
+
+
+ /* read title */
+ memset(data_file_info->graph_title, 0, X_AXIS_TITLE_LEN);
+
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("title=", line, 6) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the graph title from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ line[strcspn(line, "\n")] = 0; // remove carriage return
+ strncpy(data_file_info->graph_title, &line[strcspn(line, "=")+1],
+ X_AXIS_TITLE_LEN-1);
+
+
+ /* read graph type */
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("graph_type=", line, 10) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the graph type entry from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read number at position following the equals sign */
+ err = sscanf(&line[strcspn(line, "=")+1], "%d",
+ &data_file_info->graph_type);
+
+ if (err != 1) {
+ fprintf(stdout, "%s line %d: ERROR reading the number events from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+
+ /* read number of events */
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("number events=", line, 14) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the number events entry from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read number at position following the equals sign */
+ err = sscanf(&line[strcspn(line, "=")+1], "%d",
+ &data_file_info->number_events);
+
+ if (err != 1) {
+ fprintf(stdout, "%s line %d: ERROR reading the number events from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+
+ /* read number of bins */
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("number bins=", line, 11) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the number bins entry from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read number at position following the equals sign */
+ err = sscanf(&line[strcspn(line, "=")+1], "%d",
+ &data_file_info->number_bins);
+
+ if (err != 1) {
+ fprintf(stdout, "%s line %d: ERROR reading the number events from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+
+ /* read event name */
+ data_file_info->event_names
+ = malloc(data_file_info->number_events*sizeof(char*));
+
+ if (data_file_info->event_names == NULL) {
+ fprintf(stdout, "%s line %d: ERROR allocating array for event names.\n",
+ __FILE__,__LINE__);
+ exit(-1);
+ }
+
+ for (i = 0; i< data_file_info->number_events; i++) {
+
+ data_file_info->event_names[i]
+ = malloc(LEGEND_TITLE_LEN + 1 * sizeof(char));
+
+
+ memset(data_file_info->event_names[i], 0, LEGEND_TITLE_LEN);
+
+ if (data_file_info->event_names == NULL) {
+ fprintf(stdout, "%s line %d: ERROR allocating array %d indexof event name array.\n",
+ __FILE__,__LINE__, i);
+ exit(-1);
+ }
+
+ num_chars = getline(&line_p, &line_size, fp);
+ if ((strncmp("event=", line, 6) != 0) || (num_chars <= 0)) {
+ fprintf(stdout, "%s line %d: ERROR reading the %d event name from file '%s'.\n",
+ __FILE__,__LINE__, i, input_file_name);
+ exit(-1);
+ }
+
+ line[strcspn(line, "\n")] = 0; // remove carriage return
+ strncpy(data_file_info->event_names[i], &line[strcspn(line, "=")+1],
+ LEGEND_TITLE_LEN-1);
+ }
+
+ /* malloc arrays to hold the data */
+ data_file_info->x_array
+ = malloc(data_file_info->number_bins*sizeof(double));
+
+ if (data_file_info->x_array == NULL) {
+ fprintf(stdout, "%s line %d: ERROR allocating storage space for X values.\n",
+ __FILE__,__LINE__);
+ exit(-1);
+ }
+
+ data_file_info->y_array = malloc(data_file_info->number_bins*sizeof(long*));
+
+ if (data_file_info->y_array == NULL) {
+ fprintf(stdout, "%s line %d: ERROR allocating storage space for Y values.\n",
+ __FILE__,__LINE__);
+ exit(-1);
+ }
+
+ for (i = 0; i< data_file_info->number_bins; i++) {
+ /* allocate each of the y arrays */
+ data_file_info->y_array[i] = malloc(data_file_info->number_events*sizeof(long int));
+
+ if (data_file_info->y_array == NULL) {
+ fprintf(stdout, "%s line %d: ERROR allocating storage space for Y values.\n",
+ __FILE__,__LINE__);
+ exit(-1);
+ }
+ }
+
+ /* Initialize the min and max for the X and Y values. */
+ data_file_info->max_x_value = 0.0;
+ data_file_info->max_y_value = 0;
+ data_file_info->min_x_value = DBL_MAX; // from float.h
+ data_file_info->min_y_value = LONG_MAX; // limits.h
+
+ y_value_sum = 0;
+
+ /* Need to allocate an input line that will be big enough for an input line of data.
+ * Estimate is the number of Y values plus one for the X value times the assumed
+ * max characters in the number (which includes spaces between values)
+ */
+ data_line_size = EST_DATA_VALUE_SIZE * (data_file_info->number_events + 1);
+ data_line = malloc(data_line_size * sizeof(char));
+
+ if (data_line == NULL) {
+ fprintf(stdout, "%s line %d: ERROR allocating input data line.\n",
+ __FILE__,__LINE__);
+ exit(-1);
+ }
+
+ data_line_orig = data_line;
+ line_p = data_line;
+
+ /* Read X and Y data from the input file */
+ for (i = 0; i< data_file_info->number_bins; i++) {
+
+ /* read line of data */
+ num_chars = getline(&data_line, &data_line_size, fp);
+
+ if (num_chars <= 0) {
+ fprintf(stdout, "%s line %d: ERROR reading the graph data from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read X data */
+ data_file_info->x_array[i] = strtod(data_line, &line_p);
+ data_line = line_p; /* move pointer past value just read */
+
+ if (data_file_info->x_array[i] > data_file_info->max_x_value)
+ data_file_info->max_x_value = data_file_info->x_array[i];
+
+ if (data_file_info->x_array[i] < data_file_info->min_x_value)
+ data_file_info->min_x_value = data_file_info->x_array[i];
+
+ if (line_p == NULL) {
+ fprintf(stdout, "%s line %d: ERROR reading X data from file '%s'.\n",
+ __FILE__,__LINE__, input_file_name);
+ exit(-1);
+ }
+
+ /* read Y data */
+ /* If doing a bar graph, we need the minimum y data value and
+ * the max of the sum of the y data values for a given bin. This
+ * is because we will graph the counts for each event on top of
+ * each other.
+ */
+ for (j = 0; j< data_file_info->number_events; j++) {
+
+ data_file_info->y_array[i][j] = strtol(data_line, &line_p, 10);
+
+ if (line_p == NULL) {
+ fprintf(stdout, "%s line %d: ERROR reading Y data set %d from file '%s'.\n",
+ __FILE__,__LINE__, j, input_file_name);
+ exit(-1);
+ }
+
+ data_line = line_p; /* move pointer past value just read */
+
+ if (data_file_info->graph_type == LINE_GRAPH) {
+ if (data_file_info->y_array[i][j] > data_file_info->max_y_value)
+ data_file_info->max_y_value = data_file_info->y_array[i][j];
+
+ if (data_file_info->y_array[i][j] < data_file_info->min_y_value)
+ data_file_info->min_y_value = data_file_info->y_array[i][j];
+
+ } else {
+ /* If doing a bar graph, need Y max across the data sets. */
+ y_value_sum += data_file_info->y_array[i][j];
+ }
+ }
+
+ if (data_file_info->graph_type == BAR_GRAPH) {
+ if (y_value_sum > data_file_info->max_y_value)
+ data_file_info->max_y_value = y_value_sum;
+
+#if DEBUG
+ printf("Bin %d, y_value_sum = %ld, max_y = %ld, min_y = %ld\n",
+ i, y_value_sum,
+ data_file_info->max_y_value,
+ data_file_info->min_y_value);
+#endif
+
+ y_value_sum = 0; /* zero for next iteration */
+ }
+
+ /* reset line pointer to the beginning of buffer */
+ data_line = data_line_orig;
+ }
+
+ if (data_file_info->graph_type == BAR_GRAPH)
+ /* Have to do the bar graph from y = 0 to y = max of the
+ * sum across data sets to make the relative height of the
+ * bars accurate.
+ */
+ data_file_info->min_y_value = 0;
+
+#if DEBUG
+ printf("start time = %f\n", data_file_info->start_time);
+ printf("end time = %f\n", data_file_info->end_time);
+ printf("graph title = %s\n", data_file_info->graph_title);
+ printf("x axis title = %s\n", data_file_info->x_axis_title);
+ printf("y axis title = %s\n", data_file_info->y_axis_title);
+ printf("number events = %d\n", data_file_info->number_events);
+ printf("number bins = %d\n", data_file_info->number_bins);
+
+ for (i = 0; i< data_file_info->number_events; i++) {
+ printf("event = %s\n", data_file_info->event_names[i]);
+ }
+
+ for (i = 0; i< data_file_info->number_bins; i++) {
+ printf("X[%d] = %f ", i, data_file_info->x_array[i]);
+ for (j = 0; j< data_file_info->number_events; j++) {
+ printf("Y[%d][%d] = %ld ", i, j, data_file_info->y_array[i][j]);
+ }
+ printf("\n\n");
+ }
+ printf("x axis min = %f\n", data_file_info->min_x_value);
+ printf("x axis max = %f\n", data_file_info->max_x_value);
+ printf("y axis min = %ld\n", data_file_info->min_y_value);
+ printf("y axis max = %ld\n", data_file_info->max_y_value);
+ fflush(stdout);
+#endif
+ }
+
+int main()
+{
+ FILE *fp;
+ float x_unit_space, y_unit_space;
+ struct data_file_info_st data_file_info;
+
+ read_data_file(INPUTFILE, &data_file_info);
+
+ fp = fopen(data_file_info.plot_file_name, "w");
+
+ if (fp == NULL) {
+ fprintf(stdout, "Failed to open output file %s\n",
+ data_file_info.plot_file_name);
+ exit(-1);
+ }
+
+ generate_header(fp, &data_file_info);
+
+ x_unit_space = draw_x_axis(fp, &data_file_info);
+ y_unit_space = draw_y_axis(fp, &data_file_info);
+
+ generate_legend_title(fp, &data_file_info);
+
+ if (data_file_info.graph_type == LINE_GRAPH)
+ generate_lines(fp, x_unit_space, y_unit_space,
+ &data_file_info);
+
+ else
+ generate_bars(fp, x_unit_space, y_unit_space,
+ &data_file_info);
+
+ generate_end(fp);
+ fflush(stdout);
+ fflush(fp);
+ fclose(fp);
+ exit(0);
+}
diff --git a/utils/process_time_stamps.prl b/utils/process_time_stamps.prl
new file mode 100755
index 0000000..890a129
--- /dev/null
+++ b/utils/process_time_stamps.prl
@@ -0,0 +1,829 @@
+#!/usr/bin/perl
+#
+# process_time_stamps.prl
+#
+# This script reads an OProfile xml output file and generates a
+# data file for use by the SVG plot program.
+#
+# The OProfile xml file is typically created by running operf and opreport
+# with the -T option. The -T tells operf and opreport to collect and process
+# the time stamp data.
+#
+# example run:
+#
+# operf -T -e CPU_CLK_UNHALTED:100000 <your workload>
+# opreport -T > opreport-out
+#
+# Copyright 2016 OProfile authors
+# Read the file COPYING
+#
+# Created on: Sept. 25, 2015
+# Author Carl Love ***@us.ibm.com
+# (C) Copyright IBM Corp. 2015
+#
+# Updated on: March. 15, 2016
+
+use strict;
+use Getopt::Long qw(GetOptions);
+
+###########################
+#main
+my $DATA_SEPARATOR = "\t ";
+
+# Default name for the generated data file
+# NOTE: if you change this you must also change #define INPUTFILE
+# in generate_svg.c
+my $DEFAULT_OUTPUT_DATA_FILE = "__workload_tm_data.dat__";
+
+# Default name for ts plot file
+my $DEFAULT_TS_PLOT_FILE = "workload_plot.html";
+
+
+# Command line options
+#
+# -ts_plot_title Title to put on the graph
+#
+# -debug Enable debug prints
+#
+# -start_time Beginning of time to display, default beginning of
+# data.
+#
+# -end_time End of time to display, default end of data.
+#
+# -output_data_file Output file name to write the data for plotting
+#
+# -ts_plot_file Output file name for the plot
+#
+# -line_graph Create a line graph
+#
+# -bar_graph Create a bar graph
+#
+# -max_symbols 0 - combine all symbol time stamps in a single data set.
+# if greater then zero, display the top N symbols where
+# N is the argument of symbol_threshold
+
+# Process the command line arguments
+#
+my $debug = 0; # set to 1 to enable debug prints
+my $ts_plot_title = "";
+my $usr_start_time = 0;
+my $usr_end_time = -1;
+my $line_graph = 0;
+my $bar_graph = 0;
+my $max_bins = 200;
+my $output_data_file = $DEFAULT_OUTPUT_DATA_FILE;
+my $ts_plot_file = $DEFAULT_TS_PLOT_FILE;
+my $print_symbol_threshold = 0;
+my $FH_DATA_FILE;
+
+GetOptions (
+ 'debug!' => \$debug,
+ 'ts_plot_title=s' => \$ts_plot_title,
+ 'start_time=s' => \$usr_start_time,
+ 'end_time=s' => \$usr_end_time,
+ 'line_graph!' => \$line_graph,
+ 'bar_graph!' => \$bar_graph,
+ 'max_bins=s' => \$max_bins,
+ 'max_symbols=s' => \$print_symbol_threshold,
+ 'output_data_file=s' => \$output_data_file,
+ 'ts_plot_file=s' => \$ts_plot_file,
+ ) or die "Unknown command line option\n";
+
+
+if ($debug) {
+ printf " process_time_stamps.prl, Command line argument settings are: \n";
+ printf " debug = $debug \n";
+ printf " ts_plot_title = $ts_plot_title \n";
+ printf " start_time = $usr_start_time \n";
+ printf " end_time = $usr_end_time \n";
+ printf " line_graph = $line_graph \n";
+ printf " bar_graph = $bar_graph \n";
+ printf " max_symbols = $print_symbol_threshold \n";
+ printf " max_bins = $max_bins \n";
+ printf " ts_plot_file = $ts_plot_file \n";
+ printf " output_data_file = $output_data_file \n";
+}
+
+## Check command line argument
+if ($line_graph && $bar_graph) {
+ die "process_time_stamps.prl: Error, cannot specify both line and bar graph styles.\n";
+}
+if (!$line_graph && !$bar_graph) {
+ # must specify line_graph or bar_graph
+ $line_graph=1;
+}
+
+if ($max_bins < 0) {
+ die "The number of bins for the bar graph style must be positive.\n"
+}
+
+my $num_symbols = 0;
+my $found_tm = 0;
+my $found_symbol = 0;
+my $min_tm = -1;
+my $max_tm = -1;
+
+my ($i, $j, $k, $n, $print_rank, $bin_width, $num_events);
+my ($end_time, $max_bin_count, $sum, $x_coordinate, $bin_time, $value);
+my ($all_symbols, $print_symbol, $name, $id_name, $rank, $delta);
+my ($symb_min_tm, $symb_max_tm, $top_index, $top_count, $slice_num);
+my ($offset, $start_time, $end_time);
+my (@sym_name, @sym_rank, @bin_count, @tm_array, @fields, @count, @fields);
+my (@symbol_max_tm, @symbol_min_tm, @subfields);
+
+my (@classes, $found_classes, $ev_num, $ev_number, $class_name, @class_mapping);
+my ($max_events, @event_name, $name, $element, $adj_num_events);
+### Global data
+my $included_count = 0;
+my $excluded_count = 0;
+
+##############################
+### get data
+&read_xml_file($num_symbols, $min_tm, $max_tm, @count, @sym_name, @sym_rank, @tm_array, @symbol_min_tm, @symbol_max_tm);
+
+# Size of class_mapping is the number of events in the data set.
+# When the data set consists of a single event, there is no event
+# to class mapping. This results in the size of class_mapping
+# being set to-1.
+if ($#class_mapping == -1) {
+ $max_events = 1;
+} else {
+ $max_events = $#class_mapping + 1;
+}
+
+## Enable debugging the parsing of the data file
+if ($debug) {
+ &debug_print_extracted_data();
+}
+
+######################################
+
+### Display symbols
+# 0 - Collapse all symbol data into a single line
+# 3 - Show time stamps for symbols counts in the top N
+
+
+### Setup to display the time range. The assumption is that the
+# user is inputting an adjusted start/end time based on a
+# previously viewed graph.
+
+if ($usr_start_time <= 0) {
+ $start_time = $min_tm;
+} else {
+ $start_time = $usr_start_time + $min_tm;
+}
+if ($debug) {
+ print "USER start time = $usr_start_time\n";
+ print "USER input stop time = $usr_end_time\n";
+ print "MAX TIME = $max_tm\n";
+}
+
+if ($usr_end_time == -1) {
+ $end_time = $max_tm;
+} elsif ($usr_end_time < ($max_tm -$min_tm)) {
+ $end_time = $usr_end_time + $min_tm;
+
+ if ($debug) {
+ printf "SET END_TIME TO UNNORMALIZED USER END TIME, $end_time\n";
+ }
+} else {
+ $end_time = $max_tm;
+}
+$bin_width = ($end_time - $start_time) / $max_bins;
+
+if ($debug) {
+ print "Display_window = 1, Initial, min_tm = $min_tm, max_tm = $max_tm\n";
+ print "Display_window = 1, start_time = $start_time, end_time = $end_time\n";
+ print "print_symbol_threshold = $print_symbol_threshold \n";
+ print "output_data_file = $output_data_file\n";
+ print "output_ts_plot_file = $ts_plot_file\n";
+ print "line_graph = $line_graph\n";
+ print "line_graph = $line_graph\n";
+ print "bar_graph = $bar_graph\n";
+ print "user start time = $usr_start_time\n";
+ print "user end time = $usr_end_time\n";
+}
+
+# Open the output data file
+if (open $FH_DATA_FILE, ">", "$output_data_file") {
+ if ($debug) {
+ printf "Success opening output file $output_data_file\n";
+ }
+} else {
+ printf "process_time_stamps.prl: ERROR cannot open file $output_data_file\n";
+ die;
+}
+
+$ev_number = 0;
+if ($line_graph == 1) {
+ &print_bin_line_plot_script_file();
+ &print_bin_data_file_for_plot();
+} elsif ($bar_graph == 1) {
+ &print_bin_hist_plot_script_file();
+ &print_bin_data_file_for_plot();
+} else {
+ print "process_time_stamps.prl: ERROR, unknown value of graph style\n";
+}
+
+if ($debug) {
+ print "Start time = ", $start_time, "\n";
+ print "bin width = ", $bin_width, "\n";
+ print "End time = ", $end_time, "\n";
+
+ &print_timestamp_range_for_symbols();
+}
+
+
+close $FH_DATA_FILE;
+
+###################### End of main
+
+
+#### subroutines #############################################
+
+sub get_class_event_number {
+ $i = 0;
+
+ while( $i <= $#class_mapping)
+ {
+ # check passed name
+ if ($_[0] eq $class_mapping[$i]) {
+ return $i;
+ }
+ $i = $i + 1;
+ }
+# In the case of a data set with a single event, there will
+# not be a class mapping. Return 0 for the event.
+ return 0;
+}
+
+sub generate_symbol_rank (@sym_rank) {
+ #initialize the rank for all symbols and events
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ for ($i = 0; $i <= $num_symbols; $i = $i + 1) {
+ $sym_rank[$n][$i] = 0;
+ }
+ }
+
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ # go through the list of symbols and assign the rank of 1 to
+ # num_symbols where the symbol with the highest count is 1,
+ # the next highest is 2,...
+ $rank = 1;
+
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ $top_index = -1;
+ $top_count = 0;
+ for ($j = 0; $j < $num_symbols; $j = $j + 1) {
+ if (($sym_rank[$n][$j] == 0) && ($top_index == -1)) {
+ $top_index = $j;
+ $top_count = $count[$n][$j];
+ } elsif (($count[$n][$j] > $top_count) && ($sym_rank[$n][$j] == 0)) {
+ $top_index = $j;
+ $top_count = $count[$n][$j];
+ }
+ }
+ $sym_rank[$n][$top_index] = $rank;
+ $rank = $rank + 1;
+ }
+ }
+
+ if ($debug) {
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ for ($j = 0; $j < $num_symbols; $j = $j + 1) {
+ print "Event $n, Symbol $sym_name[$j], at rank $sym_rank[$n][$j], count $count[$n][$j].\n";
+ }
+ }
+ }
+}
+
+sub read_xml_file ($num_symbols, $min_tm, $max_tm, @count, @sym_name, @sym_rank, @tm_array, @symbol_min_tm, @symbol_max_tm) {
+# read the input
+
+ while(<>) {
+ # look for the symbol name
+ @fields = split(' ', $_);
+
+ if ($debug) {
+ print "LINE: $_\n";
+ }
+
+ if ($fields[0] eq "<symbol") {
+ @subfields = split('>', $fields[1]);
+ # change double quot to singe quote otherwise we get confused
+ # by the double quotes around the title.
+ $name = $subfields[0];
+ $name=~ s/"/'/g;
+ $sym_name[$num_symbols] = $name;
+
+ $found_symbol = 1;
+ if ($debug) {
+ print "Found symbol number $num_symbols = $sym_name[$num_symbols] \n";
+ }
+ }
+
+ if ($fields[0] eq "</symbol>") {
+ $found_symbol = 0;
+ $num_symbols = $num_symbols + 1;
+ if ($debug) {
+ print "found </symbol>, num_symbols incremented to $num_symbols\n";
+ }
+ }
+
+ if ($fields[0] eq "<eventsetup") {
+ @subfields = split('"', $fields[1]);
+ $ev_num = $subfields[1];
+ @subfields = split('"', $fields[2]);
+ $name = $subfields[1];
+ $event_name[$ev_num] = $name;
+
+ if ($debug) {
+ print "found eventsetup ev_num = $ev_num, name = $name\n";
+ }
+ }
+
+ if ($found_classes == 1) {
+ if ($fields[0] eq "<class") { # form <class name="c0" event="0"/>
+ @subfields = split('"', $fields[1]);
+ $class_name = $subfields[1];
+ @subfields = split('"', $fields[2]);
+ $ev_num = $subfields[1];
+ $class_mapping[$ev_num] = $class_name;
+ if($debug) {
+ print "Class $class_name Event $ev_num\n";
+ }
+ $name=~ s/"/'/g;
+ }
+ }
+
+ if ((($found_tm == 1) && ($found_symbol == 1))) {
+ # the entry may be <timestamp 0xfffff where the tag and data are
+ # the same line
+ $found_tm = 0;
+ if ($debug) {
+ print "Found time stamps, number TMs, event num $ev_num, $count[$ev_num][$num_symbols] \n";
+ }
+
+ if ($fields[0] =~ /\<timestamp/) {
+ # time stamps start in field 1 in this case
+ $offset = 1;
+ } else {
+ $offset = 0;
+ }
+
+ $symb_min_tm = -1;
+ $symb_max_tm = -1;
+
+ $i = 0;
+ while ( $fields[$i+$offset] ne "</timestamp>") {
+ $value = oct($fields[$i+$offset]);
+ if ($debug) {
+ print "TM value = $value\n";
+ }
+
+ if ($min_tm == -1) {
+ $min_tm = $value;
+ } elsif ($min_tm > $value) {
+ $min_tm = $value;
+ }
+
+ if ($max_tm == -1) {
+ $max_tm = $value;
+ } elsif ($max_tm < $value) {
+ $max_tm = $value;
+ }
+
+ if ($symb_min_tm == -1) {
+ $symb_min_tm = $value;
+ } elsif ($symb_min_tm > $value) {
+ $symb_min_tm = $value;
+ }
+
+ if ($symb_max_tm == -1) {
+ $symb_max_tm = $value;
+ } elsif ($symb_max_tm < $value) {
+ $symb_max_tm = $value;
+ }
+
+ if ($debug) {
+ printf( "found tm_array[$ev_num][$num_symbols][$i] = 0x%x\n", $value);
+ }
+ $tm_array[$ev_num][$num_symbols][$i] = $value;
+ $i = $i +1;
+ }
+ $count[$ev_num][$num_symbols] = $i;
+ $symbol_min_tm[$ev_num][$num_symbols] = $symb_min_tm;
+ $symbol_max_tm[$ev_num][$num_symbols] = $symb_max_tm;
+ if ($debug) {
+ print "symbol_min_tm[$ev_num][$num_symbols] = $symbol_min_tm[$ev_num][$num_symbols] \n";
+ print "symbol_max_tm[$ev_num][$num_symbols] = $symbol_max_tm[$ev_num][$num_symbols] \n";
+ }
+ }
+
+ if ($fields[0] eq "<symboldata") {
+ # Found a symbol table entry, update symbol id in sym_name
+ # with the actual symbol name
+ @subfields = split('"', $fields[2]);
+ $name = $subfields[1];
+ $id_name = $fields[1];
+ $id_name=~ s/"/'/g; # changed " to ' when storing id
+ $id_name=~ s/id=/idref=/g;
+
+ if ($debug) {
+ print "found <symboldata name:$id_name name:$name \n";
+ print "CURRENT LINE: $_\n";
+ }
+
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ #search for id_name in $sym_name and update with actual name
+ if ($debug) {
+ print " searching:sym_name[$i] = $sym_name[$i] \n";
+ }
+
+ if ($sym_name[$i] eq $id_name) {
+ if ($debug) {
+ print "Found id_name, replace name $sym_name[$i] at index $i with $name\n";
+ }
+ $sym_name[$i] = $name;
+ if ($debug) {
+ print "update sym_name is $sym_name[$i] at index $i\n";
+ }
+ last;
+ }
+ }
+ }
+
+ if ($fields[0] =~ /\<classes\>/) { # field has substring <count
+ if ($debug) {
+ print "Found classes entry \n";
+ }
+ $found_classes = 1;
+ }
+
+ if ($fields[0] eq "<timestamp>") { # time stamps on next line
+ # single event
+ $ev_num = 0;
+ if ($debug) {
+ print "Found time stamp entry \n";
+ }
+ $found_tm = 1;
+ }
+
+ if ($fields[0] eq "<timestamp") { # time stamps on next line
+ # data consists of multiple events
+ @subfields = split('"', $fields[1]);
+ $class_name = $subfields[1];
+
+ if ($debug) {
+ print "EVENT NAME = $class_name\n";
+ print "Found time stamp entry \n";
+ }
+ $ev_num = get_class_event_number($class_name);
+ $found_tm = 1;
+ }
+ }
+}
+
+sub debug_print_extracted_data {
+ print "\n\nEXTRACTED DATA \n\n";
+
+ print " Number of events = $max_events\n";
+ print " Number of symbols found = $num_symbols\n";
+ print " Min time stamp = $min_tm\n";
+ print " Max time stamp = $max_tm\n\n";
+
+ for ($ev_num = 0; $ev_num < $max_events; $ev_num = $ev_num + 1) {
+ for ($i = 0; $i <= $num_symbols; $i = $i + 1) {
+ print "Event number $k\n";
+ print "Symbol = $sym_name[$i], count[$ev_num][$i] = $count[$ev_num][$i]\n";
+ print "symbol_min_tm = $symbol_min_tm[$ev_num][$i]\n";
+ print "symbol_max_tm = $symbol_max_tm[$ev_num][$i]\n\n";
+
+ for ($j = 0; $j < $count[$ev_num][$i]; $j = $j + 1) {
+ print "tm_array[$ev_num][$i][$j] = $tm_array[$ev_num][$i][$j] \n";
+ }
+ print "\n\n";
+ }
+ }
+ print "\n\nEND OF EXTRACTED DATA \n\n";
+}
+
+# print selected symbols with time stamps
+sub print_timestamp_range_for_symbols {
+ $ev_num = $_[0];
+
+ print "Minimum raw time ", $min_tm, "\n";
+ print "Maximum raw time ", $max_tm, "\n\n";
+
+ print "Minimum adjusted time ", $min_tm - $min_tm, "\n";
+ print "Maximum adjusted time ", $max_tm - $min_tm, "\n\n";
+
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ print "Symbol: ", $sym_name[$i], "\n";
+ print " Min time stamp = ", $symbol_min_tm[$ev_num][$i] - $min_tm, "\n";
+ print " Max time stamp = ", $symbol_max_tm[$ev_num][$i] - $min_tm, "\n";
+ printf("\n");
+ }
+}
+
+sub print_bin_data_file_for_plot {
+# count samples within the bin size, plot counts within each bin, for the specified event
+ $all_symbols = 1; # print all symbols in one line
+ $bin_width = ($end_time - $start_time) / $max_bins;
+
+ $print_symbol = 0;
+ $bin_time = $start_time;
+
+ for ($k = 0; $k < $max_bins; $k = $k + 1) {
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ $bin_count[$n][$i][$k] = 0;
+
+ if ($debug) {
+ print "range[$bin_time, $bin_time+$bin_width] \n";
+ }
+ for ($j = 0; $j < $count[$n][$i]; $j = $j + 1) {
+ $value = $tm_array[$n][$i][$j];
+ if ($debug) {
+ print "tm_array[$n][$i][$j] = $tm_array[$n][$i][$j]\n";
+ }
+ if (($value >= $bin_time) &&
+ ($value <= ($bin_time + $bin_width))) {
+ $bin_count[$n][$i][$k] = $bin_count[$n][$i][$k] + 1;
+ }
+ }
+ if ($debug) {
+ print "bin_count[$n][$i][$k] = $bin_count[$n][$i][$k]\n";
+ }
+ }
+ }
+ $bin_time = $bin_time + $bin_width;
+ }
+
+ if ($print_symbol_threshold == 0) {
+ for ($k = 0; $k < $max_bins; $k = $k + 1) {
+ $x_coordinate = $k * $bin_width;
+ print $FH_DATA_FILE $x_coordinate, $DATA_SEPARATOR;
+
+ # print the data for each event
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ $sum = 0;
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ $sum = $sum + $bin_count[$n][$i][$k];
+ }
+ if ($debug) {
+ print " counts in bin[$k][$n] = $sum\n";
+ }
+ print $FH_DATA_FILE "$sum ", $DATA_SEPARATOR;
+ }
+
+ print $FH_DATA_FILE "\n";
+ }
+
+ } elsif ($print_symbol_threshold > 0) {
+
+ if($debug) {
+ print "print_bin_data_file_for_plot: print_symbol_threshold is $print_symbol_threshold\n";
+ }
+
+ for ($k = 0; $k < $max_bins; $k = $k + 1) {
+ $x_coordinate = $k * $bin_width;
+ print $FH_DATA_FILE $x_coordinate, $DATA_SEPARATOR;
+
+ # print the data for each event
+ for ($ev_num = 0; $ev_num < $max_events; $ev_num = $ev_num + 1) {
+ # print the N symbols
+ for ($n = 0; $n < $print_symbol_threshold; $n = $n + 1) {
+ $print_rank = $n + 1; # column 1 is X data
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ if ($sym_rank[$ev_num][$i] == $print_rank) {
+ if ($debug) {
+ print "Print data for event $event_name[$ev_num], $sym_name[$i] print_rank = $print_rank\n";
+ }
+ print $FH_DATA_FILE $bin_count[$ev_num][$i][$k], $DATA_SEPARATOR;
+ }
+ }
+ }
+
+ # Sum counts for all symbols whose rank is greater
+ # then top N symbols and print them in the last
+ # column for other
+ $sum = 0;
+ for ($n = $print_symbol_threshold; $n < $num_symbols; $n = $n + 1) {
+ $print_rank = $n + 1;
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ if ($sym_rank[$ev_num][$i] >= $print_symbol_threshold) {
+ $sum = $sum + $bin_count[$ev_num][$i][$k];
+ }
+ }
+ }
+ print $FH_DATA_FILE "$sum", $DATA_SEPARATOR;;
+ }
+ print $FH_DATA_FILE "\n ";
+ }
+
+ } else {
+ print "process_time_stamps.prl: ERROR, print_symbol_threshold value not valid in print_bin_data_file_for_plot\n";
+ }
+}
+
+sub print_base_plot_script {
+# This writes the output file name, x and y label information, bin width etc.
+
+ # Write the following at the head of the output file. generate_svg.c
+ # will read them from the file.
+
+ print $FH_DATA_FILE "ts_plot_file=", $ts_plot_file, "\n";
+ print $FH_DATA_FILE "start_time=", $usr_start_time, "\n";
+ print $FH_DATA_FILE "end_time=", $usr_end_time, "\n";
+ print $FH_DATA_FILE "bin_size=", $bin_width, "\n";
+
+ if ($line_graph == 1) {
+ print $FH_DATA_FILE "xlabel=Time in ns, since plot start time. \n";
+ print $FH_DATA_FILE "ylabel=Counts in bin.\n";
+ } elsif ($bar_graph == 1) {
+ print $FH_DATA_FILE "xlabel=Time in ns.\n";
+ print $FH_DATA_FILE "ylabel=Counts in bin.\n";
+
+ } else {
+ die "process_time_stamps.prl: ERROR: neither line_graph or bar_graph was set\n";
+ }
+}
+
+sub print_bin_line_plot_script_file() {
+ $bin_width = ($end_time - $start_time) / $max_bins;
+ if ($debug) {
+ print "print_bin_line_plot_script_file(), bin_width = $bin_width\n";
+ }
+
+ &print_base_plot_script();
+
+ if ($ts_plot_title eq "") {
+ print $FH_DATA_FILE "title=Line-Plot\n";
+ } else {
+ print $FH_DATA_FILE "title=$ts_plot_title\n";
+ }
+
+ print $FH_DATA_FILE "graph_type=0\n"; #line graph
+
+ if (($print_symbol_threshold == 0) && ($max_events == 1)) {
+ # Note if there is only one event, the XML file does not contain the
+ # event name thus event_name[] is empty.
+
+ print $FH_DATA_FILE "number events=$max_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+ print $FH_DATA_FILE "event=$event_name[0]\n";
+
+ } elsif (($print_symbol_threshold == 0) && ($max_events > 1)){
+ print $FH_DATA_FILE "number events=$max_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ $ev_num = $n + 1;
+
+ print $FH_DATA_FILE "event=$event_name[$n]\n";
+ }
+
+ } elsif (($print_symbol_threshold > 0) && ($max_events == 1)) {
+ # Note if there is only one event, the XML file does not contain the
+ # event name thus event_name[] is empty.
+
+ if($debug) {
+ print "print_bin_line_plot_script_file: print_symbol_threshold is $print_symbol_threshold, max_events = 1\n";
+ }
+
+ $ev_num = 0; # only have one event
+ &generate_symbol_rank(@sym_rank);
+
+ print $FH_DATA_FILE "number events=$max_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+
+ for ($n = 0; $n < $print_symbol_threshold; $n = $n + 1) {
+ # Last column is sum of counts for all other symbols
+ $print_rank = $n + 1;
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ if ($sym_rank[$ev_num][$i] == $print_rank) {
+ print $FH_DATA_FILE "event=$sym_name[$i]\n";
+ }
+ }
+ }
+
+ } elsif (($print_symbol_threshold > 0) && ($max_events > 1)) {
+ &generate_symbol_rank(@sym_rank);
+
+ if($debug) {
+ print "print_bin_line_plot_script_file: print_symbol_threshold is $print_symbol_threshold, max_events = $max_events\n";
+ }
+
+ $num_events = $print_symbol_threshold + 1;
+
+ # Each event has print_symbol_threshold symbols plus other
+ # event_names.
+ $adj_num_events = $max_events * ($print_symbol_threshold + 1);
+
+ print $FH_DATA_FILE "number events=$adj_num_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+
+ for ($ev_num = 0; $ev_num < $max_events; $ev_num = $ev_num + 1) {
+ $print_rank = 1;
+ for ($n = 0; $n < $print_symbol_threshold; $n = $n + 1) {
+ # Last column is sum of counts for all other symbols
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ if ($sym_rank[$ev_num][$i] == $print_rank) {
+ print $FH_DATA_FILE "event=$event_name[$ev_num]-$sym_name[$i]\n";
+ }
+ }
+ $print_rank = $print_rank + 1;
+ }
+
+ # column 1 is X data, last column other y data
+ print $FH_DATA_FILE "event='$event_name[$ev_num]-Other'\n";
+ }
+
+ } else {
+ print "process_time_stamps.prl: ERROR, unsupported value of print_symbol_threshold = $print_symbol_threshold in print_bin_line_plot_script_file\n";
+ }
+}
+
+sub print_bin_hist_plot_script_file {
+# script for making a histogram plot
+ $bin_width = ($end_time - $start_time) / $max_bins;
+
+ &print_base_plot_script();
+
+ if ($ts_plot_title eq "") {
+ print $FH_DATA_FILE "title=Histogram-Plot\n";
+ } else {
+ print $FH_DATA_FILE "title=$ts_plot_title\n";
+ }
+ print $FH_DATA_FILE "graph_type=1\n"; #bar graph
+
+ if (($print_symbol_threshold == 0) && ($max_events == 1)) {
+ print $FH_DATA_FILE "number events=$max_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+ print $FH_DATA_FILE "event=event\n";
+
+ } elsif (($print_symbol_threshold == 0) && ($max_events > 1)) {
+ print $FH_DATA_FILE "number events=$max_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+
+ for ($n = 0; $n < $max_events; $n = $n + 1) {
+ $ev_num = $n + 1;
+ print $FH_DATA_FILE "event='$event_name[$n]'\n";
+ }
+
+ } elsif (($print_symbol_threshold > 0) && ($max_events == 1)) {
+ &generate_symbol_rank(@sym_rank);
+
+ if($debug) {
+ print "print_bin_hist_plot_script_file: print_symbol_threshold is $print_symbol_threshold; max_events = 1\n";
+ }
+
+ print $FH_DATA_FILE "number events=$max_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+
+ # data routine
+ $ev_num = 0; # only have 1 event
+
+ for ($n = 0; $n < $print_symbol_threshold; $n = $n + 1) {
+ # Last column is sum of counts for all other symbols
+ $print_rank = $n + 1; # column 0 is X data
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ if ($sym_rank[$ev_num][$i] == $print_rank) {
+ print $FH_DATA_FILE "event='$sym_name[$i]'\n";
+ }
+ }
+ }
+
+ } elsif (($print_symbol_threshold > 0) && ($max_events > 1)) {
+ if($debug) {
+ print "print_bin_hist_plot_script_file: print_symbol_threshold is $print_symbol_threshold; max_events = $max_events\n"
+ }
+
+ &generate_symbol_rank(@sym_rank);
+
+ # Each event has print_symbol_threshold symbols plus other
+ # event_names.
+ $adj_num_events = $max_events * ($print_symbol_threshold + 1);
+
+ print $FH_DATA_FILE "number events=$adj_num_events\n";
+ print $FH_DATA_FILE "number bins=$max_bins\n";
+
+ for ($ev_num = 0; $ev_num < $max_events; $ev_num = $ev_num + 1) {
+ $print_rank = 1; # column 0 is X data
+ for ($n = 0; $n < $print_symbol_threshold; $n = $n + 1) {
+ # Last column is sum of counts for all other symbols
+ for ($i = 0; $i < $num_symbols; $i = $i + 1) {
+ if ($sym_rank[$ev_num][$i] == $print_rank) {
+ print $FH_DATA_FILE "event='$event_name[$ev_num]-$sym_name[$i]'\n"
+ }
+ }
+ $print_rank = $print_rank + 1;
+ }
+
+ print $FH_DATA_FILE "event='$event_name[$ev_num]-Other'\n";
+ }
+
+ } else {
+ print "process_time_stamps.prl: ERROR, unsupported value of print_symbol_threshold = $print_symbol_threshold in print_bin_hist_plot_script_file\n";
+ }
+}
--
1.8.3.1
Loading...