[PATCH 2/2] version3, Add time stamp collection to operf and opreport,

"Carl E. Love" <[email protected]>
Newsgroups gmane.linux.oprofile
Message-ID <[email protected]>
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 <[email protected]>
---
 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   [email protected]
+ *  (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   [email protected]
+#  (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




------------------------------------------------------------------------------
Transform Data into Opportunity.
Accelerate data analysis in your applications with
Intel Data Analytics Acceleration Library.
Click to learn more.
http://pubads.g.doubleclick.net/gampad/clk?id=278785351&iu=/4140
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.