[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