| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 # Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 # | 3 # |
| 4 # Use of this source code is governed by a BSD-style license | 4 # Use of this source code is governed by a BSD-style license |
| 5 # that can be found in the LICENSE file in the root of the source | 5 # that can be found in the LICENSE file in the root of the source |
| 6 # tree. An additional intellectual property rights grant can be found | 6 # tree. An additional intellectual property rights grant can be found |
| 7 # in the file PATENTS. All contributing project authors may | 7 # in the file PATENTS. All contributing project authors may |
| 8 # be found in the AUTHORS file in the root of the source tree. | 8 # be found in the AUTHORS file in the root of the source tree. |
| 9 | 9 |
| 10 # This script is used to plot simulation dynamics. The expected format is | 10 # This script is used to plot simulation dynamics. The expected format is |
| 11 # PLOT <plot_number> <var_name>:<ssrc>@<alg_name> <time> <value> | 11 # PLOT <plot_number> <var_name>:<ssrc>@<alg_name> <time> <value> |
| 12 # <var_name> may optionally be followed by #<axis_alignment> but it is | 12 # <var_name> may optionally be followed by #<axis_alignment> but it is |
| 13 # deprecated. <plot_number> is also deprecated. | 13 # deprecated. <plot_number> is also deprecated. |
| 14 # Each combination <var_name>:<ssrc>@<alg_name> is stored in it's own time | 14 # Each combination <var_name>:<ssrc>@<alg_name> is stored in it's own time |
| 15 # series. The main function defines which time series should be displayed and | 15 # series. The main function defines which time series should be displayed and |
| 16 # whether they should should be displayed in the same or separate windows. | 16 # whether they should should be displayed in the same or separate windows. |
| 17 | 17 |
| 18 | 18 |
| 19 import matplotlib.pyplot as plt | 19 import matplotlib.pyplot as plt |
| 20 import numpy | 20 import numpy |
| 21 import re | 21 import re |
| 22 import sys | 22 import sys |
| 23 | 23 |
| 24 # Change this to True to save the figure to a file. Look below for details. | 24 # Change this to True to save the figure to a file. Look below for details. |
| 25 save_figure = False | 25 SAVE_FIGURE = False |
| 26 | 26 |
| 27 class ParsePlotLineException(Exception): | 27 class ParsePlotLineException(Exception): |
| 28 def __init__(self, reason, line): | 28 def __init__(self, reason, line): |
| 29 super(ParsePlotLineException, self).__init__() | 29 super(ParsePlotLineException, self).__init__() |
| 30 self.reason = reason | 30 self.reason = reason |
| 31 self.line = line | 31 self.line = line |
| 32 | 32 |
| 33 | 33 |
| 34 def parse_plot_line(line): | 34 def ParsePlotLine(line): |
| 35 split_line = line.split() | 35 split_line = line.split() |
| 36 if len(split_line) != 5: | 36 if len(split_line) != 5: |
| 37 raise ParsePlotLineException("Expected 5 arguments on line", line) | 37 raise ParsePlotLineException("Expected 5 arguments on line", line) |
| 38 (plot, _, annotated_var, time, value) = split_line | 38 (plot, _, annotated_var, time, value) = split_line |
| 39 if plot != "PLOT": | 39 if plot != "PLOT": |
| 40 raise ParsePlotLineException("Line does not begin with \"PLOT\\t\"", line) | 40 raise ParsePlotLineException("Line does not begin with \"PLOT\\t\"", line) |
| 41 # The variable name can contain any non-whitespace character except "#:@" | 41 # The variable name can contain any non-whitespace character except "#:@" |
| 42 match = re.match(r'([^\s#:@]+)(?:#\d)?:(\d+)@(\S+)', annotated_var) | 42 match = re.match(r'([^\s#:@]+)(?:#\d)?:(\d+)@(\S+)', annotated_var) |
| 43 | 43 |
| 44 if match == None: | 44 if match == None: |
| 45 raise ParsePlotLineException("Could not parse variable name, ssrc and \ | 45 raise ParsePlotLineException("Could not parse variable name, ssrc and \ |
| 46 algorithm name", annotated_var) | 46 algorithm name", annotated_var) |
| 47 var_name = match.group(1) | 47 var_name = match.group(1) |
| 48 ssrc = match.group(2) | 48 ssrc = match.group(2) |
| 49 alg_name = match.group(3).replace('_', ' ') | 49 alg_name = match.group(3).replace('_', ' ') |
| 50 | 50 |
| 51 return (var_name, ssrc, alg_name, time, value) | 51 return (var_name, ssrc, alg_name, time, value) |
| 52 | 52 |
| 53 | 53 |
| 54 def generate_label(var_name, ssrc, ssrc_count, alg_name): | 54 def GenerateLabel(var_name, ssrc, ssrc_count, alg_name): |
| 55 label = var_name | 55 label = var_name |
| 56 if ssrc_count > 1 or ssrc != "0": | 56 if ssrc_count > 1 or ssrc != "0": |
| 57 label = label + " flow " + ssrc | 57 label = label + " flow " + ssrc |
| 58 if alg_name != "-": | 58 if alg_name != "-": |
| 59 label = label + " " + alg_name | 59 label = label + " " + alg_name |
| 60 return label | 60 return label |
| 61 | 61 |
| 62 | 62 |
| 63 class Figure(object): | 63 class Figure(object): |
| 64 def __init__(self, name): | 64 def __init__(self, name): |
| 65 self.name = name | 65 self.name = name |
| 66 self.subplots = [] | 66 self.subplots = [] |
| 67 | 67 |
| 68 def addSubplot(self, var_names, xlabel, ylabel): | 68 def AddSubplot(self, var_names, xlabel, ylabel): |
| 69 self.subplots.append(Subplot(var_names, xlabel, ylabel)) | 69 self.subplots.append(Subplot(var_names, xlabel, ylabel)) |
| 70 | 70 |
| 71 def addSample(self, var_name, ssrc, alg_name, time, value): | 71 def AddSample(self, var_name, ssrc, alg_name, time, value): |
| 72 for s in self.subplots: | 72 for s in self.subplots: |
| 73 s.addSample(var_name, ssrc, alg_name, time, value) | 73 s.AddSample(var_name, ssrc, alg_name, time, value) |
| 74 | 74 |
| 75 def plotFigure(self, fig): | 75 def PlotFigure(self, fig): |
| 76 n = len(self.subplots) | 76 n = len(self.subplots) |
| 77 for i in range(n): | 77 for i in range(n): |
| 78 ax = fig.add_subplot(n, 1, i+1) | 78 axis = fig.add_subplot(n, 1, i+1) |
| 79 self.subplots[i].plotSubplot(ax) | 79 self.subplots[i].PlotSubplot(axis) |
| 80 | 80 |
| 81 | 81 |
| 82 class Subplot(object): | 82 class Subplot(object): |
| 83 def __init__(self, var_names, xlabel, ylabel): | 83 def __init__(self, var_names, xlabel, ylabel): |
| 84 self.xlabel = xlabel | 84 self.xlabel = xlabel |
| 85 self.ylabel = ylabel | 85 self.ylabel = ylabel |
| 86 self.var_names = var_names | 86 self.var_names = var_names |
| 87 self.samples = dict() | 87 self.samples = dict() |
| 88 | 88 |
| 89 def addSample(self, var_name, ssrc, alg_name, time, value): | 89 def AddSample(self, var_name, ssrc, alg_name, time, value): |
| 90 if var_name not in self.var_names: | 90 if var_name not in self.var_names: |
| 91 return | 91 return |
| 92 | 92 |
| 93 if alg_name not in self.samples.keys(): | 93 if alg_name not in self.samples.keys(): |
| 94 self.samples[alg_name] = {} | 94 self.samples[alg_name] = {} |
| 95 if ssrc not in self.samples[alg_name].keys(): | 95 if ssrc not in self.samples[alg_name].keys(): |
| 96 self.samples[alg_name][ssrc] = {} | 96 self.samples[alg_name][ssrc] = {} |
| 97 if var_name not in self.samples[alg_name][ssrc].keys(): | 97 if var_name not in self.samples[alg_name][ssrc].keys(): |
| 98 self.samples[alg_name][ssrc][var_name] = [] | 98 self.samples[alg_name][ssrc][var_name] = [] |
| 99 | 99 |
| 100 self.samples[alg_name][ssrc][var_name].append((time, value)) | 100 self.samples[alg_name][ssrc][var_name].append((time, value)) |
| 101 | 101 |
| 102 def plotSubplot(self, ax): | 102 def PlotSubplot(self, axis): |
| 103 ax.set_xlabel(self.xlabel) | 103 axis.set_xlabel(self.xlabel) |
| 104 ax.set_ylabel(self.ylabel) | 104 axis.set_ylabel(self.ylabel) |
| 105 | 105 |
| 106 count = 0 | 106 count = 0 |
| 107 for alg_name in self.samples.keys(): | 107 for alg_name in self.samples.keys(): |
| 108 for ssrc in self.samples[alg_name].keys(): | 108 for ssrc in self.samples[alg_name].keys(): |
| 109 for var_name in self.samples[alg_name][ssrc].keys(): | 109 for var_name in self.samples[alg_name][ssrc].keys(): |
| 110 x = [sample[0] for sample in self.samples[alg_name][ssrc][var_name]] | 110 x = [sample[0] for sample in self.samples[alg_name][ssrc][var_name]] |
| 111 y = [sample[1] for sample in self.samples[alg_name][ssrc][var_name]] | 111 y = [sample[1] for sample in self.samples[alg_name][ssrc][var_name]] |
| 112 x = numpy.array(x) | 112 x = numpy.array(x) |
| 113 y = numpy.array(y) | 113 y = numpy.array(y) |
| 114 | 114 |
| 115 ssrc_count = len(self.samples[alg_name].keys()) | 115 ssrc_count = len(self.samples[alg_name].keys()) |
| 116 l = generate_label(var_name, ssrc, ssrc_count, alg_name) | 116 l = GenerateLabel(var_name, ssrc, ssrc_count, alg_name) |
| 117 plt.plot(x, y, label=l, linewidth=2.0) | 117 plt.plot(x, y, label=l, linewidth=2.0) |
| 118 count += 1 | 118 count += 1 |
| 119 | 119 |
| 120 plt.grid(True) | 120 plt.grid(True) |
| 121 if count > 1: | 121 if count > 1: |
| 122 plt.legend(loc='best') | 122 plt.legend(loc='best') |
| 123 | 123 |
| 124 | 124 |
| 125 def main(): | 125 def main(): |
| 126 receiver = Figure("PacketReceiver") | 126 receiver = Figure("PacketReceiver") |
| 127 receiver.addSubplot(['Throughput_kbps', 'MaxThroughput_', 'Capacity_kbps', | 127 receiver.AddSubplot(['Throughput_kbps', 'MaxThroughput_', 'Capacity_kbps', |
| 128 'PerFlowCapacity_kbps', 'MetricRecorderThroughput_kbps'], | 128 'PerFlowCapacity_kbps', 'MetricRecorderThroughput_kbps'], |
| 129 "Time (s)", "Throughput (kbps)") | 129 "Time (s)", "Throughput (kbps)") |
| 130 receiver.addSubplot(['Delay_ms_', 'Delay_ms'], "Time (s)", | 130 receiver.AddSubplot(['Delay_ms_', 'Delay_ms'], "Time (s)", |
| 131 "One-way delay (ms)") | 131 "One-way delay (ms)") |
| 132 receiver.addSubplot(['Packet_Loss_'], "Time (s)", "Packet Loss Ratio") | 132 receiver.AddSubplot(['Packet_Loss_'], "Time (s)", "Packet Loss Ratio") |
| 133 | 133 |
| 134 kalman_state = Figure("KalmanState") | 134 kalman_state = Figure("KalmanState") |
| 135 kalman_state.addSubplot(['kc', 'km'], "Time (s)", "Kalman gain") | 135 kalman_state.AddSubplot(['kc', 'km'], "Time (s)", "Kalman gain") |
| 136 kalman_state.addSubplot(['slope_1/bps'], "Time (s)", "Slope") | 136 kalman_state.AddSubplot(['slope_1/bps'], "Time (s)", "Slope") |
| 137 kalman_state.addSubplot(['var_noise'], "Time (s)", "Var noise") | 137 kalman_state.AddSubplot(['var_noise'], "Time (s)", "Var noise") |
| 138 | 138 |
| 139 detector_state = Figure("DetectorState") | 139 detector_state = Figure("DetectorState") |
| 140 detector_state.addSubplot(['offset_ms'], "Time (s)", "Offset") | 140 detector_state.AddSubplot(['offset_ms'], "Time (s)", "Offset") |
| 141 detector_state.addSubplot(['gamma_ms'], "Time (s)", "Gamma") | 141 detector_state.AddSubplot(['gamma_ms'], "Time (s)", "Gamma") |
| 142 | 142 |
| 143 trendline_state = Figure("TrendlineState") | 143 trendline_state = Figure("TrendlineState") |
| 144 trendline_state.addSubplot(["accumulated_delay_ms", "smoothed_delay_ms"], | 144 trendline_state.AddSubplot(["accumulated_delay_ms", "smoothed_delay_ms"], |
| 145 "Time (s)", "Delay (ms)") | 145 "Time (s)", "Delay (ms)") |
| 146 trendline_state.addSubplot(["trendline_slope"], "Time (s)", "Slope") | 146 trendline_state.AddSubplot(["trendline_slope"], "Time (s)", "Slope") |
| 147 | 147 |
| 148 target_bitrate = Figure("TargetBitrate") | 148 target_bitrate = Figure("TargetBitrate") |
| 149 target_bitrate.addSubplot(['target_bitrate_bps'], "Time (s)", "Bitrate (bps)") | 149 target_bitrate.AddSubplot(['target_bitrate_bps'], "Time (s)", "Bitrate (bps)") |
| 150 | 150 |
| 151 # Select which figures to plot here. | 151 # Select which figures to plot here. |
| 152 figures = [receiver, detector_state, trendline_state, target_bitrate] | 152 figures = [receiver, detector_state, trendline_state, target_bitrate] |
| 153 | 153 |
| 154 # Add samples to the figures. | 154 # Add samples to the figures. |
| 155 for line in sys.stdin: | 155 for line in sys.stdin: |
| 156 if line.startswith("[ RUN ]"): | 156 if line.startswith("[ RUN ]"): |
| 157 test_name = re.search(r'\.(\w+)', line).group(1) | 157 test_name = re.search(r'\.(\w+)', line).group(1) |
| 158 if line.startswith("PLOT"): | 158 if line.startswith("PLOT"): |
| 159 try: | 159 try: |
| 160 (var_name, ssrc, alg_name, time, value) = parse_plot_line(line) | 160 (var_name, ssrc, alg_name, time, value) = ParsePlotLine(line) |
| 161 for f in figures: | 161 for f in figures: |
| 162 # The sample will be ignored bv the figures that don't need it. | 162 # The sample will be ignored bv the figures that don't need it. |
| 163 f.addSample(var_name, ssrc, alg_name, time, value) | 163 f.AddSample(var_name, ssrc, alg_name, time, value) |
| 164 except ParsePlotLineException as e: | 164 except ParsePlotLineException as e: |
| 165 print e.reason | 165 print e.reason |
| 166 print e.line | 166 print e.line |
| 167 | 167 |
| 168 # Plot figures. | 168 # Plot figures. |
| 169 for f in figures: | 169 for f in figures: |
| 170 fig = plt.figure(f.name) | 170 fig = plt.figure(f.name) |
| 171 f.plotFigure(fig) | 171 f.PlotFigure(fig) |
| 172 if save_figure: | 172 if SAVE_FIGURE: |
| 173 fig.savefig(test_name + f.name + ".png") | 173 fig.savefig(test_name + f.name + ".png") |
| 174 plt.show() | 174 plt.show() |
| 175 | 175 |
| 176 if __name__ == '__main__': | 176 if __name__ == '__main__': |
| 177 main() | 177 main() |
| OLD | NEW |