Handle multiple nodes in cluster

This commit is contained in:
Pascal Engélibert 2026-06-29 16:29:47 +02:00
commit e6719ab571
5 changed files with 295 additions and 237 deletions

View file

@ -1,15 +1,4 @@
# TLS
### WolfSSL
```bash
git clone https://github.com/wolfSSL/wolfssl --depth 1
cd wolfssl
sh autogen.sh
./configure --enable-all --enable-all-crypto --disable-shared --prefix=/opt/wolfssl-rs/
make
sudo make install
```
# TLS Energy measurement
## Reproduce
@ -159,7 +148,7 @@ https://api.grid5000.fr/stable/sites/nancy/metrics?nodes=gros-69&metrics=bmc_nod
```bash
python plots.py summary results/g5k/summary X results/pi3/summary pi3 results/i5/summary i5 results/core2/summary C2
python plots.py log2 results/core2/impl C2 results/pi3/impls \$\\\\pi\$3 results/i5/impls i5
python plots.py log2 results/core2/impls results/pi3/impls results/i5/impls
python plots.py stab results/pi3/stability \$\\\\pi\$3 results/core2/stability C2 results/i5/stability i5 results/g5k/stability X
```

48
exp.py
View file

@ -131,9 +131,9 @@ CONFIGS = {
True,
],
"records": [
#{ "filename": "wp2", "repeat": 10000, "time": 600, "reproduce": 1 },
{ "filename": "yt2-ads", "repeat": 10000, "time": 600, "reproduce": 1 },
{ "filename": "yt2-ublock", "repeat": 10000, "time": 600, "reproduce": 1 },
{ "filename": "wp2", "repeat": 10000, "time": 600, "reproduce": 1 },
{ "filename": "yt2-ads", "repeat": 10000, "time": 1200, "reproduce": 1 },
{ "filename": "yt2-ublock", "repeat": 10000, "time": 1200, "reproduce": 1 },
#{ "filename": "wp2", "repeat": 10000, "time": 300, "reproduce": 100 },
],
"repo_dir": "/home/tuxmain/reps/tlsbench",
@ -166,17 +166,17 @@ CONFIGS = {
#"debug",
],
"sides": [
"client",
#"client",
"server",
],
"tls": [
False,
#True,
#False,
True,
],
"records": [
{ "filename": "wp2", "repeat": 10000, "time": 300, "reproduce": 3 },
{ "filename": "yt2-ads", "repeat": 10000, "time": 300, "reproduce": 3 },
{ "filename": "yt2-ublock", "repeat": 10000, "time": 300, "reproduce": 3 },
#{ "filename": "wp2", "repeat": 10000, "time": 600, "reproduce": 1 },
{ "filename": "yt2-ads", "repeat": 10000, "time": 600, "reproduce": 1 },
{ "filename": "yt2-ublock", "repeat": 10000, "time": 600, "reproduce": 1 },
#{ "filename": "test", "repeat": 1, "time": 10 },
#{ "filename": "wp2", "repeat": 10000, "time": 300, "reproduce": 100 },
],
@ -348,13 +348,13 @@ CERT_SIGN_ALGS = [
"rsa2048", "rsa3072", "rsa4096", # widely used
]
IMPLS = [
"aws-lc", # Amazon's crypto widely used in Rust stuff
#"aws-lc", # Amazon's crypto widely used in Rust stuff
#"boring", # Google's fork of OpenSSL used in Chrome and Android
#"graviola", # New crypto in Rust
#"openssl", # widely used
"openssl", # widely used
#"openssl-static",
#"ring", # used in most Rust stuff
#"symcrypt", # Microsoft's crypto
"ring", # used in most Rust stuff
"symcrypt", # Microsoft's crypto
]
# Symmetric ciphers
# They also allow to choose the TLS version.
@ -785,6 +785,9 @@ def run_exp(config, only_record=None, idle=False, shutdown=False, debug=False):
if idle:
print("Measuring idle...")
remote_bytes_in, remote_bytes_out = get_net_stat(ssh)
controller_bytes_in, controller_bytes_out = (0, 0)
if config["measure_both"]:
controller_bytes_in, controller_bytes_out = get_net_stat(None)
energy = 0
energy_rapl = 0
if config["wattmeter"]:
@ -803,8 +806,13 @@ def run_exp(config, only_record=None, idle=False, shutdown=False, debug=False):
if config["rapl"]:
new_energy_rapl = get_rapl_energy(ssh, remote_path)
new_remote_bytes_in, new_remote_bytes_out = get_net_stat(ssh)
new_controller_bytes_in, new_controller_bytes_out = (0, 0)
if config["measure_both"]:
new_controller_bytes_in, new_controller_bytes_out = get_net_stat(None)
remote_bytes_in_diff = new_remote_bytes_in - remote_bytes_in
remote_bytes_out_diff = new_remote_bytes_out - remote_bytes_out
controller_bytes_in_diff = new_controller_bytes_in - controller_bytes_in
controller_bytes_out_diff = new_controller_bytes_out - controller_bytes_out
energy_diff = new_energy - energy
energy_rapl_diff = new_energy_rapl - energy_rapl
time_diff = end - start
@ -812,6 +820,9 @@ def run_exp(config, only_record=None, idle=False, shutdown=False, debug=False):
try:
with open(logfile_path, "a") as logfile:
logfile.write(f"{target} idle - - - - - - - - - {start} {end} {time_diff} 0 {remote_bytes_in_diff} {remote_bytes_out_diff} {energy_diff} {energy_rapl_diff} -\n")
if config["measure_both"]:
controller_target = config["controller_target"]
logfile.write(f"{controller_target} idle - - - - - - - - - {start} {end} {time_diff} 0 {controller_bytes_in_diff} {controller_bytes_out_diff} 0 0 -\n")
logfile.close()
break
except Exception as e:
@ -1098,6 +1109,7 @@ Run options:
--idle Also measure when idle
--shutdown Shutdown host and target when finished
--debug Print netreplay's debug
-f <file> JSON file to update config
""".format(
sig_algs = " ".join(CERT_SIGN_ALGS),
configs = " ".join([i for i in CONFIGS]),
@ -1121,6 +1133,16 @@ Run options:
update_certs(config)
elif opt == "run":
config = CONFIGS[sys.argv[2]]
add_config_file = getargv("-f")
if add_config_file:
import json
f = open(add_config_file, "r")
j = json.load(f)
f.close()
for k in j:
config[k] = j[k]
if "--count" in sys.argv:
exps = 0
for expname in config["experiments"]:

View file

@ -48,6 +48,9 @@ def insert_wh_into_logfile(path, site, user, psw):
logs = []
records = {}
for line in lines[1:]:
if line[0] in "#\n":
logs.append({"comment": line})
continue
cols = line.removesuffix("\n").split(" ")
log = {}
for col in range(len(cols)):
@ -61,6 +64,9 @@ def insert_wh_into_logfile(path, site, user, psw):
outfile = open(path+"-wh", "w")
outfile.write(lines[0])
for log in logs:
if "comment" in log:
outfile.write(log["comment"])
continue
line = ""
for col in colnames:
if line != "":
@ -97,7 +103,7 @@ def get_psw():
return psw
def main():
if len(sys.argv) < 5:
if len(sys.argv) < 4:
print("Usage:")
print("python g5watt.py <user> <site> <logfile_path>")
exit(0)

20
orchestrate.py Normal file
View file

@ -0,0 +1,20 @@
# Orchestrator for G5K
# Fill the IP addresses and config tweaks of your job.
import json, socket
# Enter all the numbers of the nodes of the job
nodes = []
# IP of the nodes ("n" is placeholder for the node number)
IP = "172.16.101.n"
configs = [
{}
]
def orchestrate():
pass
if __name__ == "__main__":
orchestrate()

441
plots.py
View file

@ -71,14 +71,23 @@ PRETTY_TABLE = {
"wp2": "WP",
"yt2-ads": "YT",
"yt2-ublock": "YT+µ",
"paradoxe": "X",
"core2": "C2",
}
PRETTY_TABLE_GNUPLOT = {
"pi3": "Pi",
"wp2": "WP",
"yt2-ads": "YT",
"yt2-ublock": "YT+µ",
"paradoxe": "X",
"core2": "C2",
"i5": "i5",
}
# "cluster-number" to "cluster"
def cluster_name(target):
return target[:target.find("-")] if "-" in target else target
def impl_title(impl):
# Gnuplot does not escape underscores when generating tex
return impl.replace("_", "-")
@ -231,7 +240,7 @@ def make_log_plot(logs, exp, criterion, side, obj, record, machine=None, version
ciphers = {}
impls = []
plain_line = None
idle_val = None
idle_val = {}
conv_factor = 1.0
if obj == "energy":
# Convert Wh to Ws
@ -239,12 +248,12 @@ def make_log_plot(logs, exp, criterion, side, obj, record, machine=None, version
for log in logs:
if log["exp"] == "idle":
idle_val = float(log[COL[obj]]) / float(log["time"]) * conv_factor
idle_val[log["target"]] = float(log[COL[obj]]) / float(log["time"]) * conv_factor
if log["exp"] != exp or log["record"] != record:
continue
if log["side"] == side and log["tls"] == "0":
n = float(log.get("n", "1000"))
plain_line = "plain {}".format((float(log[COL[obj]]) * conv_factor - idle_val * float(log["time"])) / n)
plain_line = "plain {}".format((float(log[COL[obj]]) * conv_factor[log["target"]] - idle_val[log["target"]] * float(log["time"])) / n)
if plain_line == None:
return
@ -258,11 +267,11 @@ def make_log_plot(logs, exp, criterion, side, obj, record, machine=None, version
ver = VER_LABEL[log["cipher"]]
if log[COL[criterion]]+"/"+ver not in ciphers:
ciphers[log[COL[criterion]]+"/"+ver] = {}
ciphers[log[COL[criterion]]+"/"+ver][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val * float(log["time"])) / n
ciphers[log[COL[criterion]]+"/"+ver][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val[log["target"]] * float(log["time"])) / n
else:
if log[COL[criterion]] not in ciphers:
ciphers[log[COL[criterion]]] = {}
ciphers[log[COL[criterion]]][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val * float(log["time"])) / n
ciphers[log[COL[criterion]]][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val[log["target"]] * float(log["time"])) / n
if log["impl"] not in impls:
impls.append(log["impl"])
impls.sort()
@ -304,50 +313,50 @@ def make_log_plot(logs, exp, criterion, side, obj, record, machine=None, version
maketitle=maketitle
)
def make_log_plot_points(logs_by_target, exp, criterion, side, obj, record, version=None):
def make_log_plot_points(logs, exp, criterion, side, obj, record, version=None):
f = open(f"/dev/shm/plots/{obj}_by_{criterion}_{side}_{record}.dat", "w")
ciphers = {target: {} for target in logs_by_target}
ciphers = {}
impls = []
plain = {target: None for target in logs_by_target}
idle_val = {target: None for target in logs_by_target}
plain = {}
idle_val = {}
conv_factor = 1.0
if obj == "energy":
# Convert Wh to Ws
conv_factor = 3600.0
for target in logs_by_target:
logs = logs_by_target[target]
for log in logs:
if log["exp"] == "idle":
idle_val[target] = float(log[COL[obj]]) / float(log["time"]) * conv_factor
if log["exp"] != exp or log["record"] != record:
continue
if log["side"] == side and log["tls"] == "0":
n = float(log.get("n", "1000"))
plain[target] = (float(log[COL[obj]]) * conv_factor - idle_val[target] * float(log["time"])) / n
for log in logs:
if log["target"] not in ciphers:
ciphers[log["target"]] = {}
plain[log["target"]] = None
idle_val[log["target"]] = None
if log["exp"] == "idle":
idle_val[log["target"]] = float(log[COL[obj]]) / float(log["time"]) * conv_factor
if log["exp"] != exp or log["record"] != record:
continue
if log["side"] == side and log["tls"] == "0":
n = float(log.get("n", "1000"))
plain[log["target"]] = (float(log[COL[obj]]) * conv_factor - idle_val[log["target"]] * float(log["time"])) / n
#for target in plain:
# if plain[target] == None:
# return
for target in logs_by_target:
logs = logs_by_target[target]
for log in logs:
if log["exp"] == exp and log["record"] == record and log["side"] == side:
if version != None and VER_LABEL[log["cipher"]] != version:
continue
n = float(log.get("n", "1000"))
if version == None:
ver = VER_LABEL[log["cipher"]]
if log[COL[criterion]]+"/"+ver not in ciphers[target]:
ciphers[target][log[COL[criterion]]+"/"+ver] = {}
ciphers[target][log[COL[criterion]]+"/"+ver][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val[target] * float(log["time"])) / n
else:
if log[COL[criterion]] not in ciphers[target]:
ciphers[target][log[COL[criterion]]] = {}
ciphers[target][log[COL[criterion]]][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val[target] * float(log["time"])) / n
if log["impl"] not in impls:
impls.append(log["impl"])
for log in logs:
if log["exp"] == exp and log["record"] == record and log["side"] == side:
if version != None and VER_LABEL[log["cipher"]] != version:
continue
n = float(log.get("n", "1000"))
if version == None:
ver = VER_LABEL[log["cipher"]]
if log[COL[criterion]]+"/"+ver not in ciphers[log["target"]]:
ciphers[log["target"]][log[COL[criterion]]+"/"+ver] = {}
ciphers[log["target"]][log[COL[criterion]]+"/"+ver][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val[log["target"]] * float(log["time"])) / n
else:
if log[COL[criterion]] not in ciphers[log["target"]]:
ciphers[log["target"]][log[COL[criterion]]] = {}
ciphers[log["target"]][log[COL[criterion]]][log["impl"]] = (float(log[COL[obj]]) * conv_factor - idle_val[log["target"]] * float(log["time"])) / n
if log["impl"] not in impls:
impls.append(log["impl"])
impls.sort()
f.write("target fulltarget {} none {}\n".format(criterion, " ".join([impl_title(impl) for impl in impls])))
for target in plain:
@ -359,7 +368,7 @@ def make_log_plot_points(logs_by_target, exp, criterion, side, obj, record, vers
cipher_parts = cipher.split("/")
f.write("{} {} {}({}) {} {}\n".format(
target,
ALG_LABEL[cipher_parts[0]]+"/"+target,
ALG_LABEL[cipher_parts[0]]+"/"+PRETTY_TABLE_GNUPLOT[target],
ALG_LABEL[cipher_parts[0]],
cipher_parts[1],
plain[target],
@ -371,7 +380,7 @@ def make_log_plot_points(logs_by_target, exp, criterion, side, obj, record, vers
else:
f.write("{} {} {} {} {}\n".format(
target,
ALG_LABEL[cipher]+"/"+target,
ALG_LABEL[cipher]+"/"+PRETTY_TABLE_GNUPLOT[target],
ALG_LABEL[cipher],
plain[target],
" ".join([
@ -541,30 +550,25 @@ def make_linear_regression(logs, cat="impl"):
# Measure relative difference between TLS versions
def cmp_versions_multitarget(logs, exps, criteria, objs):
ciphers = {}
idle_val = {target: None for target in logs_by_target}
idle_val = {}
for target in logs_by_target:
logs = logs_by_target[target]
for log in logs:
log["target"] = target
log["io"] = int(log["bytes_in"]) + int(log["bytes_out"])
if log["exp"] == "idle":
idle_val[target] = {obj:float(log[COL[obj]]) / float(log["time"]) for obj in objs}
for log in logs:
log["io"] = int(log["bytes_in"]) + int(log["bytes_out"])
if log["exp"] == "idle":
idle_val[log["target"]] = {obj:float(log[COL[obj]]) / float(log["time"]) for obj in objs}
for target in logs_by_target:
logs = logs_by_target[target]
for log in logs:
if log["exp"] not in exps or log["tls"] == "0":
continue
ver = VER_LABEL[log["cipher"]]
if ver not in ciphers:
ciphers[ver] = {}
key = [target]
for criterion in criteria:
key.append(ALG_LABEL.get(log[COL[criterion]], log[COL[criterion]]))
key = "/".join(key)
if key not in ciphers[ver]:
ciphers[ver][key] = log
for log in logs:
if log["exp"] not in exps or log["tls"] == "0":
continue
ver = VER_LABEL[log["cipher"]]
if ver not in ciphers:
ciphers[ver] = {}
key = [log["target"]]
for criterion in criteria:
key.append(ALG_LABEL.get(log[COL[criterion]], log[COL[criterion]]))
key = "/".join(key)
if key not in ciphers[ver]:
ciphers[ver][key] = log
diff_rel_max = {obj:0.0 for obj in objs}
diff_rel_sum = {obj:0.0 for obj in objs}
@ -670,16 +674,16 @@ def tabulate(lines, separator=" ", endline="", ruler=True):
return table
def make_summary(logs):
plain_result_key = lambda log: (log["exp"], log["side"], log["record"])
result_key = lambda log: (log["exp"], log["side"], log["record"], log["impl"], log["alg"], log["kex"], log["cipher"], log["ed"])
plain_result_key = lambda log: (cluster_name(log["target"]), log["exp"], log["side"], log["record"])
result_key = lambda log: (cluster_name(log["target"]), log["exp"], log["side"], log["record"], log["impl"], log["alg"], log["kex"], log["cipher"], log["ed"])
plain_results = {}
results = {}
idle_val = None
idle_val = {}
for log in logs:
if log["exp"] == "idle":
idle_val = {
idle_val[log["target"]] = {
"cpu": float(log["cpu"]) / float(log["time"]),
"energy": float(log["Wh"]) / float(log["time"]) * 3600,
"in": float(log["bytes_in"]) / float(log["time"]),
@ -688,20 +692,21 @@ def make_summary(logs):
if log["tls"] == "0":
n = float(log.get("n", "1000"))
plain_results[plain_result_key(log)] = {
"cpu": (float(log["cpu"]) - idle_val["cpu"] * float(log["time"])) / n,
"cpu": (float(log["cpu"]) - idle_val[log["target"]]["cpu"] * float(log["time"])) / n,
"total_energy": float(log["Wh"]) * 3600 / n,
"energy": (float(log["Wh"]) * 3600 - idle_val["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val["out"] * float(log["time"])) / n,
"energy": (float(log["Wh"]) * 3600 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val[log["target"]]["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val[log["target"]]["out"] * float(log["time"])) / n,
}
if log["exp"] != "idle" and log["tls"] == "1":
n = float(log.get("n", "1000"))
results[result_key(log)] = {
"cpu": (float(log["cpu"]) - idle_val["cpu"] * float(log["time"])) / n,
"target": log["target"],
"cpu": (float(log["cpu"]) - idle_val[log["target"]]["cpu"] * float(log["time"])) / n,
"total_energy": float(log["Wh"]) * 3600 / n,
"energy": (float(log["Wh"]) * 3600 - idle_val["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val["out"] * float(log["time"])) / n,
"energy": (float(log["Wh"]) * 3600 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val[log["target"]]["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val[log["target"]]["out"] * float(log["time"])) / n,
}
lines = [[
@ -718,10 +723,10 @@ def make_summary(logs):
]]
for k in results:
r = results[k]
p = plain_results[k[:3]]
p = plain_results[k[:4]]
lines.append([
"/".join([str(i) for i in k]),
str(round(idle_val["energy"], 1)),
str(round(idle_val[r["target"]]["energy"], 1)),
str(round(p["energy"], 1)),
str(round(r["energy"], 1)),
str(round(r["energy"] - p["energy"], 1)) + " (" + str(round((r["energy"] - p["energy"])/r["energy"]*100, 1)) + "%)",
@ -734,16 +739,16 @@ def make_summary(logs):
print(tabulate(lines))
def analyze_logs(logs):
plain_result_key = lambda log: (log["exp"], log["side"], log["record"])
result_key = lambda log: (log["exp"], log["side"], log["record"], log["impl"], log["alg"], log["kex"], log["cipher"], log["ed"])
plain_result_key = lambda log: (log["target"], log["exp"], log["side"], log["record"])
result_key = lambda log: (log["target"], log["exp"], log["side"], log["record"], log["impl"], log["alg"], log["kex"], log["cipher"], log["ed"])
plain_results = {}
results = {}
idle_val = None
idle_val = {}
for log in logs:
if log["exp"] == "idle":
idle_val = {
idle_val[log["target"]] = {
"cpu": float(log["cpu"]) / float(log["time"]),
"energy": float(log["Wh"]) / float(log["time"]) * 3600,
"in": float(log["bytes_in"]) / float(log["time"]),
@ -752,15 +757,17 @@ def analyze_logs(logs):
if log["tls"] == "0":
n = float(log.get("n", "1000"))
plain_results[plain_result_key(log)] = {
"cpu": (float(log["cpu"]) - idle_val["cpu"] * float(log["time"])) / n,
"target": log["target"],
"cpu": (float(log["cpu"]) - idle_val[log["target"]]["cpu"] * float(log["time"])) / n,
"total_energy": float(log["Wh"]) * 3600 / n,
"energy": (float(log["Wh"]) * 3600 - idle_val["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val["out"] * float(log["time"])) / n,
"energy": (float(log["Wh"]) * 3600 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val[log["target"]]["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val[log["target"]]["out"] * float(log["time"])) / n,
}
if log["exp"] != "idle" and log["tls"] == "1":
n = float(log.get("n", "1000"))
results[result_key(log)] = {
"target": log["target"],
"exp": log["exp"],
"side": log["side"],
"record": log["record"],
@ -769,18 +776,19 @@ def analyze_logs(logs):
"kex": log["kex"],
"cipher": log["cipher"],
"ed": log["ed"],
"cpu": (float(log["cpu"]) - idle_val["cpu"] * float(log["time"])) / n,
"cpu": (float(log["cpu"]) - idle_val[log["target"]]["cpu"] * float(log["time"])) / n,
"total_energy": float(log["Wh"]) * 3600 / n,
"energy": (float(log["Wh"]) * 3600 - idle_val["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val["out"] * float(log["time"])) / n,
"energy": (float(log["Wh"]) * 3600 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val[log["target"]]["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val[log["target"]]["out"] * float(log["time"])) / n,
}
lines = []
for k in results:
r = results[k]
p = plain_results[k[:3]]
p = plain_results[k[:4]]
lines.append({
"target": r["target"],
"exp": r["exp"],
"side": r["side"],
"record": r["record"],
@ -848,16 +856,16 @@ def average_items(items, to_average, target=None):
return avg
def analyze_average_logs(logs, target=None):
plain_result_key = lambda log: (log["exp"], log["side"], log["record"])
result_key = lambda log: (log["exp"], log["side"], log["record"], log["impl"], log["alg"], log["kex"], log["cipher"], log["ed"])
plain_result_key = lambda log: (cluster_name(log["target"]), log["exp"], log["side"], log["record"])
result_key = lambda log: (cluster_name(log["target"]), log["exp"], log["side"], log["record"], log["impl"], log["alg"], log["kex"], log["cipher"], log["ed"])
plain_results = {}
results = {}
idle_val = None
idle_val = {}
for log in logs:
if log["exp"] == "idle":
idle_val = {
idle_val[log["target"]] = {
"cpu": float(log["cpu"]) / float(log["time"]),
"energy": float(log["Wh"]) / float(log["time"]) * 3600,
"in": float(log["bytes_in"]) / float(log["time"]),
@ -868,17 +876,20 @@ def analyze_average_logs(logs, target=None):
if plain_result_key(log) not in plain_results:
plain_results[plain_result_key(log)] = []
plain_results[plain_result_key(log)].append({
"cpu": (float(log["cpu"]) - idle_val["cpu"] * float(log["time"])) / n,
"target": log["target"],
"cpu": (float(log["cpu"]) - idle_val[log["target"]]["cpu"] * float(log["time"])) / n,
"total_energy": float(log["Wh"]) * 3600 / n,
"energy": (float(log["Wh"]) * 3600 - idle_val["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val["out"] * float(log["time"])) / n,
"energy": (float(log["Wh"]) * 3600 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val[log["target"]]["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val[log["target"]]["out"] * float(log["time"])) / n,
"cpu": float(log["cpu"]) / n,
})
if log["exp"] != "idle" and log["tls"] == "1":
n = float(log.get("n", "1000"))
if result_key(log) not in results:
results[result_key(log)] = []
results[result_key(log)].append({
"target": log["target"],
"exp": log["exp"],
"side": log["side"],
"record": log["record"],
@ -887,12 +898,12 @@ def analyze_average_logs(logs, target=None):
"kex": log["kex"],
"cipher": log["cipher"],
"ed": log["ed"],
"idle": idle_val["energy"],
"cpu": (float(log["cpu"]) - idle_val["cpu"] * float(log["time"])) / n,
"idle": idle_val[log["target"]]["energy"],
"cpu": float(log["cpu"]) / n,
"total_energy": float(log["Wh"]) * 3600 / n,
"energy": (float(log["Wh"]) * 3600 - idle_val["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val["out"] * float(log["time"])) / n,
"energy": (float(log["Wh"]) * 3600 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"in": (float(log["bytes_in"]) - idle_val[log["target"]]["in"] * float(log["time"])) / n,
"out": (float(log["bytes_out"]) - idle_val[log["target"]]["out"] * float(log["time"])) / n,
})
for key in plain_results:
@ -903,8 +914,9 @@ def analyze_average_logs(logs, target=None):
lines = []
for k in results:
r = results[k]
p = plain_results[k[:3]]
p = plain_results[k[:4]]
lines.append({
"target": r["target"],
"exp": r["exp"],
"side": r["side"],
"record": r["record"],
@ -1121,65 +1133,84 @@ def make_tx_plot(logs_by_target, server_target):
])
print(tabulate(latex, separator=" & ", endline="\\\\ \\cline{3-9}", ruler=False))
def make_summary_plot(logs_by_target):
lines = [["exp", "record", "alg", "kex", "cipher", "ed", "side", "target", "impl", "plain E (J/S)", "TLS E (J/S)", "TLS only E (J/S)", "plain io (o/S)", "TLS io (o/S)", "TLS only io (o/S)", "TLS E rel", "TLS io rel"]]
def make_summary_plot(logs):
lines = [["exp", "record", "alg", "kex", "cipher", "ed", "side", "target", "impl", "plain E (J/S)", "TLS E (J/S)", "TLS only E (J/S)", "plain io (o/S)", "TLS io (o/S)", "TLS only io (o/S)", "TLS E rel", "TLS io rel", "CPU rel"]]
results = []
for target in logs_by_target:
logs = logs_by_target[target]
target_results = analyze_average_logs(logs, target=target)
for log in target_results:
plain_energy = log["plain"]["energy"]
tls_energy = log["tls"]["energy"]
tls_only_energy = tls_energy - plain_energy
tls_rel_energy = tls_only_energy / plain_energy
plain_io = log["plain"]["in"] + log["plain"]["out"]
tls_io = log["tls"]["in"] + log["tls"]["out"]
tls_only_io = tls_io - plain_io
tls_rel_io = tls_only_io / plain_io
results.append({
"target": target,
"exp": log["exp"],
"record": log["record"],
"alg": log["alg"],
"kex": log["kex"],
"cipher": log["cipher"],
"ed": log["ed"],
"version": VER_LABEL[log["cipher"]],
"impl": log["impl"],
"side": log["side"],
"tls": log["tls"],
"idle_energy": log["idle"],
"plain_energy": plain_energy,
"tls_energy": tls_energy,
"tls_only_energy": tls_only_energy,
"plain_io": plain_io,
"tls_io": tls_io,
"tls_only_io": tls_only_io,
"tls_rel_energy": tls_rel_energy,
"tls_rel_io": tls_rel_io,
})
lines.append([
log["exp"],
log["record"],
log["alg"],
log["kex"],
log["cipher"],
log["ed"],
log["side"],
target,
log["impl"],
str(round(plain_energy, 2)),
str(round(tls_energy, 2)),
str(round(tls_only_energy, 2)),
str(round(plain_io, 2)),
str(round(tls_io, 2)),
str(round(tls_only_io, 2)),
str(round(tls_rel_energy*100, 2))+"%",
str(round(tls_rel_io*100, 2))+"%",
])
target_results = analyze_average_logs(logs)
for log in target_results:
plain_energy = log["plain"]["energy"]
tls_energy = log["tls"]["energy"]
tls_only_energy = tls_energy - plain_energy
tls_rel_energy = tls_only_energy / plain_energy
plain_io = log["plain"]["in"] + log["plain"]["out"]
tls_io = log["tls"]["in"] + log["tls"]["out"]
tls_only_io = tls_io - plain_io
tls_rel_io = tls_only_io / plain_io
plain_cpu = log["plain"]["cpu"]
tls_cpu = log["tls"]["cpu"]
tls_only_cpu = tls_cpu - plain_cpu
results.append({
"target": log["target"],
"exp": log["exp"],
"record": log["record"],
"alg": log["alg"],
"kex": log["kex"],
"cipher": log["cipher"],
"ed": log["ed"],
"version": VER_LABEL[log["cipher"]],
"impl": log["impl"],
"side": log["side"],
"tls": log["tls"],
"idle_energy": log["idle"],
"plain_energy": plain_energy,
"tls_energy": tls_energy,
"tls_only_energy": tls_only_energy,
"plain_io": plain_io,
"tls_io": tls_io,
"tls_only_io": tls_only_io,
"tls_rel_energy": tls_rel_energy,
"tls_rel_io": tls_rel_io,
"plain_cpu": plain_cpu,
"tls_cpu": tls_cpu,
"tls_only_cpu": tls_only_cpu,
})
lines.append([
log["exp"],
log["record"],
log["alg"],
log["kex"],
log["cipher"],
log["ed"],
log["side"],
log["target"],
log["impl"],
str(round(plain_energy, 2)),
str(round(tls_energy, 2)),
str(round(tls_only_energy, 2)),
str(round(plain_io, 2)),
str(round(tls_io, 2)),
str(round(tls_only_io, 2)),
str(round(tls_rel_energy*100, 2))+"%",
str(round(tls_rel_io*100, 2))+"%",
(str(round(tls_only_cpu / plain_cpu * 100, 2))+"%") if plain_cpu != 0 else "-",
])
print(tabulate(lines))
print()
avg_cluster_idle = {}
for log in results:
target = cluster_name(log["target"])
if target not in avg_cluster_idle:
avg_cluster_idle[target] = {}
avg_cluster_idle[target][log["idle_energy"]] = 1
for target in avg_cluster_idle:
avg = 0
nb = 0
for val in avg_cluster_idle[target]:
avg += val
nb += 1
avg_cluster_idle[target]["avg"] = avg / nb
print("\
\\multicolumn{1}{|c|}{\\multirow{2}*{\\textbf{Target}}}&\
\\multicolumn{1}{|c|}{\\multirow{2}*{\\textbf{Idle (W)}}}&\
@ -1192,13 +1223,13 @@ def make_summary_plot(logs_by_target):
latex_lines = {}
latex_keys = []
for log in results:
key = (log["target"], log["record"], log["side"])
key = (cluster_name(log["target"]), log["record"], log["side"])
if key in latex_lines:
continue
latex_keys.append(key)
latex_lines[key] = [
PRETTY_TABLE.get(log["target"], log["target"]),
"${}$".format(roundz(log["idle_energy"], 2)),
PRETTY_TABLE.get(cluster_name(log["target"]), cluster_name(log["target"])),
"${}$".format(roundz(avg_cluster_idle[cluster_name(log["target"])]["avg"], 2)),
PRETTY_TABLE[log["record"]],
log["side"],
"${}$".format(roundz(log["plain_energy"], 2)),
@ -1297,6 +1328,8 @@ def make_summary_plot(logs_by_target):
samples_energy_server = []
samples_io = []
for log_new in results:
if "paradoxe" in log_new["target"]:
continue
ok = True
for filter in cmp["new"]:
if log_new[filter] != cmp["new"][filter]:
@ -1304,7 +1337,7 @@ def make_summary_plot(logs_by_target):
break
if not ok:
continue
key_new = (log_new["exp"], log_new["target"], log_new["impl"], log_new["record"], log_new["side"])
key_new = (log_new["exp"], cluster_name(log_new["target"]), log_new["impl"], log_new["record"], log_new["side"])
for log_old in results:
ok = True
for filter in cmp["old"]:
@ -1313,7 +1346,7 @@ def make_summary_plot(logs_by_target):
break
if not ok:
continue
key_old = (log_old["exp"], log_old["target"], log_old["impl"], log_old["record"], log_old["side"])
key_old = (log_old["exp"], cluster_name(log_old["target"]), log_old["impl"], log_old["record"], log_old["side"])
if key_new == key_old:
if log_new["side"] == "server":
samples_energy_server.append((log_new["tls_energy"] / log_old["tls_energy"] - 1.0) * 100.0)
@ -1339,10 +1372,8 @@ def make_summary_plot(logs_by_target):
f_energy = open("/dev/shm/plots/energy-global.dat", "w")
f_io = open("/dev/shm/plots/io-global.dat", "w")
for log in results:
if log["target"] == "pi3" and "yt" in log["record"]:
continue
f_energy.write("{}-{} {}\n".format(PRETTY_TABLE_GNUPLOT.get(log["target"], log["target"]), log["side"], log["tls_rel_energy"] * 100.0))
f_io.write("{}-{} {}\n".format(PRETTY_TABLE_GNUPLOT.get(log["target"], log["target"]), log["side"], log["tls_rel_io"] * 100.0))
f_energy.write("{}-{} {}\n".format(PRETTY_TABLE_GNUPLOT.get(cluster_name(log["target"]), log["target"]), log["side"], log["tls_rel_energy"] * 100.0))
f_io.write("{}-{} {}\n".format(PRETTY_TABLE_GNUPLOT.get(cluster_name(log["target"]), log["target"]), log["side"], log["tls_rel_io"] * 100.0))
f_energy.close()
f_io.close()
@ -1357,31 +1388,27 @@ def compute_box_plot(a):
def make_stability_plot(logs_by_target):
f = open(f"/dev/shm/plots/stability.dat", "w")
idle_val = {target: None for target in logs_by_target}
idle_val = {}
for target in logs_by_target:
logs = logs_by_target[target]
for log in logs:
if log["exp"] == "idle":
idle_val[target] = {
"energy": float(log[COL["energy"]]) / float(log["time"]) * 3600.0,
"io": float(log["bytes_in"])+float(log["bytes_out"]) / float(log["time"]),
}
for log in logs:
if log["exp"] == "idle":
idle_val[log["target"]] = {
"energy": float(log[COL["energy"]]) / float(log["time"]) * 3600.0,
"io": float(log["bytes_in"])+float(log["bytes_out"]) / float(log["time"]),
}
all_results = {}
for target in logs_by_target:
logs = logs_by_target[target]
for log in logs:
if log["exp"] == "idle":
continue
n = float(log.get("n", "1000"))
key = "{}-{}".format(target, log["side"])
if key not in all_results:
all_results[key] = []
all_results[key].append({
"energy": (float(log[COL["energy"]]) * 3600.0 - idle_val[target]["energy"] * float(log["time"])) / n,
"io": (float(log["bytes_in"])+float(log["bytes_out"]) - idle_val[target]["io"] * float(log["time"])) / n / 1024**2
})
for log in logs:
if log["exp"] == "idle":
continue
n = float(log.get("n", "1000"))
key = "{}-{}".format(PRETTY_TABLE_GNUPLOT[cluster_name(log["target"])], log["side"])
if key not in all_results:
all_results[key] = []
all_results[key].append({
"energy": (float(log[COL["energy"]]) * 3600.0 - idle_val[log["target"]]["energy"] * float(log["time"])) / n,
"io": (float(log["bytes_in"])+float(log["bytes_out"]) - idle_val[log["target"]]["io"] * float(log["time"])) / n / 1024**2
})
means = {key: {
"energy": sum([i["energy"] for i in all_results[key]])/len(all_results[key]),
@ -1429,6 +1456,8 @@ def parse_logs(logfile_name):
logs = []
records = {}
for line in lines[1:]:
if line[0] in "#\n":
continue
cols = line.removesuffix("\n").split(" ")
log = {}
for col in range(len(cols)):
@ -1465,24 +1494,22 @@ if __name__ == "__main__":
make_log_plot(logs, "zrtt", "ed", side, "energy", record, machine=machine, maketitle=maketitle, version="1.3")
cmp_versions(logs, ["impl-cipher-ver", "impl-cert-ver", "impl-kex-ver"], ["side", "cipher", "cert", "kex", "record"], ["cpu", "energy"])
elif cmd == "log2":
# Args: log2 <file1> <target1> [<file2> <target2>] [...]
# Args: log2 <file1> [<file2>] [...]
# Only use the intersection of the records
logs_by_target = {sys.argv[3]: logs}
records_to_remove = {}
for i in range(4, len(sys.argv), 2):
for i in range(3, len(sys.argv)):
logs_i, records_i = parse_logs(sys.argv[i])
for record in records:
if record not in records_i:
records_to_remove[record] = ()
target_i = sys.argv[i+1]
logs_by_target[target_i] = logs_i
logs += logs_i
for record in records_to_remove:
records.pop(record)
for side in ["client", "server"]:
for record in records:
make_log_plot_points(logs_by_target, "impl-cipher-ver", "cipher", side, "energy", record, version="1.3")
make_log_plot_points(logs_by_target, "impl-cert-ver", "cert", side, "energy", record, version="1.3")
make_log_plot_points(logs_by_target, "impl-kex-ver", "kex", side, "energy", record, version="1.3")
make_log_plot_points(logs, "impl-cipher-ver", "cipher", side, "energy", record, version="1.3")
make_log_plot_points(logs, "impl-cert-ver", "cert", side, "energy", record, version="1.3")
make_log_plot_points(logs, "impl-kex-ver", "kex", side, "energy", record, version="1.3")
cmp_versions_multitarget(logs, ["impl-cipher-ver", "impl-cert-ver", "impl-kex-ver"], ["side", "cipher", "cert", "kex", "record", "ed", "impl"], ["energy", "io"])
elif cmd == "prof":
for side in ["client", "server"]:
@ -1494,15 +1521,11 @@ if __name__ == "__main__":
make_profile_plot_grouped(logs, "impl-cert-ver", "cert", side, record, "impl", no_flamegraph=no_flamegraph, machine=machine, maketitle=maketitle, version="1.3")
make_profile_plot_grouped(logs, "impl-kex-ver", "kex", side, record, "impl", no_flamegraph=no_flamegraph, machine=machine, maketitle=maketitle, version="1.3")
elif cmd == "summary":
# Args: stab <file1> <target1> [<file2> <target2>] [...]
# First target is the server
server = sys.argv[3]
logs_by_target = {server: logs}
for i in range(4, len(sys.argv), 2):
# Args: stab <file1> [<file2>] [...]
for i in range(3, len(sys.argv)):
logs_i, records_i = parse_logs(sys.argv[i])
target_i = sys.argv[i+1]
logs_by_target[target_i] = logs_i
make_summary_plot(logs_by_target)
logs += logs_i
make_summary_plot(logs)
elif cmd == "tx":
# Args: stab <file1> <target1> [<file2> <target2>] [...]
# First target is the server
@ -1519,10 +1542,8 @@ if __name__ == "__main__":
import numpy as np
make_linear_regression(logs, "alg")
elif cmd == "stab":
# Args: stab <file1> <target1> [<file2> <target2>] [...]
logs_by_target = {sys.argv[3]: logs}
for i in range(4, len(sys.argv), 2):
# Args: stab <file1> [<file2>] [...]
for i in range(3, len(sys.argv)):
logs_i, records_i = parse_logs(sys.argv[i])
target_i = sys.argv[i+1]
logs_by_target[target_i] = logs_i
make_stability_plot(logs_by_target)
logs += logs_i
make_stability_plot(logs)