From 2b53c2335f57bf0d9b5deab7d919a975fb137cb4 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 15 Mar 2024 21:26:03 +0100 Subject: [PATCH 1/3] Support printing stats table in json format --- scripts/osg_stats.py | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index 3cdd0febae..d898accb10 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -7,6 +7,7 @@ set of keys over given range of frames. import click import collections +import json import matplotlib.pyplot import numpy import operator @@ -43,6 +44,12 @@ import termtables 'between Physics Actors and physics_time_taken. Format: --plot .') @click.option('--stats', type=str, multiple=True, help='Print table with stats for a given metric containing min, max, mean, median etc.') +@click.option('--stats_sum', is_flag=True, + help='Add a row to stats table for a sum per frame of all given stats metrics.') +@click.option('--stats_sort_by', type=str, default=None, multiple=True, + help='Sort stats table by given fields (source, key, sum, min, max etc).') +@click.option('--stats_table_format', type=click.Choice(['markdown', 'json']), default='markdown', + help='Print table with stats in given format.') @click.option('--precision', type=int, help='Format floating point numbers with given precision') @click.option('--timeseries_sum', is_flag=True, @@ -51,8 +58,6 @@ import termtables help='Add a graph to timeseries for a sum per frame of all given commulative timeseries.') @click.option('--timeseries_delta_sum', is_flag=True, help='Add a graph to timeseries for a sum per frame of all given timeseries delta.') -@click.option('--stats_sum', is_flag=True, - help='Add a row to stats table for a sum per frame of all given stats metrics.') @click.option('--begin_frame', type=int, default=0, help='Start processing from this frame.') @click.option('--end_frame', type=int, default=sys.maxsize, @@ -67,14 +72,12 @@ import termtables help='Threshold for hist_over.') @click.option('--show_common_path_prefix', is_flag=True, help='Show common path prefix when applied to multiple files.') -@click.option('--stats_sort_by', type=str, default=None, multiple=True, - help='Sort stats table by given fields (source, key, sum, min, max etc).') @click.argument('path', type=click.Path(), nargs=-1) def main(print_keys, regexp_match, timeseries, hist, hist_ratio, stdev_hist, plot, stats, precision, timeseries_sum, stats_sum, begin_frame, end_frame, path, commulative_timeseries, commulative_timeseries_sum, frame_number_name, hist_threshold, threshold_name, threshold_value, show_common_path_prefix, stats_sort_by, - timeseries_delta, timeseries_delta_sum): + timeseries_delta, timeseries_delta_sum, stats_table_format): sources = {v: list(read_data(v)) for v in path} if path else {'stdin': list(read_data(None))} if not show_common_path_prefix and len(sources) > 1: longest_common_prefix = os.path.commonprefix(list(sources.keys())) @@ -109,7 +112,8 @@ def main(print_keys, regexp_match, timeseries, hist, hist_ratio, stdev_hist, plo if plot: draw_plots(sources=frames, plots=plot) if stats: - print_stats(sources=frames, keys=matching_keys(stats), stats_sum=stats_sum, precision=precision, sort_by=stats_sort_by) + print_stats(sources=frames, keys=matching_keys(stats), stats_sum=stats_sum, precision=precision, + sort_by=stats_sort_by, table_format=stats_table_format) if hist_threshold: draw_hist_threshold(sources=frames, keys=matching_keys(hist_threshold), begin_frame=begin_frame, threshold_name=threshold_name, threshold_value=threshold_value) @@ -291,7 +295,7 @@ def draw_plots(sources, plots): fig.canvas.manager.set_window_title('plots') -def print_stats(sources, keys, stats_sum, precision, sort_by): +def print_stats(sources, keys, stats_sum, precision, sort_by, table_format): stats = list() for name, frames in sources.items(): for key in keys: @@ -301,11 +305,22 @@ def print_stats(sources, keys, stats_sum, precision, sort_by): metrics = list(stats[0].keys()) if sort_by: stats.sort(key=operator.itemgetter(*sort_by)) - termtables.print( - [list(v.values()) for v in stats], - header=metrics, - style=termtables.styles.markdown, - ) + if table_format == 'markdown': + termtables.print( + [list(v.values()) for v in stats], + header=metrics, + style=termtables.styles.markdown, + ) + elif table_format == 'json': + table = list() + for row in stats: + row_table = dict() + for key, value in zip(metrics, row.values()): + row_table[key] = value + table.append(row_table) + print(json.dumps(table)) + else: + print(f'Unsupported table format: {table_format}') def draw_hist_threshold(sources, keys, begin_frame, threshold_name, threshold_value): From 080245aa2643bc7112544894baa7f3ade5d6fca3 Mon Sep 17 00:00:00 2001 From: elsid Date: Fri, 15 Mar 2024 21:26:51 +0100 Subject: [PATCH 2/3] Do not align arrays by duplicating last value To produce the same stats for single and multiple sources. If there are multiple sources with different number of frames, leave the number of values per each metric as is. For example: source 1: [1, None, 2] source 2: [3, None, 4, 5] before this change becomes: source 1: [1, 1, 2, 2] source 2: [3, 3, 4, 5] and after this change: source 1: [1, 1, 2] source 2: [3, 3, 4, 5] --- scripts/osg_stats.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index d898accb10..e42d62452a 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -149,17 +149,18 @@ def collect_per_frame(sources, keys, begin_frame, end_frame, frame_number_name): for key in keys: result[name][key] = [None] * (end_frame - begin_frame) for name, frames in sources.items(): + max_index = 0 for frame in frames: number = frame[frame_number_name] if begin_frame <= number < end_frame: index = number - begin_frame + max_index = max(max_index, index) for key in keys: if key in frame: result[name][key][index] = frame[key] - for name in result.keys(): for key in keys: prev = 0.0 - values = result[name][key] + values = result[name][key][:max_index + 1] for i in range(len(values)): if values[i] is not None: prev = values[i] @@ -183,9 +184,11 @@ def draw_timeseries(sources, keys, add_sum, begin_frame, end_frame): x = numpy.array(range(begin_frame, end_frame)) for name, frames in sources.items(): for key in keys: - ax.plot(x, frames[key], label=f'{key}:{name}') + y = frames[key] + ax.plot(x[:len(y)], y, label=f'{key}:{name}') if add_sum: - ax.plot(x, numpy.sum(list(frames[k] for k in keys), axis=0), label=f'sum:{name}', linestyle='--') + y = numpy.sum(list(frames[k] for k in keys), axis=0) + ax.plot(x[:len(y)], y, label=f'sum:{name}', linestyle='--') ax.grid(True) ax.legend() fig.canvas.manager.set_window_title('timeseries') @@ -196,10 +199,11 @@ def draw_commulative_timeseries(sources, keys, add_sum, begin_frame, end_frame): x = numpy.array(range(begin_frame, end_frame)) for name, frames in sources.items(): for key in keys: - ax.plot(x, numpy.cumsum(frames[key]), label=f'{key}:{name}') + y = numpy.cumsum(frames[key]) + ax.plot(x[:len(y)], y, label=f'{key}:{name}') if add_sum: - ax.plot(x, numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)), label=f'sum:{name}', - linestyle='--') + y = numpy.cumsum(numpy.sum(list(frames[k] for k in keys), axis=0)) + ax.plot(x[:len(y)], y, label=f'sum:{name}', linestyle='--') ax.grid(True) ax.legend() fig.canvas.manager.set_window_title('commulative_timeseries') @@ -210,10 +214,11 @@ def draw_timeseries_delta(sources, keys, add_sum, begin_frame, end_frame): x = numpy.array(range(begin_frame + 1, end_frame)) for name, frames in sources.items(): for key in keys: - ax.plot(x, numpy.diff(frames[key]), label=f'{key}:{name}') + y = numpy.diff(frames[key]) + ax.plot(x[:len(y)], numpy.diff(frames[key]), label=f'{key}:{name}') if add_sum: - ax.plot(x, numpy.diff(numpy.sum(list(frames[k] for k in keys), axis=0)), label=f'sum:{name}', - linestyle='--') + y = numpy.diff(numpy.sum(list(frames[k] for k in keys), axis=0)) + ax.plot(x[:len(y)], y, label=f'sum:{name}', linestyle='--') ax.grid(True) ax.legend() fig.canvas.manager.set_window_title('timeseries_delta') @@ -312,12 +317,7 @@ def print_stats(sources, keys, stats_sum, precision, sort_by, table_format): style=termtables.styles.markdown, ) elif table_format == 'json': - table = list() - for row in stats: - row_table = dict() - for key, value in zip(metrics, row.values()): - row_table[key] = value - table.append(row_table) + table = [dict(zip(metrics, row.values())) for row in stats] print(json.dumps(table)) else: print(f'Unsupported table format: {table_format}') From 6b860caa3e2b0db7c5fd6fec1a55cb465099f8c4 Mon Sep 17 00:00:00 2001 From: elsid Date: Mon, 18 Mar 2024 01:26:43 +0100 Subject: [PATCH 3/3] Fix spelling --- scripts/osg_stats.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/osg_stats.py b/scripts/osg_stats.py index e42d62452a..20fae2cac8 100755 --- a/scripts/osg_stats.py +++ b/scripts/osg_stats.py @@ -23,11 +23,11 @@ import termtables help='Print a list of all present keys in the input file.') @click.option('--regexp_match', is_flag=True, help='Use all metric that match given key. ' - 'Can be used with stats, timeseries, commulative_timeseries, hist, hist_threshold') + 'Can be used with stats, timeseries, cumulative_timeseries, hist, hist_threshold') @click.option('--timeseries', type=str, multiple=True, help='Show a graph for given metric over time.') -@click.option('--commulative_timeseries', type=str, multiple=True, - help='Show a graph for commulative sum of a given metric over time.') +@click.option('--cumulative_timeseries', type=str, multiple=True, + help='Show a graph for cumulative sum of a given metric over time.') @click.option('--timeseries_delta', type=str, multiple=True, help='Show a graph for delta between neighbouring frames of a given metric over time.') @click.option('--hist', type=str, multiple=True, @@ -54,8 +54,8 @@ import termtables help='Format floating point numbers with given precision') @click.option('--timeseries_sum', is_flag=True, help='Add a graph to timeseries for a sum per frame of all given timeseries metrics.') -@click.option('--commulative_timeseries_sum', is_flag=True, - help='Add a graph to timeseries for a sum per frame of all given commulative timeseries.') +@click.option('--cumulative_timeseries_sum', is_flag=True, + help='Add a graph to timeseries for a sum per frame of all given cumulative timeseries.') @click.option('--timeseries_delta_sum', is_flag=True, help='Add a graph to timeseries for a sum per frame of all given timeseries delta.') @click.option('--begin_frame', type=int, default=0, @@ -75,7 +75,7 @@ import termtables @click.argument('path', type=click.Path(), nargs=-1) def main(print_keys, regexp_match, timeseries, hist, hist_ratio, stdev_hist, plot, stats, precision, timeseries_sum, stats_sum, begin_frame, end_frame, path, - commulative_timeseries, commulative_timeseries_sum, frame_number_name, + cumulative_timeseries, cumulative_timeseries_sum, frame_number_name, hist_threshold, threshold_name, threshold_value, show_common_path_prefix, stats_sort_by, timeseries_delta, timeseries_delta_sum, stats_table_format): sources = {v: list(read_data(v)) for v in path} if path else {'stdin': list(read_data(None))} @@ -97,8 +97,8 @@ def main(print_keys, regexp_match, timeseries, hist, hist_ratio, stdev_hist, plo if timeseries: draw_timeseries(sources=frames, keys=matching_keys(timeseries), add_sum=timeseries_sum, begin_frame=begin_frame, end_frame=end_frame) - if commulative_timeseries: - draw_commulative_timeseries(sources=frames, keys=matching_keys(commulative_timeseries), add_sum=commulative_timeseries_sum, + if cumulative_timeseries: + draw_cumulative_timeseries(sources=frames, keys=matching_keys(cumulative_timeseries), add_sum=cumulative_timeseries_sum, begin_frame=begin_frame, end_frame=end_frame) if timeseries_delta: draw_timeseries_delta(sources=frames, keys=matching_keys(timeseries_delta), add_sum=timeseries_delta_sum, @@ -194,7 +194,7 @@ def draw_timeseries(sources, keys, add_sum, begin_frame, end_frame): fig.canvas.manager.set_window_title('timeseries') -def draw_commulative_timeseries(sources, keys, add_sum, begin_frame, end_frame): +def draw_cumulative_timeseries(sources, keys, add_sum, begin_frame, end_frame): fig, ax = matplotlib.pyplot.subplots() x = numpy.array(range(begin_frame, end_frame)) for name, frames in sources.items(): @@ -206,7 +206,7 @@ def draw_commulative_timeseries(sources, keys, add_sum, begin_frame, end_frame): ax.plot(x[:len(y)], y, label=f'sum:{name}', linestyle='--') ax.grid(True) ax.legend() - fig.canvas.manager.set_window_title('commulative_timeseries') + fig.canvas.manager.set_window_title('cumulative_timeseries') def draw_timeseries_delta(sources, keys, add_sum, begin_frame, end_frame):