Skip to content

Commit

Permalink
Plot bottleneck separately
Browse files Browse the repository at this point in the history
  • Loading branch information
ccanel committed Feb 7, 2024
1 parent 36aa77a commit 085bf0f
Showing 1 changed file with 96 additions and 8 deletions.
104 changes: 96 additions & 8 deletions unfair/scripts/eval.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def plot_lines(
legend_ncol=1,
figsize=FIGSIZE,
):
"""An element in lines is a tuple of the form: ( label, ( xs, ys ) )"""
plt.figure(figsize=figsize)
plt.grid(True)

Expand Down Expand Up @@ -202,7 +203,14 @@ def plot_lines(


def plot_flows_over_time(
exp, out_flp, flw_to_pkts, flw_to_cca, sender_fairness=False, flw_to_sender=None
exp,
out_flp,
flw_to_pkts,
flw_to_cca,
sender_fairness=False,
flw_to_sender=None,
xlim=None,
bottleneck_Mbps=None,
):
lines = []
initial_time = min(
Expand Down Expand Up @@ -289,6 +297,24 @@ def plot_flows_over_time(
else:
lines = [(throughputs, flw_to_cca[flw]) for (throughputs, flw) in lines]

colors = [COLORS_MAP["blue"], COLORS_MAP["red"]] if sender_fairness else None

# If we are supposed to mark the bottleneck bandwidth, then create a horizontal
# line and prepend it to the lines.
if bottleneck_Mbps is not None:
start_time_s = min(xs[0] for _, (xs, _) in lines)
end_time_s = max(xs[-1] for _, (xs, _) in lines)
lines.insert(
0,
(
"Bottleneck",
([start_time_s, end_time_s], [bottleneck_Mbps, bottleneck_Mbps]),
),
)
# Make the line orange.
if colors is not None:
colors.insert(0, COLORS_MAP["orange"])

plot_lines(
lines,
"time (s)",
Expand All @@ -298,7 +324,7 @@ def plot_flows_over_time(
out_flp,
legendloc=("center" if sender_fairness else "upper right"),
linewidth=(2 if sender_fairness else 1),
colors=([COLORS_MAP["blue"], COLORS_MAP["red"]] if sender_fairness else None),
colors=colors,
bbox_to_anchor=((0.5, 1.15) if sender_fairness else None),
legend_ncol=(2 if sender_fairness else 1),
figsize=(5, 2.6),
Expand Down Expand Up @@ -473,6 +499,7 @@ def parse_opened_exp(
flw_to_pkts = utils.drop_packets_after_first_flow_finishes(flw_to_pkts)

# Highest receiver port.
# TODO: Need to refactor this to just drop data from before the last flow starts.
late_flows_port = max(flw[6] for flw in params["flowsets"])
late_flws = [
flw for flw in flws if flw[1] == late_flows_port and len(flw_to_pkts[flw]) > 0
Expand Down Expand Up @@ -506,10 +533,6 @@ def parse_opened_exp(
{flw: flw_to_pkts[flw] for flw in flws},
flw_to_cca,
)
# TODO: Add markers for bottleneck
# Need to get bottleneck info in here
# So, need to get config file in here?
# Bottleneck info is not in the

# Remove data from before the late flows start.
for flw, pkts in flw_to_pkts.items():
Expand Down Expand Up @@ -539,7 +562,71 @@ def parse_opened_exp(
if exp.use_bess:
# Determine a mapping from class to flows in that class.
class_to_flws = collections.defaultdict(list)
classifier = CLASSIFIERS[CATEGORIES[params["category"]][0]]
category = params["category"]
classifier = CLASSIFIERS[CATEGORIES[category][0]]

# If the category is multibottleneck, then we need to break down time into
# regions based on the bottleneck.
if category == "multibottleneck":
# Dict mapping time to a list of bottleneck events at that time.
bottleneck_events = collections.defaultdict(dict)
# Add all bottleneck events to unified list. Replace rates of 0
# (no bottleneck) with the BESS bandwidth.
for sender, bottleneck_schedule in params["sender_bottlenecks"].items():
for bottleneck_event in bottleneck_schedule:
rate = bottleneck_event["rate_Mbps"]
bottleneck_events[bottleneck_event["time_s"]][sender] = (
rate if rate != 0 else params["bess_bw_Mbps"]
)
# Go through the list of events and populate the rate values of any senders
# that did not change.
times_s = sorted(bottleneck_events.keys())
for idx, time_s in enumerate(times_s[:-1]):
for sender, rate in bottleneck_events[time_s].items():
if sender not in bottleneck_events[times_s[idx + 1]]:
bottleneck_events[times_s[idx + 1]][sender] = rate
# Sort bottleneck events by time.
bottleneck_events = sorted(bottleneck_events.items(), key=lambda x: x[0])

# Create range-based bottleneck situations.
end_time_s = max(flowset["end_time_s"] for flowset in params["flowsets"])
bottleneck_situations = []
for idx, bottleneck in enumerate(bottleneck_events):
time_s, configs = bottleneck
if idx == len(bottleneck_events) - 1:
next_time_s = end_time_s
else:
next_time_s = bottleneck_events[idx + 1][0]
bottleneck_situations.append((time_s, next_time_s, configs))
# Num bottleneck events
num_bottlenecks_situations = len(bottleneck_situations)
assert (
num_bottlenecks_situations == 3
), f"Expected 3 bottleneck situations, but found {num_bottlenecks_situations}."

for bneck_start_s, bneck_end_s, bneck_config in bottleneck_situations:
# Plot all flows (shared bottleneck).
plot_flows_over_time(
exp,
out_flp[:-4] + "_bneckbess.pdf",
flw_to_pkts,
flw_to_cca,
sender_fairness,
flw_to_sender,
xlim=(bneck_start_s, bneck_end_s),
bottleneck_Mbps=params["bess_bw_Mbps"],
)
# Plot each sender-side bottleneck separately.
for sender, flws in sender_to_flws.items():
plot_flows_over_time(
exp,
out_flp[:-4] + f"_bneck{sender}.pdf",
{flw: flw_to_pkts[flw] for flw in flws},
flw_to_cca,
xlim=(bneck_start_s, bneck_end_s),
bottleneck_Mbps=bneck_config[sender],
)

for flw in params["flowsets"]:
flow_class = classifier(flw)
for sender_port in flw[5]:
Expand Down Expand Up @@ -1221,11 +1308,12 @@ def eval_shared(args, our_label, matched):


def eval_multibottleneck(args, our_label, matched):
"""Generate graphs for the multibottleneck flows experiments."""
raise NotImplementedError()


def eval_background(args, our_label, matched):
"""Generate graphs for the simple background flows experiments."""
"""Generate graphs for the background flows experiments."""
matched_results = {}
for enabled_exp, (disabled_results, enabled_results) in matched.items():
(
Expand Down

0 comments on commit 085bf0f

Please sign in to comment.