Commit d510cfc0 authored by Andreas Schmidt's avatar Andreas Schmidt
Browse files

+= notebook and analysis code

parent 0b6aa867
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
__pycache__/
.ipynb_checkpoints/

analyze/__init__.py

0 → 100644
+0 −0

Empty file added.

analyze/ipts.py

0 → 100644
+144 −0
Original line number Diff line number Diff line
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from .util import experiment_config, cdf, protos, all_colors, colors, all_markers, markers, anonymize, scatter_dot_size, scatter_dot_linewidths, linestyles, opt_linewidth

pace_columns = [
                "AppSendPaceInternal",
                "AppSendPaceDependent",
                "AppSendPaceExternal",
                "TransTransmitPaceInternal",
                "TransTransmitPaceDependent",
                "TransTransmitPaceExternal",
                "NWPace",
                "RecvBtlPace"
                ]

def prep(filename):
    df = pd.read_csv(filename,header=None,index_col=0,names=["SendT","IPT", "AppSendPaceInternal","AppSendPaceDependent","AppSendPaceExternal","TransTransmitPaceInternal","TransTransmitPaceDependent","TransTransmitPaceExternal","RecvBtlPace","NWPace"])
    df["Round"] = df.index
    df["SendT"] /= 1000**2 # ns -> ms
    df["IPT"] /= 1000**2 # ns -> ms
    for column in pace_columns:
        df[column] /= 1000 # us -> ms
    return df

def ipts_cdf(folder, r=None, protocols=None, figsize = (16,5), file_name="ipt_cdf.pdf", export=False, anonymous=False, legend=None, iptopt=None):
    if legend is None:
        legend = {}
    if r is None:
        r = slice(0,-1)
    p = protocols if protocols is not None else protos

    exp = experiment_config(folder)
    baseline = (max(exp["network_pace"], exp["app_send_delay"], exp["app_recv_delay"])) * 1000
    if iptopt is not None:
        baseline = iptopt

    fig = plt.figure(figsize=figsize)
    dfs = {}
    for i, proto in enumerate(p):
        df = prep("{0}/sender_{1}.csv".format(folder, proto))[r]
        dfs[proto] = df
        cdf(df["IPT"], grid=False, label=anonymize(proto, anonymous).upper(), color=colors[proto], linestyle=linestyles[proto])
    plt.axvline(x=baseline, color=colors["line"], linewidth=opt_linewidth, linestyle=linestyles["opt"], label="$IPT_{opt}$")
    if legend is not False:
        plt.legend(**legend)
    plt.xlabel("Inter Packet Time [ms]")
    plt.ylabel("CDF")

    plt.yticks(np.arange(0.0, 1.1, 0.5))

    if export and file_name is not None:
        fig.savefig(file_name)
    return dfs

def _ipt_by_time(df,ax,proto,i,anonymous=False,legend=None):
    if legend is None:
        legend = {}
    ax.scatter(df["SendT"], df["IPT"], label=anonymize(proto, anonymous).upper(), marker=markers[proto], color=colors[proto], s=scatter_dot_size, linewidths=scatter_dot_linewidths)
    #ax.grid()
    ax.semilogy()
    if legend is not False:
        ax.legend(**legend)

def _ipt_by_round(df,ax,proto,i,anonymous=False,legend=None):
    if legend is None:
        legend = {}
    ax.scatter(df["Round"], df["IPT"], label=anonymize(proto, anonymous).upper(), marker=markers[proto], color=colors[proto], s=scatter_dot_size, linewidths=scatter_dot_linewidths)
    #ax.grid()
    ax.semilogy()
    if legend is not False:
        ax.legend(**legend)

def ipts_timeseries(folder, r=None, times=True, rounds=True, paces=None, protocols=None, grid=False, legend=None, figsize = (16,9), file_name="ipt.pdf", export=False, anonymous=False, iptopt=None):
    if legend is None:
        legend = {}
    if r is None:
        r = slice(0,-1)
    p = protocols if protocols is not None else protos

    rows = sum([times, rounds, 1 if paces is not None else 0])
    fig, axes = plt.subplots(nrows=rows, ncols=1)
    fig.set_size_inches(figsize[0], figsize[1])
    exp = experiment_config(folder)
    effective_rounds = 0

    baseline = (max(exp["network_pace"], exp["app_send_delay"], exp["app_recv_delay"])) * 1000
    if iptopt is not None:
        baseline = iptopt

    dfs = {}

    for i, proto in enumerate(p):
        df = prep("{}/sender_{}.csv".format(folder, proto))[r]
        dfs[proto] = df
        effective_rounds = len(df.index)
        ax_idx = 0

        if times:
            _ipt_by_time(df,axes[ax_idx] if rows > 1 else axes,proto,i,anonymous,legend)
            ax_idx += 1

        if rounds:
            _ipt_by_round(df,axes[ax_idx] if rows > 1 else axes,proto,i,anonymous,legend)
            ax_idx += 1

        if paces is not None and proto == "prrt":
            ax = axes[ax_idx] if rows > 1 else axes
            for j, name in enumerate(paces):
                ax.scatter(df["Round"], df[name], label=name, marker=all_markers[j], color=all_colors[j], s=scatter_dot_size, linewidths=scatter_dot_linewidths)
            ax.set_xlabel("Round Number")
            ax.set_ylabel("Pace [ms]")
            ax.axhline(y=baseline, color=colors["line"], linestyle=linestyles["opt"], linewidth=opt_linewidth, label="$IPT_{opt}$")
            ax.semilogy()
            if grid:
                ax.grid()
            ax.legend(loc=legend)

    mintime = effective_rounds * baseline

    ax_idx = 0

    if times:
        ax = axes[ax_idx] if rows > 1 else axes
        ax.axhline(y=baseline, color=colors["line"], linestyle=linestyles["opt"], linewidth=opt_linewidth, label="$IPT_{opt}$")
        ax.axvline(x=mintime, color=colors["line"], linestyle=linestyles["opt2"], linewidth=opt_linewidth, label="$EXP_{opt}$")
        if legend is not False:
            ax.legend(**legend)
        ax.set_xlabel("Send Time [ms]")
        ax.set_ylabel("Inter Packet Time [ms]")
        ax_idx += 1

    if rounds:
        ax = axes[ax_idx] if rows > 1 else axes
        ax.axhline(y=baseline, color=colors["line"], linestyle=linestyles["opt"], linewidth=opt_linewidth, label="$IPT_{opt}$")
        if legend is not False:
            ax.legend(**legend)
        ax.set_xlabel("Round Number")
        ax.set_ylabel("Inter Packet Time [ms]")

    if export and file_name is not None:
        fig.savefig(file_name)

    return dfs

analyze/receiver.py

0 → 100644
+183 −0
Original line number Diff line number Diff line
from .util import experiment_config, protos, markers, colors, cdf, anonymize, scatter_dot_size, scatter_dot_linewidths, linestyles, opt_linewidth
import pandas as pd
import numpy as np
import math
import matplotlib.pyplot as plt

pace_columns = [
                "TransReceivePaceInternal",
                "TransReceivePaceDependent",
                "TransReceivePaceExternal",
                "AppDeliverPaceInternal",
                "AppDeliverPaceDependent",
                "AppDeliverPaceExternal",
                "SendBtlPace"]


def preprocess(filename, colname="time"):
    df = pd.read_csv(filename,
                     header=None,
                     index_col=0,
                     names=[colname+"A",
                            colname,
                            "AppDeliverPaceInternal",
                            "AppDeliverPaceDependent",
                            "AppDeliverPaceExternal",
                            "TransReceivePaceInternal",
                            "TransReceivePaceDependent",
                            "TransReceivePaceExternal",
                            "SendBtlPace"])

    df.drop([colname+"A"], axis=1, inplace=True)
    df[colname].replace(to_replace=0, value=np.nan, inplace=True)
    df[colname] = df[colname] / 1000.0**2  # plot ms
    for column in pace_columns:
        df[column] /= 1000  # us in ms
    return df


def dts_box(folder, r=None):
    if r is None:
        r = slice(0, -1)

    exp = experiment_config(folder)
    baseline = (exp["delay"] + exp["network_pace"]) * 1000

    df = None
    for i, proto in enumerate(protos):
        dfx = preprocess("{0}/receiver_{1}.csv".format(folder, proto))[r]
        dfx.rename(index=str, columns={"time": proto.upper()}, inplace=True)
        if df is None:
            df = dfx
        else:
            df = df.join(dfx)
    df.plot.box(grid=False, vert=False, figsize=(16, 5))
    plt.axvline(x=baseline, color=colors["line"], linestyle=linestyles["opt"], label="$DT_{opt}$", linewidth=opt_linewidth)
    plt.xlabel("E2E Delivery Time [ms]")
    plt.legend()

def receiver_dts_cdf(folder, r=None, protocols=None,
                     grid=False, figsize=(16, 5),
                     export=False, file_name="dts_cdf.pdf",
                     anonymous=False,
                     hide_dtopt=False,
                     dtopt=None,
                     legend=None,
                     xlabel=True,
                     ylabel=True,
                     t_max=None):
    if legend is None:
        legend = {}
    if r is None:
        r = slice(0, -1)
    p = protocols if protocols is not None else protos
    exp = experiment_config(folder)
    baseline = (exp["delay"] + exp["network_pace"]) * 1000
    if dtopt is not None:
        baseline = dtopt

    fig = plt.figure(figsize=figsize)
    dfs = {}
    for i, proto in enumerate(p):
        df = preprocess("{0}/receiver_{1}.csv".format(folder, proto))[r]
        dfs[proto] = df
        cdf(df["time"], grid=False, label=anonymize(proto, anonymous).upper(),
            color=colors[proto], linestyle=linestyles[proto])
    if xlabel:
        plt.xlabel("E2E Delivery Time [ms]")
    if t_max is not None:
        plt.xlim([baseline*0.9,t_max*1.1])
    if ylabel:
        plt.ylabel("CDF")
    if not hide_dtopt:
        plt.axvline(x=baseline, color=colors["line"], linestyle=linestyles["opt"], linewidth=opt_linewidth, label="$DT_{opt}$")
    if legend is not False:
        plt.legend(**legend)
    if grid:
        plt.grid()

    plt.yticks(np.arange(0.0, 1.1, 0.5))

    if export and file_name is not None:
        fig.savefig(file_name)
    return dfs

def plot_dts(filename, proto, r=None,
             anonymous=False,
             marker="+",
             color="black",
             hide_tcp_cca=False,
             use_icc=False,
             legend=None):
    if legend is None:
        legend = {}
    if r is None:
        r = slice(0, -1)
    df = preprocess(filename)[r]
    plt.scatter(df.index, df["time"],
                label=anonymize(proto, anonymous, hide_tcp_cca=hide_tcp_cca, use_icc=use_icc).upper(),
                marker=marker, color=color, s=scatter_dot_size, linewidths=scatter_dot_linewidths)
    if legend is not False:
        plt.legend(**legend)
    return df

def receiver_dts_timeseries(folder, r=None, protocols=None,
                            grid=False, figsize=(16, 9),
                            export=False, file_name="dts.pdf",
                            anonymous=False,
                            dtopt=None,
                            hide_dtopt=False,
                            hide_tcp_cca=False,
                            ylim=None,
                            theoretical=False,
                            legend=None,
                            ylabel=True):
    if legend is None:
        legend = { "loc": "upper center"}
    if r is None:
        r = slice(0, -1)
    p = protocols if protocols is not None else protos
    exp = experiment_config(folder)
    baseline = (exp["delay"] + exp["network_pace"]) * 1000
    if dtopt is not None:
        baseline = dtopt

    fig = plt.figure(figsize=figsize)
    dfs = {}
    for i, proto in enumerate(p):
        df = plot_dts("{0}/receiver_{1}.csv".format(folder, proto), proto, r,
                 anonymous, marker=markers[proto], color=colors[proto], hide_tcp_cca=hide_tcp_cca, use_icc=theoretical, legend=legend)
        dfs[proto] = df
    plt.xlabel("Rounds")
    if ylabel:
        plt.ylabel("E2E Delivery Time [ms]")
    if not hide_dtopt:
        opt_lbl="Theoretical Minimum" if theoretical else "$DT_{opt}$"
        plt.axhline(y=baseline, color=colors["line"], linestyle=linestyles["opt"], linewidth=opt_linewidth, label=opt_lbl)
    if legend is not False:
        plt.legend(**legend)
    if ylim is not None:
        plt.ylim(ylim)
    if grid:
        plt.grid()
    plt.semilogy()

    if export and file_name is not None:
        fig.savefig(file_name)
    return dfs

def receiver_paces(folder, r=None, grid=False):
    if r is None:
        r = slice(0, -1)
    fig = plt.figure()
    fig.set_size_inches(16, 9)
    df = preprocess("{}/receiver_prrt.csv".format(folder))[r]
    for j, name in enumerate(pace_columns):
        plt.scatter(df.index, df[name], label=name, marker=all_markers[j],
                    color=colors[name], s=scatter_dot_size, linewidths=scatter_dot_linewidths)
    plt.xlabel("Round Number")
    plt.ylabel("Pace [ms]")
    if grid:
        plt.grid()
    plt.legend()
    return df

analyze/util.py

0 → 100644
+108 −0
Original line number Diff line number Diff line
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

from matplotlib import rcParams
plt.rc("figure", autolayout=True)

SMALL_SIZE = 18
MEDIUM_SIZE = 20
BIGGER_SIZE = 24

plt.rc('font', size=SMALL_SIZE)          # controls default text sizes
plt.rc('axes', titlesize=SMALL_SIZE)     # fontsize of the axes title
plt.rc('axes', labelsize=MEDIUM_SIZE)    # fontsize of the x and y labels
plt.rc('xtick', labelsize=SMALL_SIZE)    # fontsize of the tick labels
plt.rc('ytick', labelsize=SMALL_SIZE)    # fontsize of the tick labels
plt.rc('legend', fontsize=MEDIUM_SIZE)    # legend fontsize
plt.rc('figure', titlesize=BIGGER_SIZE)  # fontsize of the figure title

protos = ["tcp-cubic", "tcp-bbr", "prrt"]
all_markers = ["*", "+", "x", "d", "o", "v", "^", "<"]
markers = {
    "prrt": "*",
    "tcp-cubic": "s",
    "tcp-bbr": ".",
    "tcp-cubic-u": "s",
    "tcp-bbr-u": "d"
}
all_colors = ["green","blue","orange","purple","red","pink","yellow","black"]

colors = {
    "prrt": "#E69F00",
    "tcp-bbr": "#009E73",
    "tcp-bbr-u": "#56B4E9",
    "tcp-cubic": "#CC79A7",
    "tcp-cubic-u": "#D55E00",
    "line": "#000000"
}
linestyles = {
    "prrt": "--",
    "tcp-cubic": "-.",
    "tcp-cubic-u": "-.",
    "tcp-bbr": ":",
    "tcp-bbr-u": ":",
    "opt": "--",
    "opt2": "-."
}
scatter_dot_size = 40
scatter_dot_linewidths=1
cdf_linewidth=4
opt_linewidth=4

def anonymize(proto, anonymous, hide_tcp_cca=False, use_icc=False):
    if anonymous and proto == "prrt":
        return "icc" if use_icc else "icp"
    if hide_tcp_cca:
        return proto.replace("-cubic", "").replace("-bbr", "")
    return proto

def cdf(values, ax=None, grid=False, **kwargs):
    if ax is None:
        ax = plt

    if not "linestyle" in kwargs:
        kwargs["linestyle"] = "-"

    s = np.sort(values)
    ax.semilogx(s, np.searchsorted(s, s, side='right') / len(s), linewidth=cdf_linewidth, **kwargs)

def experiment_config(folder):
    exp = pd.read_csv("{}/experiment.csv".format(folder))
    size = exp.at[0,"Size"]
    delay = exp.at[0,"Delay"]
    jitter = exp.at[0,"Jitter"]
    rate = exp.at[0,"Rate"]
    bdp = exp.at[0,"BDP"]
    sndbuf = exp.at[0,"SNDBUF"]
    rcvbuf = exp.at[0,"RCVBUF"]
    rounds = exp.at[0,"Rounds"]
    return {
        "delay": delay,
        "jitter": jitter,
        "loss": "{:.2f}%".format(exp.at[0,"Loss"] * 100),
        "rate": rate,
        "network_pace": (size * 8) / (rate),
        "size": size,
        "bdp" : bdp,
        "rcvbuf" : rcvbuf,
        "sndbuf" : sndbuf,
        "rounds": rounds,
        "app_send_delay": exp.at[0,"APP_SEND_PACE"],
        "app_send_jitter": exp.at[0,"APP_SEND_JITTER"],
        "app_recv_delay": exp.at[0,"APP_RECV_PACE"],
        "app_recv_jitter": exp.at[0,"APP_RECV_JITTER"],
        "app_send_rate": exp.at[0,"Size"] / exp.at[0,"APP_SEND_PACE"] if exp.at[0,"APP_SEND_PACE"] != 0 else np.inf,
        "app_recv_rate": exp.at[0,"Size"] / exp.at[0,"APP_RECV_PACE"] if exp.at[0,"APP_RECV_PACE"] != 0 else np.inf,
        #"btlbuf": exp.at[0,"BTLBUF"]
    }

def duration_inflate(dfs, proto, exp, length):
    last_time = dfs[proto].iloc[-1]["SendT"]
    conf = experiment_config(exp)
    opt = conf["app_recv_delay"] * length * 1000
    return [proto, last_time/1000, opt/1000]

def experiment_duration_inflation(protos, dfs, exp, length):
    rows = [duration_inflate(dfs, proto, exp, length) for proto in protos]
    return pd.DataFrame(rows,columns=["Proto","EXP_ACT [ms]","EXP_OPT [ms]"]).set_index("Proto")
Loading