mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-10-01 01:36:09 -04:00
160 lines
5.2 KiB
Python
160 lines
5.2 KiB
Python
|
"""Parse logs of K-Bench tests and generate performance graphs."""
|
||
|
import json
|
||
|
import os
|
||
|
from collections import defaultdict
|
||
|
|
||
|
import numpy as np
|
||
|
from evaluators import default, fio, network
|
||
|
from matplotlib import pyplot as plt
|
||
|
|
||
|
BAR_COLOR = '#90FF99' # Mint Green
|
||
|
|
||
|
# Rotate bar labels by X degrees
|
||
|
LABEL_ROTATE_BY = 30
|
||
|
LABEL_FONTSIZE = 9
|
||
|
|
||
|
# Some lookup dictionaries for x axis
|
||
|
api_suffix = 'ms'
|
||
|
pod_key2header = {
|
||
|
'pod_create': 'Pod Create',
|
||
|
'pod_list': 'Pod List',
|
||
|
'pod_get': 'Pod Get',
|
||
|
'pod_update': 'Pod Update',
|
||
|
'pod_delete': 'Pod Delete',
|
||
|
}
|
||
|
svc_key2header = {
|
||
|
'svc_create': 'Service Create',
|
||
|
'svc_list': 'Service List',
|
||
|
'svc_update': 'Service Update',
|
||
|
'svc_delete': 'Service Delete',
|
||
|
'svc_get': 'Service Get',
|
||
|
}
|
||
|
depl_key2header = {
|
||
|
'depl_create': 'Deployment Create',
|
||
|
'depl_list': 'Deployment List',
|
||
|
'depl_update': 'Deployment Update',
|
||
|
'depl_scale': 'Deployment Scale',
|
||
|
'depl_delete': 'Deployment Delete',
|
||
|
}
|
||
|
|
||
|
fio_suffix = 'MiB/s'
|
||
|
fio_key2header = {
|
||
|
'fio_root_async_R70W30_R': 'async_R70W30 mix,\n seq. reads',
|
||
|
'fio_root_async_R70W30_W': 'async_R70W30 mix,\n seq. writes',
|
||
|
'fio_root_async_R100W0_R': 'async_R100W0 mix,\n seq. reads',
|
||
|
'fio_root_async_R0W100_W': 'async_R0W100 mix,\n seq. writes',
|
||
|
}
|
||
|
|
||
|
net_suffix = 'Mbit/s'
|
||
|
net_key2header = {
|
||
|
'net_internode_snd': f'iperf internode \n send ({net_suffix})',
|
||
|
'net_intranode_snd': f'iperf intranode \n send ({net_suffix})',
|
||
|
}
|
||
|
|
||
|
|
||
|
def configure() -> dict:
|
||
|
"""Set the config.
|
||
|
|
||
|
Raises BaseException if base_path or CSP missing.
|
||
|
|
||
|
Returns a config dict with the BASE_PATH to the tests
|
||
|
and the cloud service provider CSP.
|
||
|
"""
|
||
|
base_path = os.getenv('KBENCH_RESULTS', None)
|
||
|
if not base_path or not os.path.isdir(base_path):
|
||
|
raise Exception("Environment variable 'KBENCH_RESULTS' \
|
||
|
needs to point to the K-Bench results root folder")
|
||
|
|
||
|
csp = os.getenv('CSP', None)
|
||
|
if not csp:
|
||
|
raise Exception("Environment variable 'CSP' \
|
||
|
needs to name the cloud service provider.")
|
||
|
return {'BASE_PATH': base_path, 'CSP': csp}
|
||
|
|
||
|
|
||
|
def bar_chart(data, headers, title='', suffix='', val_label=True, y_log=False):
|
||
|
"""Generate a bar chart from data.
|
||
|
|
||
|
Args:
|
||
|
data (list): List of value points.
|
||
|
headers (list): List of headers (x-axis).
|
||
|
title (str, optional): The title for the chart. Defaults to "".
|
||
|
suffix (str, optional): The suffix for values e.g. "MiB/s". Defaults to "".
|
||
|
val_label (bool, optional): Put a label of the value over the bar chart. Defaults to True.
|
||
|
y_log (bool, optional): Set the y-axis to a logarithmic scale. Defaults to False.
|
||
|
Returns:
|
||
|
fig (matplotlib.pyplot.figure): The pyplot figure
|
||
|
"""
|
||
|
fig, ax = plt.subplots(figsize=(8, 5))
|
||
|
fig.patch.set_facecolor('white')
|
||
|
ax.set_xticks(np.arange(len(headers)))
|
||
|
ax.set_xticklabels(headers)
|
||
|
if y_log:
|
||
|
ax.set_yscale('log')
|
||
|
bars = ax.bar(headers, data, color=BAR_COLOR, edgecolor='black')
|
||
|
if val_label:
|
||
|
ax.bar_label(bars, fmt='%g {suffix}'.format(suffix=suffix))
|
||
|
plt.setp(ax.get_xticklabels(), fontsize=LABEL_FONTSIZE, rotation=LABEL_ROTATE_BY)
|
||
|
plt.title(f'{title} ({suffix})')
|
||
|
plt.tight_layout()
|
||
|
return fig
|
||
|
|
||
|
|
||
|
def main() -> None:
|
||
|
"""Read, parse and evaluate the K-Bench tests.
|
||
|
|
||
|
Generate a human-readable table and diagrams.
|
||
|
"""
|
||
|
config = configure()
|
||
|
|
||
|
benchmark_path = os.path.join(
|
||
|
config['BASE_PATH'],
|
||
|
"kbench-constellation-" + config['CSP'],
|
||
|
)
|
||
|
if not os.path.exists(benchmark_path):
|
||
|
raise Exception(f'Path to benchmarks {benchmark_path} does not exist.')
|
||
|
|
||
|
tests = {f"constellation-{config['CSP']}": benchmark_path}
|
||
|
|
||
|
# Execute tests
|
||
|
default_results = default.eval(tests=tests)
|
||
|
network_results = network.eval(tests=tests)
|
||
|
fio_results = fio.eval(tests=tests)
|
||
|
|
||
|
combined_results = defaultdict(dict)
|
||
|
for test in tests:
|
||
|
combined_results[test].update(default_results[test])
|
||
|
combined_results[test].update(network_results[test])
|
||
|
combined_results[test].update(fio_results[test])
|
||
|
|
||
|
# Write the compact results.
|
||
|
with open('kbench_results.json', 'w') as w:
|
||
|
json.dump(combined_results, fp=w, sort_keys=False, indent=2)
|
||
|
|
||
|
# Generate graphs.
|
||
|
subject = list(combined_results.keys())[0]
|
||
|
data = combined_results[subject]
|
||
|
|
||
|
# Combine the evaluation of the Kubernetes API benchmarks
|
||
|
for i, api in enumerate([pod_key2header, svc_key2header, depl_key2header]):
|
||
|
api_data = [data[h] for h in api]
|
||
|
hdrs = api.values()
|
||
|
bar_chart(data=api_data, headers=hdrs, title="API Latency", suffix=api_suffix)
|
||
|
plt.savefig(f'api_{i}_perf.png', bbox_inches="tight")
|
||
|
|
||
|
# Network chart
|
||
|
net_data = [data[h] for h in net_key2header]
|
||
|
hdrs = net_key2header.values()
|
||
|
bar_chart(data=net_data, headers=hdrs, title="Network Throughput", suffix=net_suffix)
|
||
|
plt.savefig('net_perf.png', bbox_inches="tight")
|
||
|
|
||
|
# fio chart
|
||
|
fio_data = [data[h] for h in fio_key2header]
|
||
|
hdrs = fio_key2header.values()
|
||
|
bar_chart(data=fio_data, headers=hdrs, title="Storage Throughput", suffix=fio_suffix)
|
||
|
plt.savefig('storage_perf.png', bbox_inches="tight")
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|