#!/usr/bin/env python # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. # # Use of this source code is governed by a BSD-style license # that can be found in the LICENSE file in the root of the source # tree. An additional intellectual property rights grant can be found # in the file PATENTS. All contributing project authors may # be found in the AUTHORS file in the root of the source tree. """Generate graphs for data generated by loopback tests.
Usage examples:
Show end to end time for a single full stack test.
./full_stack_tests_plot.py -df end_to_end -o 600 --frames 1000 vp9_data.txt
Show simultaneously PSNR and encoded frame size for two different runs of
full stack test. Averaged over a cycle of 200 frames. Used e.g. for
screenshare slide test.
./full_stack_tests_plot.py -c 200 -df psnr -drf encoded_frame_size \\
before.txt after.txt
Similar to the previous test, but multiple graphs.
./full_stack_tests_plot.py -c 200 -df psnr vp8.txt vp9.txt --next \\
-c 200 -df sender_time vp8.txt vp9.txt --next \\
-c 200 -df end_to_end vp8.txt vp9.txt """
import argparse from collections import defaultdict import itertools import sys import matplotlib.pyplot as plt import numpy
# Fields
DROPPED = 0
INPUT_TIME = 1 # ms (timestamp)
SEND_TIME = 2 # ms (timestamp)
RECV_TIME = 3 # ms (timestamp)
RENDER_TIME = 4 # ms (timestamp)
ENCODED_FRAME_SIZE = 5 # bytes
PSNR = 6
SSIM = 7
ENCODE_TIME = 8 # ms (time interval)
NAME_TO_ID = {field[1]: field[0] for field in _FIELDS}
ID_TO_TITLE = {field[0]: field[2] for field in _FIELDS}
def FieldArgToId(arg): if arg == "none": returnNone if arg in NAME_TO_ID: return NAME_TO_ID[arg] if arg + "_ms"in NAME_TO_ID: return NAME_TO_ID[arg + "_ms"] raise Exception("Unrecognized field name \"{}\"".format(arg))
class PlotLine(object): """Data for a single graph line."""
def _ReadSamples(self, filename): """Reads graph data from the given file."""
f = open(filename)
it = iter(f)
self.title = it.next().strip()
self.length = int(it.next())
field_names = [name.strip() for name in it.next().split()]
field_ids = [NAME_TO_ID[name] for name in field_names]
for field_id in field_ids:
self.samples[field_id] = [0.0] * self.length
for sample_id in xrange(self.length): for col, value in enumerate(it.next().split()):
self.samples[field_ids[col]][sample_id] = float(value)
def _SubtractFirstInputTime(self):
offset = self.samples[INPUT_TIME][0] for field in [INPUT_TIME, SEND_TIME, RECV_TIME, RENDER_TIME]: if field in self.samples:
self.samples[field] = [x - offset for x in self.samples[field]]
def _GenerateAdditionalData(self): """Calculates sender time, receiver time etc. from the raw data."""
s = self.samples
last_render_time = 0 for field_id in [
SENDER_TIME, RECEIVER_TIME, END_TO_END, RENDERED_DELTA
]:
s[field_id] = [0] * self.length
for k in range(self.length):
s[SENDER_TIME][k] = s[SEND_TIME][k] - s[INPUT_TIME][k]
def _Hide(self, values): """
Replaces values for dropped frames withNone.
These values are then skipped by the Plot() method. """
return [ Noneif self.samples[DROPPED][k] else values[k] for k in range(len(values))
]
def AddSamples(self, config, target_lines_list): """Creates graph lines from the current data set with given config.""" for field in config.fields: # field is None means the user wants just to skip the color. if field isNone:
target_lines_list.append(None) continue
field_id = field & FIELD_MASK
values = self.samples[field_id]
if field & HIDE_DROPPED:
values = self._Hide(values)
def Plot(self, ax1):
lines = [] for data in self.data_list: ifnot data: # Add None lines to skip the colors.
lines.extend([None] * len(self.fields)) else:
data.AddSamples(self, lines)
def _SliceValues(values): if self.offset:
values = values[self.offset:] if self.frames:
values = values[:self.frames] return values
length = None for line in lines: if line isNone: continue
line.values = _SliceValues(line.values) if self.cycle_length:
line.values = AverageOverCycle(line.values, self.cycle_length)
if length isNone:
length = len(line.values) elif length != len(line.values): raise Exception("All arrays should have the same length!")
ax1.set_xlabel("Frame", fontsize="large") if any(line.flags & RIGHT_Y_AXIS for line in lines if line):
ax2 = ax1.twinx()
ax2.set_xlabel("Frame", fontsize="large") else:
ax2 = None
# Have to implement color_cycle manually, due to two scales in a graph.
color_cycle = ["b", "r", "g", "c", "m", "y", "k"]
color_iter = itertools.cycle(color_cycle)
for line in lines: ifnot line:
color_iter.next() continue
if self.cycle_length:
x = numpy.array(range(self.cycle_length)) else:
x = numpy.array(
range(self.offset, self.offset + len(line.values)))
y = numpy.array(line.values)
ax = ax2 if line.flags & RIGHT_Y_AXIS else ax1
ax.Plot(x,
y, "o-",
label=line.label,
markersize=3.0,
linewidth=1.0,
color=color_iter.next())
def LoadFiles(filenames):
result = [] for filename in filenames: if filename in LoadFiles.cache:
result.append(LoadFiles.cache[filename]) else:
data = Data(filename)
LoadFiles.cache[filename] = data
result.append(data) return result
parser.add_argument("-c", "--cycle_length",
nargs=1,
action=CustomAction,
type=int,
help="Cycle length over which to average the values.")
parser.add_argument( "-f", "--field",
nargs=1,
action=CustomAction,
help="Name of the field to show. Use 'none' to skip a color.")
parser.add_argument("-r", "--right",
nargs=0,
action=CustomAction,
help="Use right Y axis for given field.")
parser.add_argument("-d", "--drop",
nargs=0,
action=CustomAction,
help="Hide values for dropped frames.")
parser.add_argument("-o", "--offset",
nargs=1,
action=CustomAction,
type=int,
help="Frame offset.")
parser.add_argument("-n", "--next",
nargs=0,
action=CustomAction,
help="Separator for multiple graphs.")
parser.add_argument( "--frames",
nargs=1,
action=CustomAction,
type=int,
help="Frame count to show or take into account while averaging.")
parser.add_argument("-t", "--title",
nargs=1,
action=CustomAction,
help="Title of the graph.")
parser.add_argument("-O", "--output_filename",
nargs=1,
action=CustomAction,
help="Use to save the graph into a file. " "Otherwise, a window will be shown.")
parser.add_argument( "files",
nargs="+",
action=CustomAction,
help="List of text-based files generated by loopback tests.") return parser
def _PlotConfigFromArgs(args, graph_num): # Pylint complains about using kwargs, so have to do it this way.
cycle_length = None
frames = None
offset = 0
output_filename = None
title = "Graph"
def PlotConfigsFromArgs(args): """Generates plot configs for given command line arguments.""" # The way it works: # First we detect separators -n/--next and split arguments into groups, one # for each plot. For each group, we partially parse it with # argparse.ArgumentParser, modified to remember the order of arguments. # Then we traverse the argument list and fill the PlotConfig.
args = itertools.groupby(args, lambda x: x in ["-n", "--next"])
prep_args = list(list(group) for match, group in args ifnot match)
parser = GetParser()
plot_configs = [] for index, raw_args in enumerate(prep_args):
graph_args = parser.parse_args(raw_args).ordered_args
plot_configs.append(_PlotConfigFromArgs(graph_args, index)) return plot_configs
def ShowOrSavePlots(plot_configs): for config in plot_configs:
fig = plt.figure(figsize=(14.0, 10.0))
ax = fig.add_subPlot(1, 1, 1)
plt.title(config.title)
config.Plot(ax) if config.output_filename:
print "Saving to", config.output_filename
fig.savefig(config.output_filename)
plt.close(fig)
plt.show()
if __name__ == "__main__":
ShowOrSavePlots(PlotConfigsFromArgs(sys.argv[1:]))
Messung V0.5
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.