CCF/tests/plot_node_load.py

119 строки
3.5 KiB
Python

# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the Apache 2.0 License.
import argparse
import datetime
import json
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import os
# For consistency between plots we want a function from label (name) to colour.
# We could do this programatically from the hashes to handle general values, but
# this is sufficient and makes it simple to group similar messages with similar colours
LABELS_TO_COLOURS = {
# Processed on Host
"AdminMessage::log_msg": "dimgray",
"AdminMessage::work_stats": "gainsboro",
"ccf::add_node": "lime",
"ccf::node_outbound": "darkgreen",
"consensus::ledger_append": "red",
"consensus::ledger_get_range": "indianred",
"consensus::ledger_commit": "maroon",
"consensus::ledger_truncate": "rosybrown",
"tls::tls_closed": "darkkhaki",
"tls::tls_connect": "khaki",
"tls::tls_outbound": "gold",
"tls::tls_stop": "goldenrod",
# Processed in enclave
"AdminMessage::tick": "dimgray",
"ccf::node_inbound": "darkgreen",
"consensus::ledger_entry_range": "red",
"tls::tls_close": "darkkhaki",
"tls::tls_inbound": "gold",
"tls::tls_start": "goldenrod",
# Processed in both
"OversizedMessage::fragment": "slategray",
}
def num_to_bytes_formatter(n, _):
suffixes = ("B", "KB", "MB", "GB")
i = 0
while n >= 1024 and i < len(suffixes) - 1:
n /= 1024.0
i += 1
return f"{n:,.2f} {suffixes[i]}"
def plot_stacked(jsons, key):
labels = []
for j in jsons:
for label in j["ringbuffer_messages"].keys():
if label not in labels:
labels.append(label)
labels.sort()
colours = []
default_colour = "black"
for i, label in enumerate(labels):
try:
colours.append(LABELS_TO_COLOURS[label])
except KeyError:
print(f"No colour for '{label}', defaulting to {default_colour}")
colours.append(default_colour)
xs = []
ys = [[] for _ in range(len(labels))]
for j in jsons:
xs.append(j["end_time_ms"])
messages = j["ringbuffer_messages"]
for i, label in enumerate(labels):
try:
count = messages[label][key]
except KeyError:
count = 0
ys[i].append(count)
def ms_to_date_formatter(ms, _):
s = ms / 1000.0
return datetime.datetime.fromtimestamp(s).strftime("%H:%M:%S")
_, ax = plt.subplots()
plt.title(f"Ringbuffer messages - {key}")
plt.ylabel(f"{key}")
plt.ticklabel_format(useOffset=False)
ax.xaxis.set_major_formatter(ms_to_date_formatter)
ax.locator_params(axis="x", nbins=5)
ax.xaxis.set_minor_locator(ticker.MultipleLocator(1000))
if key == "bytes":
ax.yaxis.set_major_formatter(num_to_bytes_formatter)
ax.stackplot(xs, ys, colors=colours, labels=labels)
ax.legend(prop={"size": 8})
path_without_ext, _ = os.path.splitext(args.load_file.name)
output_path = f"{path_without_ext}_{key}.png"
print(f"Saving plot to {output_path}")
plt.savefig(output_path, bbox_inches="tight")
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"load_file",
type=argparse.FileType("r"),
help="Path to load log file to be parsed",
)
args = parser.parse_args()
lines = args.load_file.readlines()
jsons = [json.loads(line) for line in lines]
plot_stacked(jsons, "count")
plot_stacked(jsons, "bytes")