plot.py (5663B)
1 #! /usr/bin/env python3 2 # 3 # This Source Code Form is subject to the terms of the Mozilla Public 4 # License, v. 2.0. If a copy of the MPL was not distributed with this 5 # file, You can obtain one at http://mozilla.org/MPL/2.0/. 6 # 7 # This scripts plots graphs produced by our drift correction code. 8 # 9 # Install dependencies with: 10 # > pip install bokeh pandas 11 # 12 # Generate the csv data file with the DriftControllerGraphs log module: 13 # > MOZ_LOG=raw,sync,DriftControllerGraphs:5 \ 14 # > MOZ_LOG_FILE=/tmp/driftcontrol.csv \ 15 # > ./mach gtest '*AudioDrift*StepResponse' 16 # 17 # Generate the graphs with this script: 18 # > ./dom/media/driftcontrol/plot.py /tmp/driftcontrol.csv.moz_log 19 # 20 # The script should produce a file plot.html in the working directory and 21 # open it in the default browser. 22 23 import argparse 24 from collections import OrderedDict 25 26 import pandas 27 from bokeh.io import output_file, show 28 from bokeh.layouts import gridplot 29 from bokeh.models import TabPanel, Tabs 30 from bokeh.plotting import figure 31 32 33 def main(): 34 parser = argparse.ArgumentParser( 35 prog="plot.py for DriftControllerGraphs", 36 description="""Takes a csv file of DriftControllerGraphs data 37 (from a single DriftController instance) and plots 38 them into plot.html in the current working directory. 39 40 The easiest way to produce the data is with MOZ_LOG: 41 MOZ_LOG=raw,sync,DriftControllerGraphs:5 \ 42 MOZ_LOG_FILE=/tmp/driftcontrol.csv \ 43 ./mach gtest '*AudioDrift*StepResponse'""", 44 ) 45 parser.add_argument("csv_file", type=str) 46 args = parser.parse_args() 47 48 all_df = pandas.read_csv(args.csv_file) 49 50 # Filter on distinct ids to support multiple plotting sources 51 tabs = [] 52 for id in list(OrderedDict.fromkeys(all_df["id"])): 53 df = all_df[all_df["id"] == id] 54 55 t = df["t"] 56 buffering = df["buffering"] 57 avgbuffered = df["avgbuffered"] 58 desired = df["desired"] 59 buffersize = df["buffersize"] 60 inlatency = df["inlatency"] 61 outlatency = df["outlatency"] 62 inframesavg = df["inframesavg"] 63 outframesavg = df["outframesavg"] 64 inrate = df["inrate"] 65 outrate = df["outrate"] 66 steadystaterate = df["steadystaterate"] 67 nearthreshold = df["nearthreshold"] 68 corrected = df["corrected"] 69 hysteresiscorrected = df["hysteresiscorrected"] 70 configured = df["configured"] 71 72 output_file("plot.html") 73 74 fig1 = figure() 75 # Variables with more variation are plotted after smoother variables 76 # because latter variables are drawn on top and so visibility of 77 # individual values in the variables with more variation is improved 78 # (when both variables are shown). 79 fig1.line( 80 t, inframesavg, color="violet", legend_label="Average input packet size" 81 ) 82 fig1.line( 83 t, outframesavg, color="purple", legend_label="Average output packet size" 84 ) 85 fig1.line(t, inlatency, color="hotpink", legend_label="In latency") 86 fig1.line(t, outlatency, color="firebrick", legend_label="Out latency") 87 fig1.line(t, desired, color="goldenrod", legend_label="Desired buffering") 88 fig1.line( 89 t, avgbuffered, color="orangered", legend_label="Average buffered estimate" 90 ) 91 fig1.line(t, buffering, color="dodgerblue", legend_label="Actual buffering") 92 fig1.line(t, buffersize, color="seagreen", legend_label="Buffer size") 93 fig1.varea( 94 t, 95 [d - h for (d, h) in zip(desired, nearthreshold)], 96 [d + h for (d, h) in zip(desired, nearthreshold)], 97 alpha=0.2, 98 color="goldenrod", 99 legend_label='"Near" band (won\'t reduce desired buffering outside)', 100 ) 101 102 slowConvergenceSecs = 30 103 adjustmentInterval = 1 104 slowHysteresis = 1 105 avgError = avgbuffered - desired 106 absAvgError = [abs(e) for e in avgError] 107 slow_offset = [e / slowConvergenceSecs - slowHysteresis for e in absAvgError] 108 fast_offset = [e / adjustmentInterval for e in absAvgError] 109 low_offset, high_offset = zip(*[ 110 (s, f) if e >= 0 else (-f, -s) 111 for (e, s, f) in zip(avgError, slow_offset, fast_offset) 112 ]) 113 114 fig2 = figure(x_range=fig1.x_range) 115 fig2.varea( 116 t, 117 steadystaterate + low_offset, 118 steadystaterate + high_offset, 119 alpha=0.2, 120 color="goldenrod", 121 legend_label="Deadband (won't change in rate within)", 122 ) 123 fig2.line(t, inrate, color="hotpink", legend_label="Nominal in sample rate") 124 fig2.line(t, outrate, color="firebrick", legend_label="Nominal out sample rate") 125 fig2.line( 126 t, 127 steadystaterate, 128 color="orangered", 129 legend_label="Estimated in rate with drift", 130 ) 131 fig2.line( 132 t, corrected, color="dodgerblue", legend_label="Corrected in sample rate" 133 ) 134 fig2.line( 135 t, 136 hysteresiscorrected, 137 color="seagreen", 138 legend_label="Hysteresis-corrected in sample rate", 139 ) 140 fig2.line( 141 t, configured, color="goldenrod", legend_label="Configured in sample rate" 142 ) 143 144 fig1.legend.location = "top_left" 145 fig2.legend.location = "top_right" 146 for fig in (fig1, fig2): 147 fig.legend.background_fill_alpha = 0.6 148 fig.legend.click_policy = "hide" 149 150 tabs.append(TabPanel(child=gridplot([[fig1, fig2]]), title=str(id))) 151 152 show(Tabs(tabs=tabs)) 153 154 155 if __name__ == "__main__": 156 main()