2024-05-28 11:44:38 +09:00

138 lines
5.9 KiB
Python

import pandas as pd
import seaborn
from matplotlib import pyplot as plt
from adversary import NodeState
from config import Config
from simulation import Simulation
class Analysis:
def __init__(self, sim: Simulation, config: Config):
self.sim = sim
self.config = config
def run(self):
message_size_df = self.message_size_distribution()
self.bandwidth(message_size_df)
self.messages_emitted_around_interval()
self.messages_in_node_over_time()
# self.node_states()
def bandwidth(self, message_size_df: pd.DataFrame):
dataframes = []
nonzero_egresses = []
nonzero_ingresses = []
for egress_bandwidths, ingress_bandwidths in zip(self.sim.p2p.measurement.egress_bandwidth_per_time,
self.sim.p2p.measurement.ingress_bandwidth_per_time):
rows = []
for node in self.sim.p2p.nodes:
egress = egress_bandwidths[node] / 1024.0
ingress = ingress_bandwidths[node] / 1024.0
rows.append((node.id, egress, ingress))
if egress > 0:
nonzero_egresses.append(egress)
if ingress > 0:
nonzero_ingresses.append(ingress)
df = pd.DataFrame(rows, columns=["node_id", "egress", "ingress"])
dataframes.append(df)
times = range(len(dataframes))
df = pd.concat([df.assign(Time=time) for df, time in zip(dataframes, times)], ignore_index=True)
df = df.pivot(index="Time", columns="node_id", values=["egress", "ingress"])
plt.figure(figsize=(12, 6))
for column in df.columns:
marker = "x" if column[0] == "ingress" else "o"
plt.plot(df.index, df[column], marker=marker, label=column[0])
plt.title("Egress/ingress bandwidth of each node over time")
plt.xlabel("Time")
plt.ylabel("Bandwidth (KiB/s)")
plt.ylim(bottom=0)
# Customize the legend to show only 'egress' and 'ingress' regardless of node_id
handles, labels = plt.gca().get_legend_handles_labels()
by_label = dict(zip(labels, handles))
plt.legend(by_label.values(), by_label.keys())
plt.grid(True)
# Adding descriptions on the right size of the plot
egress_series = pd.Series(nonzero_egresses)
ingress_series = pd.Series(nonzero_ingresses)
desc = (
f"message: {message_size_df["message_size"].mean():.0f} bytes\n"
f"{self.config.description()}\n\n"
f"[egress(>0)]\nmean: {egress_series.mean():.2f} KiB/s\nmax: {egress_series.max():.2f} KiB/s\n\n"
f"[ingress(>0)]\nmean: {ingress_series.mean():.2f} KiB/s\nmax: {ingress_series.max():.2f} KiB/s"
)
plt.text(1.02, 0.5, desc, transform=plt.gca().transAxes, verticalalignment="center", fontsize=12)
plt.subplots_adjust(right=0.8) # Adjust layout to make room for the text
plt.show()
def message_size_distribution(self) -> pd.DataFrame:
df = pd.DataFrame(self.sim.p2p.adversary.message_sizes, columns=["message_size"])
print(df.describe())
return df
def messages_emitted_around_interval(self):
df = pd.DataFrame(
[(node.id, cnt, node.id < len(self.sim.config.mixnet.real_message_prob_weights))
for node, cnt in self.sim.p2p.adversary.senders_around_interval.items()],
columns=["node_id", "msg_count", "expected"]
)
plt.figure(figsize=(10, 6))
seaborn.barplot(data=df, x="node_id", y="msg_count", hue="expected", palette={True: "red", False: "blue"})
plt.title("Messages emitted around the promised interval")
plt.xlabel("Sender Node ID")
plt.ylabel("Msg Count")
plt.legend(title="expected")
plt.show()
def messages_in_node_over_time(self):
dataframes = []
for i, msgs_in_node in enumerate(self.sim.p2p.adversary.msgs_in_node_per_window):
time = i * self.config.adversary.io_window_moving_interval
df = pd.DataFrame([(time, node.id, msg_cnt, sender_cnt) for node, (msg_cnt, sender_cnt) in msgs_in_node.items()],
columns=["time", "node_id", "msg_cnt", "sender_cnt"])
if not df.empty:
dataframes.append(df)
df = pd.concat(dataframes, ignore_index=True)
df_pivot = df.pivot(index="time", columns="node_id", values="msg_cnt")
plt.figure(figsize=(12, 6))
for column in df_pivot.columns:
plt.plot(df_pivot.index, df_pivot[column], marker=None, label=column)
plt.title("Messages in each node over time")
plt.xlabel("Time")
plt.ylabel("Msg Count")
plt.ylim(bottom=0)
plt.grid(True)
plt.tight_layout()
plt.show()
df_pivot = df.pivot(index="time", columns="node_id", values="sender_cnt")
plt.figure(figsize=(12, 6))
for column in df_pivot.columns:
plt.plot(df_pivot.index, df_pivot[column], marker=None, label=column)
plt.title("Senders of messages in each node over time")
plt.xlabel("Time")
plt.ylabel("Sender Count")
plt.ylim(bottom=0)
plt.grid(True)
plt.tight_layout()
plt.show()
def node_states(self):
rows = []
for time, node_states in self.sim.p2p.adversary.node_states.items():
for node, state in node_states.items():
rows.append((time, node.id, state))
df = pd.DataFrame(rows, columns=["time", "node_id", "state"])
plt.figure(figsize=(10, 6))
seaborn.scatterplot(data=df, x="time", y="node_id", hue="state",
palette={NodeState.SENDING: "red", NodeState.RECEIVING: "blue"})
plt.title("Node states over time")
plt.xlabel("Time")
plt.ylabel("Node ID")
plt.legend(title="state")
plt.show()