#! /usr/bin/env python3
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
# This scripts plots graphs produced by our drift correction code.
#
# Install dependencies with:
# > pip install bokeh pandas
#
# Generate the csv data file with the DriftControllerGraphs log module:
# > MOZ_LOG=raw,sync,DriftControllerGraphs:5 \
# > MOZ_LOG_FILE=/tmp/driftcontrol.csv \
# > ./mach gtest '*AudioDrift*StepResponse'
#
# Generate the graphs with this script:
# > ./dom/media/driftcontrol/plot.py /tmp/driftcontrol.csv.moz_log
#
# The script should produce a file plot.html in the working directory and
# open it in the default browser.
import argparse
from collections
import OrderedDict
import pandas
from bokeh.io
import output_file, show
from bokeh.layouts
import gridplot
from bokeh.models
import TabPanel, Tabs
from bokeh.plotting
import figure
def main():
parser = argparse.ArgumentParser(
prog=
"plot.py for DriftControllerGraphs",
description=
"""Takes a csv file of DriftControllerGraphs data
(
from a single DriftController instance)
and plots
them into plot.html
in the current working directory.
The easiest way to produce the data
is with MOZ_LOG:
MOZ_LOG=raw,sync,DriftControllerGraphs:5 \
MOZ_LOG_FILE=/tmp/driftcontrol.csv \
./mach gtest
'*AudioDrift*StepResponse'""",
)
parser.add_argument(
"csv_file", type=str)
args = parser.parse_args()
all_df = pandas.read_csv(args.csv_file)
# Filter on distinct ids to support multiple plotting sources
tabs = []
for id
in list(OrderedDict.fromkeys(all_df[
"id"])):
df = all_df[all_df[
"id"] == id]
t = df[
"t"]
buffering = df[
"buffering"]
avgbuffered = df[
"avgbuffered"]
desired = df[
"desired"]
buffersize = df[
"buffersize"]
inlatency = df[
"inlatency"]
outlatency = df[
"outlatency"]
inframesavg = df[
"inframesavg"]
outframesavg = df[
"outframesavg"]
inrate = df[
"inrate"]
outrate = df[
"outrate"]
steadystaterate = df[
"steadystaterate"]
nearthreshold = df[
"nearthreshold"]
corrected = df[
"corrected"]
hysteresiscorrected = df[
"hysteresiscorrected"]
configured = df[
"configured"]
output_file(
"plot.html")
fig1 = figure()
# Variables with more variation are plotted after smoother variables
# because latter variables are drawn on top and so visibility of
# individual values in the variables with more variation is improved
# (when both variables are shown).
fig1.line(
t, inframesavg, color=
"violet", legend_label=
"Average input packet size"
)
fig1.line(
t, outframesavg, color=
"purple", legend_label=
"Average output packet size"
)
fig1.line(t, inlatency, color=
"hotpink", legend_label=
"In latency")
fig1.line(t, outlatency, color=
"firebrick", legend_label=
"Out latency")
fig1.line(t, desired, color=
"goldenrod", legend_label=
"Desired buffering")
fig1.line(
t, avgbuffered, color=
"orangered", legend_label=
"Average buffered estimate"
)
fig1.line(t, buffering, color=
"dodgerblue", legend_label=
"Actual buffering")
fig1.line(t, buffersize, color=
"seagreen", legend_label=
"Buffer size")
fig1.varea(
t,
[d - h
for (d, h)
in zip(desired, nearthreshold)],
[d + h
for (d, h)
in zip(desired, nearthreshold)],
alpha=0.2,
color=
"goldenrod",
legend_label=
'"Near" band (won\'t reduce desired buffering outside)
',
)
slowConvergenceSecs = 30
adjustmentInterval = 1
slowHysteresis = 1
avgError = avgbuffered - desired
absAvgError = [abs(e)
for e
in avgError]
slow_offset = [e / slowConvergenceSecs - slowHysteresis
for e
in absAvgError]
fast_offset = [e / adjustmentInterval
for e
in absAvgError]
low_offset, high_offset = zip(
*[
(s, f)
if e >= 0
else (-f, -s)
for (e, s, f)
in zip(avgError, slow_offset, fast_offset)
]
)
fig2 = figure(x_range=fig1.x_range)
fig2.varea(
t,
steadystaterate + low_offset,
steadystaterate + high_offset,
alpha=0.2,
color=
"goldenrod",
legend_label=
"Deadband (won't change in rate within)",
)
fig2.line(t, inrate, color=
"hotpink", legend_label=
"Nominal in sample rate")
fig2.line(t, outrate, color=
"firebrick", legend_label=
"Nominal out sample rate")
fig2.line(
t,
steadystaterate,
color=
"orangered",
legend_label=
"Estimated in rate with drift",
)
fig2.line(
t, corrected, color=
"dodgerblue", legend_label=
"Corrected in sample rate"
)
fig2.line(
t,
hysteresiscorrected,
color=
"seagreen",
legend_label=
"Hysteresis-corrected in sample rate",
)
fig2.line(
t, configured, color=
"goldenrod", legend_label=
"Configured in sample rate"
)
fig1.legend.location =
"top_left"
fig2.legend.location =
"top_right"
for fig
in (fig1, fig2):
fig.legend.background_fill_alpha = 0.6
fig.legend.click_policy =
"hide"
tabs.append(TabPanel(child=gridplot([[fig1, fig2]]), title=str(id)))
show(Tabs(tabs=tabs))
if __name__ ==
"__main__":
main()