Commit e5fd2741 authored by Andreas Schmidt's avatar Andreas Schmidt

+= thesis AS fixes

parent cd40ae35
#define XLAP
#include "xlap.h" #include "xlap.h"
......
...@@ -3,15 +3,14 @@ import numpy as np ...@@ -3,15 +3,14 @@ import numpy as np
from .util import cdf, extract_durations from .util import cdf, extract_durations
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
def multi_cdf(dfs, config, export=False, file_name="CDF.pdf"): def multi_cdf(dfs, config, export=False, file_name="CDF.pdf", figsize= (4,4), cols=3, colors=None):
durations = [x + "_D" for x in extract_durations(config)] durations = extract_durations(config)
durations.remove("EndToEnd_D") durations.remove("EndToEnd")
cols = 3
rows = int(math.ceil(len(durations) / cols)) rows = int(math.ceil(len(durations) / cols))
items = len(durations) items = len(durations)
fig, axes = plt.subplots(nrows=rows, ncols=cols) fig, axes = plt.subplots(nrows=rows, ncols=cols)
fig.set_size_inches(4 * cols, 4 * rows, forward=True) fig.set_size_inches(figsize[0] * cols, figsize[1] * rows, forward=True)
names = [] names = []
for df in dfs: for df in dfs:
...@@ -22,16 +21,19 @@ def multi_cdf(dfs, config, export=False, file_name="CDF.pdf"): ...@@ -22,16 +21,19 @@ def multi_cdf(dfs, config, export=False, file_name="CDF.pdf"):
ax = axes[idx // cols, idx % cols] ax = axes[idx // cols, idx % cols]
else: else:
ax = axes[idx] ax = axes[idx]
for df in dfs: for i, df in enumerate(dfs):
cdf(df[duration], grid=True, ax=ax) kwargs = dict()
if colors is not None:
kwargs["color"] = colors[i]
cdf(df[duration + "_D"], grid=True, ax=ax, **kwargs)
if(idx == 0): if(idx == 0):
ax.legend(names) ax.legend(names)
ax.set_ylabel("CDF")
ax.set_xlabel("{} [us]".format(duration)) ax.set_xlabel("{} [us]".format(duration))
ax.set_ylabel("CDF")
plt.subplots_adjust(wspace=0.3,hspace=0.3) plt.subplots_adjust(wspace=0.3,hspace=0.3)
plt.tight_layout()
if export and file_name is not None: if export and file_name is not None:
fig.savefig(file_name) fig.savefig(file_name)
plt.tight_layout()
plt.show() plt.show()
...@@ -6,50 +6,52 @@ from xlap.analyse.util import extract_durations ...@@ -6,50 +6,52 @@ from xlap.analyse.util import extract_durations
def corr(df, duration, grid=False, ax=None, color="black", marker="+"): def corr(df, duration, grid=False, ax=None, color="black", marker="+"):
df.plot.scatter(ax=ax, df.plot.scatter(ax=ax,
y="EndToEnd_D", y="EndToEnd_D",
x=duration, x=duration + "_D",
grid=grid, grid=grid,
loglog=True, loglog=True,
marker=marker, marker=marker,
color=color) color=color)
def corr_multi(dfs, duration, **kwargs): def corr_multi(dfs, duration, colors=None, **kwargs):
names = [] if colors is None:
for df in dfs: colors = ["green","blue","orange"]
names.append(df.name) markers = ["v", "^", ">", "<"]
colors = ["green","blue","orange","purple","red","pink"]
markers = ["v", "^", ">", "<", "+"]
for idf, df in enumerate(dfs): for idf, df in enumerate(dfs):
corr(df, duration, color=colors[idf % len(colors)], corr(df, duration, color=colors[idf % len(colors)],
marker=markers[idf % len(markers)], **kwargs) marker=markers[idf % len(markers)], **kwargs)
if len(names) > 1:
kwargs["ax"].legend(names)
kwargs["ax"].set_xlabel("{} [us]".format(duration)) kwargs["ax"].set_xlabel("{} [us]".format(duration))
def multi_correlation(dfs, config, export=False, file_name="MultiCorrelation.pdf"): def multi_correlation(dfs, config, export=False, file_name="MultiCorrelation.pdf", figsize=(5.5,5.5), cols=2, colors=None, **kwargs):
durations = [x + "_D" for x in extract_durations(config)] durations = extract_durations(config)
durations.remove("EndToEnd_D") durations.remove("EndToEnd")
cols = 2
rows = int(math.ceil(len(durations) / cols)) rows = int(math.ceil(len(durations) / cols))
items = len(durations) items = len(durations)
fig, axes = plt.subplots(nrows=rows, ncols=cols) fig, axes = plt.subplots(nrows=rows, ncols=cols)
fig.set_size_inches(5.5 * cols, 5.5 * rows, forward=True) fig.set_size_inches(figsize[0] * cols, figsize[1] * rows, forward=True)
names = []
for df in dfs:
if hasattr(df, "name"):
names.append(df.name)
for idx, duration in enumerate(durations): for idx, duration in enumerate(durations):
if items > cols: if items > cols:
ax = axes[idx // cols, idx % cols] ax = axes[idx // cols, idx % cols]
else: else:
ax = axes[idx] ax = axes[idx]
corr_multi(dfs, duration, grid=True, ax=ax) corr_multi(dfs, duration, colors=colors, grid=True, ax=ax)
if len(names) > 1 and idx == 0:
ax.legend(names)
ax.set_ylabel("EndToEnd" if idx == 0 else "")
plt.subplots_adjust(wspace=0.3,hspace=0.3) plt.subplots_adjust(wspace=0.3,hspace=0.3)
plt.tight_layout()
if export and file_name is not None: if export and file_name is not None:
fig.savefig(file_name) fig.savefig(file_name)
plt.tight_layout()
plt.show() plt.show()
def correlation(df, config, export=False, file_name="SingleCorrelation.pdf"): def correlation(df, config, export=False, file_name="SingleCorrelation.pdf", **kwargs):
return multi_correlation([df], config, export, file_name) return multi_correlation([df], config, export, file_name, **kwargs)
...@@ -3,12 +3,13 @@ import matplotlib.pyplot as plt ...@@ -3,12 +3,13 @@ import matplotlib.pyplot as plt
from xlap.analyse.util import get_outlier_threshold, extract_durations, box from xlap.analyse.util import get_outlier_threshold, extract_durations, box
def jitter_causes(df, durations, export=False, file_name=None): def jitter_causes(df, config, export=False, file_name=None, figsize=(8,3), color="black"):
stats = df["EndToEnd_D"].describe() stats = df["EndToEnd_D"].describe()
durations = extract_durations(config)
threshold = get_outlier_threshold(stats) threshold = get_outlier_threshold(stats)
outliers = df[df["EndToEnd_D"] > threshold] outliers = df[df["EndToEnd_D"] > threshold]
reasons = [d + "_D" for d in durations.keys()] reasons = [d + "_D" for d in durations if d != "EndToEnd"]
df_reasons = pd.DataFrame(index=outliers.index) df_reasons = pd.DataFrame(index=outliers.index)
...@@ -18,17 +19,17 @@ def jitter_causes(df, durations, export=False, file_name=None): ...@@ -18,17 +19,17 @@ def jitter_causes(df, durations, export=False, file_name=None):
df_reasons[reason] = outliers[outliers[reason] > reason_threshold].notnull() df_reasons[reason] = outliers[outliers[reason] > reason_threshold].notnull()
df_sum = df_reasons.sum().sort_values(ascending=False) df_sum = df_reasons.sum().sort_values(ascending=False)
ax = df_sum.plot.bar(x="Reason", y="Frequency", rot=45, grid=True, legend=False, color="black") ax = df_sum.plot.bar(x="Reason", y="Frequency", rot=45, grid=True, legend=False, color=color)
fig = ax.get_figure() fig = ax.get_figure()
plt.ylabel("Frequency") plt.ylabel("Frequency")
ax.set_xticklabels(list(map(lambda x: x.get_text().replace("_D", ""), ax.get_xticklabels()))) ax.set_xticklabels(list(map(lambda x: x.get_text().replace("_D", ""), ax.get_xticklabels())))
fig.set_size_inches(8, 3, forward=True) fig.set_size_inches(figsize[0], figsize[1])
plt.tight_layout()
if export: if export:
fig.savefig(file_name) fig.savefig(file_name)
print("Outliers:", len(outliers), ";", "Threshold[us]:", threshold) print("Outliers:", len(outliers), ";", "Threshold[us]:", threshold)
def trace_jitter(data_frame, config=None, threshold=None, export=False, file_name=None, figsize=(8, 4.5)):
def trace_jitter(data_frame, config=None, threshold=None, export=False, file_name=None):
""" """
Displays (and saves) a stacked boxplot of durations. Displays (and saves) a stacked boxplot of durations.
""" """
...@@ -37,8 +38,10 @@ def trace_jitter(data_frame, config=None, threshold=None, export=False, file_nam ...@@ -37,8 +38,10 @@ def trace_jitter(data_frame, config=None, threshold=None, export=False, file_nam
if threshold is None: if threshold is None:
threshold = get_outlier_threshold(data_frame["EndToEnd_D"].describe()) threshold = get_outlier_threshold(data_frame["EndToEnd_D"].describe())
df_no_outliers = data_frame[data_frame["EndToEnd_D"] <= threshold] df_no_outliers = data_frame[data_frame["EndToEnd_D"] <= threshold]
box(df_no_outliers, (0, threshold), export, file_name)
print("{} / {} are no outliers.".format(len(df_no_outliers), len(data_frame)))
fig = plt.gcf() fig = plt.gcf()
fig.set_size_inches(figsize[0], figsize[1])
box(df_no_outliers, (0, threshold), export, file_name, figsize)
print("{} / {} are no outliers.".format(len(df_no_outliers), len(data_frame)))
fig.canvas.set_window_title('Jitter Analysis') fig.canvas.set_window_title('Jitter Analysis')
plt.show() plt.show()
return None
import pandas as pd import pandas as pd
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from scipy.stats.stats import pearsonr from scipy.stats.stats import pearsonr, spearmanr
import numpy as np import numpy as np
import sys import sys
import graphviz import graphviz
class LatencyAnalysis(): class LatencyAnalysis():
def __init__(self, cfg=None, hdb=None): def __init__(self, cfg=None, hdb=None):
plt.rcParams['ps.useafm'] = True
plt.rcParams['pdf.use14corefonts'] = True
plt.rcParams['text.usetex'] = False
plt.rcParams['font.family'] = 'sans-serif'
#plt.rcParams['font.sans-serif'] = 'Latin Modern Sans'
#plt.rcParams['font.monospace'] = 'FreeMono'
self.cfg = cfg self.cfg = cfg
self.hdb = hdb
correlations = [] correlations = []
labels = [] labels = []
...@@ -25,6 +20,28 @@ class LatencyAnalysis(): ...@@ -25,6 +20,28 @@ class LatencyAnalysis():
corr = pd.Series(correlations, index=labels) corr = pd.Series(correlations, index=labels)
self.corr = corr self.corr = corr
def plot_critical_regions(self, figsize=(5,5), export=False, file_name="latency-criticality.pdf"):
"""
plot regions, sorted by latency criticality
"""
hdb = self.hdb
relevant = sorted([x for x in hdb if x['Correlation'] > 0], key=lambda x: -x['Correlation'], reverse=True)
x = np.arange(len(relevant))
correlations = list(map(lambda x: x['Correlation'], relevant))
ticks = list(map(lambda x: "<%s, %s>" % (x['Start'][:-2], x['End'][:-2]), relevant))
fig, ax = plt.subplots(figsize=figsize)
rects = ax.barh(x, correlations, align="center", tick_label="")
autolabel(rects, ax, ticks)
plt.xlabel("Latency Criticality")
plt.tight_layout()
if export:
plt.savefig(file_name)
plt.show()
plt.close()
def _get_thread_for_event(config, e): def _get_thread_for_event(config, e):
...@@ -158,64 +175,15 @@ def autolabel(rects, ax, labels): ...@@ -158,64 +175,15 @@ def autolabel(rects, ax, labels):
# If we can fit the label above the column, do that; # If we can fit the label above the column, do that;
# otherwise, put it inside the column. # otherwise, put it inside the column.
if p_width > 0.50: # arbitrary; 95% looked good to me. if p_width > 0.50: # arbitrary; 95% looked good to me.
#label_position = width - (x_width) + 0.7 label_position = width - (x_width) + 0.75
label_position = width - (x_width * 0.01)
color = "white" color = "white"
align = "right" align = "right"
else: else:
label_position = width + (x_width * 0.002) label_position = width + (x_width * 0.01)
mono = {'family': 'monospace'}
ax.text(label_position, rect.get_y(), labels[i], ha=align, va='bottom', rotation=0, color=color, fontdict=mono)
def _plot_critical_regions(hdb):
"""
plot regions, sorted by latency criticality
"""
relevant = sorted([x for x in hdb if x['Correlation'] > 0], key=lambda x: -x['Correlation'], reverse=True)
x = np.arange(len(relevant))
correlations = list(map(lambda x: x['Correlation'], relevant))
ticks = list(map(lambda x: "<%s,%s>" % (x['Start'][:-2], x['End'][:-2]), relevant))
fig, ax = plt.subplots()
rects = ax.barh(x, correlations, align="center", tick_label="")
autolabel(rects, ax, ticks)
plt.xlabel('Latency criticality')
plt.tight_layout()
plt.savefig("latency-criticality.pdf")
plt.close()
def get_durations(df, config):
hb = []
events = [column for column in df.columns if column.endswith("_T")]
for event1 in df[events]:
for event2 in df[events]:
if str(event1) == str(event2):
continue
if _happens_before(df, event1, event2, config):
hb += [{'Start': str(event1), 'End': str(event2)}]
hdb = [] ax.text(label_position, rect.get_y(), labels[i], ha=align, va='bottom', rotation=0, color=color, family="monospace")
e2e = list(df['EndToEnd_D'])
for event1 in df[events]:
for event2 in df[events]:
if str(event1) == str(event2):
continue
# if _locally_happens_directly_before(df, event1, event2, hb, config):
if _happens_directly_before(df, event1, event2, hb):
# compute the correlation between e2e latency and event1-event2 latency
l3 = list(df[event2] - df[event1])
hdb += [{'Start': str(event1), 'Stop': str(event2), 'Source': 'cfa'}]
return hdb
def get_durations_2(dfs, config):
df = dfs[0] + dfs[1]
return get_durations(df, config)
def analyse(df, config): def analyse(df, config):
hb = [] hb = []
...@@ -240,12 +208,11 @@ def analyse(df, config): ...@@ -240,12 +208,11 @@ def analyse(df, config):
# compute the correlation between e2e latency and event1-event2 latency # compute the correlation between e2e latency and event1-event2 latency
l3 = list(df[event2] - df[event1]) l3 = list(df[event2] - df[event1])
if any(map(lambda x: x != 0, l3)): if any(map(lambda x: x != 0, l3)):
correlation = pearsonr(l3, e2e)[0] correlation = spearmanr(l3, e2e)[0]
else: else:
correlation = 0 correlation = 0
hdb += [{'Start': str(event1), 'End': str(event2), 'Correlation': correlation}] hdb += [{'Start': str(event1), 'End': str(event2), 'Correlation': correlation}]
cfg = _plot_controlflow_graph(df, hdb) cfg = _plot_controlflow_graph(df, hdb)
_plot_critical_regions(hdb)
return LatencyAnalysis(cfg=cfg, hdb=hdb) return LatencyAnalysis(cfg=cfg, hdb=hdb)
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.lines import Line2D
from xlap.analyse.util import extract_durations from xlap.analyse.util import extract_durations
from ipywidgets import interact from ipywidgets import interact
import ipywidgets as widgets import ipywidgets as widgets
colors = {
"sender": "#CA0020",
"receiver": "#0571B0",
"EndToEnd": "black"
}
linestyles = {
"sender": (0,(1,1,3,1,1,1)),
"receiver": (0,(1,1)),
"EndToEnd": (0,())
}
def _create_line(config): def _create_line(config):
tr = config["time_reference"] tr = config["time_reference"]
color = {
"sender": "#AAAAAA",
"receiver": "#888888",
"e2e": "black"
}
def _creator(duration_name): def _creator(duration_name):
if duration_name == "EndToEnd": if duration_name == "EndToEnd":
return [tr["sender"]["Start"] + "_T", tr["receiver"]["Stop"] + "_T", color["e2e"], "EndToEnd"] return [tr["sender"]["Start"] + "_T", tr["receiver"]["Stop"] + "_T", colors["EndToEnd"], linestyles["EndToEnd"], "EndToEnd"]
elif duration_name == "Sender": elif duration_name == "Sender":
return [tr["sender"]["Start"] + "_T", tr["sender"]["Stop"] + "_T", color["sender"], "Sender"] return [tr["sender"]["Start"] + "_T", tr["sender"]["Stop"] + "_T", colors["sender"], linestyles["sender"], "Sender"]
elif duration_name == "Receiver": elif duration_name == "Receiver":
return [tr["receiver"]["Start"] + "_T", tr["receiver"]["Stop"] + "_T", color["receiver"], "Receiver"] return [tr["receiver"]["Start"] + "_T", tr["receiver"]["Stop"] + "_T", colors["receiver"], linestyles["receiver"], "Receiver"]
else: else:
duration = config["durations"][duration_name] duration = config["durations"][duration_name]
return [duration["Start"] + "_T", duration["Stop"] + "_T", color[duration["Source"]], duration_name] return [duration["Start"] + "_T", duration["Stop"] + "_T", colors[duration["Source"]], linestyles[duration["Source"]], duration_name]
return _creator return _creator
def trace(data_frame, config, export=False, file_name="TraceJitter.pdf"): def trace(data_frame, config, export=False, file_name="PacketTrace.pdf", figsize=(8, 4.5), bbox_to_anchor=(1.05, 1), loc=2, t_max=None):
""" """
:param data_frame: :param data_frame:
...@@ -38,7 +48,7 @@ def trace(data_frame, config, export=False, file_name="TraceJitter.pdf"): ...@@ -38,7 +48,7 @@ def trace(data_frame, config, export=False, file_name="TraceJitter.pdf"):
:return: :return:
""" """
fig, ax = plt.subplots(figsize=(8, 4.5)) fig, ax = plt.subplots(figsize=figsize)
plt.grid() plt.grid()
line_creator = _create_line(config) line_creator = _create_line(config)
...@@ -54,23 +64,34 @@ def trace(data_frame, config, export=False, file_name="TraceJitter.pdf"): ...@@ -54,23 +64,34 @@ def trace(data_frame, config, export=False, file_name="TraceJitter.pdf"):
starts = data_frame[series[0]] - base starts = data_frame[series[0]] - base
ends = data_frame[series[1]] - base ends = data_frame[series[1]] - base
plt.hlines(range(n), starts, ends, series[2], linewidths=[5]) plt.hlines(range(n), starts, ends, series[2], series[3], linewidths=[5])
plt.xlabel("Time [us]") plt.xlabel("Time [us]")
if t_max is not None:
ax.set_xlim([0,t_max])
fig.canvas.draw() fig.canvas.draw()
ax.set_yticklabels(series[3]) ax.set_yticklabels(series[4])
ax.yaxis.set_ticks(np.arange(0, n, 1)) ax.yaxis.set_ticks(np.arange(0, n, 1))
sides = ["sender","receiver","EndToEnd"]
handles = list(map(lambda x: Line2D([0], [0], color=colors[x], linestyle=linestyles[x], lw=5, label=x.title() if x != "EndToEnd" else x), sides))
plt.legend(handles=handles,bbox_to_anchor=bbox_to_anchor, loc=loc, borderaxespad=0.)
plt.tight_layout()
if export: if export:
plt.savefig(file_name) plt.savefig(file_name)
plt.show() plt.show()
def traces(df, config): def traces(df, config, figsize=(10, 4.5), global_xaxis=False):
""" """
Display a slider to select sequence numbers and the respective trace. Display a slider to select sequence numbers and the respective trace.
""" """
t_max = None
if global_xaxis:
t_max = df["EndToEnd_D"].max()
@interact(seq_no=widgets.IntSlider(min=1, max=len(df), step=1, value=47)) @interact(seq_no=widgets.IntSlider(min=1, max=len(df), step=1, value=47))
def _f(seq_no): def _f(seq_no):
trace(df.ix[seq_no], config) trace(df.iloc[seq_no], config, figsize=figsize, t_max=t_max)
...@@ -37,7 +37,7 @@ def extract_durations(config): ...@@ -37,7 +37,7 @@ def extract_durations(config):
return ["EndToEnd", "Sender"] + durations_send + ["Receiver"] + durations_recv return ["EndToEnd", "Sender"] + durations_send + ["Receiver"] + durations_recv
def box(data_frame, xlim=None, export=False, file_name=None): def box(data_frame, xlim=None, export=False, file_name=None, figsize=(8, 4.5)):
""" """
Display a boxplot for the durations contained in data_frame. Display a boxplot for the durations contained in data_frame.
:param data_frame: :param data_frame:
...@@ -45,13 +45,13 @@ def box(data_frame, xlim=None, export=False, file_name=None): ...@@ -45,13 +45,13 @@ def box(data_frame, xlim=None, export=False, file_name=None):
:param file_name: :param file_name:
:return: :return:
""" """
ax = data_frame.plot.box(vert=False, grid=True) ax = data_frame.plot.box(vert=False, grid=True,figsize=figsize)
fig = ax.get_figure() fig = ax.get_figure()
ax.set_yticklabels(list(map(lambda x: x.get_text().replace("_D", ""), ax.get_yticklabels()))) ax.set_yticklabels(list(map(lambda x: x.get_text().replace("_D", ""), ax.get_yticklabels())))
plt.xlabel("Time [us]") plt.xlabel("Time [us]")
if xlim is not None: if xlim is not None:
plt.xlim(xlim) plt.xlim(xlim)
fig.set_size_inches(8, 4.5, forward=True) plt.tight_layout()
if export and file_name is not None: if export and file_name is not None:
fig.savefig(file_name) fig.savefig(file_name)
......
...@@ -3,14 +3,10 @@ import argparse ...@@ -3,14 +3,10 @@ import argparse
from xlap.parse import evaluate, parse_config from xlap.parse import evaluate, parse_config
import xlap.analyse.jitter as jitter import xlap.analyse.jitter as jitter
import xlap.analyse.latency as latency import xlap.analyse.latency as latency
import xlap.analyse.diff as difference
import xlap.analyse.e2e as e2e
tasks = { tasks = {
"jitter": None, "jitter": None,
"latency": None, "latency": None,
"difference": None,
"e2e": None,
"capture": None "capture": None
} }
...@@ -45,30 +41,10 @@ def main(): ...@@ -45,30 +41,10 @@ def main():
f.write("\n") f.write("\n")
else: else:
print(output) print(output)
elif command == "e2e":
khz1 = 2000000
khz2 = 3000000
path="../publications/rtn-18/eval/20180419_energy/"
df_data1 = evaluate(path+"sender-"+str(khz1)+".csv", path+"receiver-"+str(khz1)+".csv", config=config, kind=0)
df_data2 = evaluate(path+"sender-"+str(khz2)+".csv", path+"receiver-"+str(khz2)+".csv", config=config, kind=0)
e2e.analyse(df_data1, df_data2, config)
elif command == "latency": elif command == "latency":
df_data = evaluate(data_files["sender"], data_files["receiver"], config=config, kind=0) df_data = evaluate(data_files["sender"], data_files["receiver"], config=config, kind=0)
a = latency.analyse(df_data, config)