Skip to content

Instantly share code, notes, and snippets.

@Ngoguey42
Last active August 6, 2021 16:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ngoguey42/872ded9908593e1dc94ab0f28e8abbe8 to your computer and use it in GitHub Desktop.
Save Ngoguey42/872ded9908593e1dc94ab0f28e8abbe8 to your computer and use it in GitHub Desktop.
irmin: bench/tree.exe bootstrap trace plot
(env
(dev (flags (-w +1..3+5..28+30..39+43+46..47+49..57+61..62-40-26 -strict-sequence -strict-formats -short-paths -keep-locs -g)))
(release (flags (-w +1..3+5..28+30..39+43+46..47+49..57+61..62-40-26 -strict-sequence -strict-formats -short-paths -keep-locs )))
)
(executable
(name json_to_repr)
(libraries repr ppx_repr fmt ppx_deriving_yojson mtime mtime.clock.os unix re)
(preprocess
(pps ppx_repr ppx_deriving_yojson)))
(lang dune 2.8)
"""Plot distribution of timings out of bench/tree.exe on boostrap trace
Formatted using YAPF
"""
import argparse
import json
import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
sns.set_theme(style="ticks", color_codes=True)
plt.rcParams["legend.labelspacing"] = 1.7
p = argparse.ArgumentParser()
p.add_argument('--in',
help="""path to JSON file.
Pseudo schema:
{
"revision" : string;
"flatten": int;
"inode_config": string;
"max_durations": {string -> (int, float)};
"moving_average_points": {string -> {"x": float array; "y": float array}};
"histo_points": {string -> (int * float) array};
}
""")
p.add_argument('--out', help="Suffix of output filename")
p.add_argument('-o',
help="Overwrite if --out exists. Fail otherwise",
action="store_true")
args = p.parse_args()
print(args)
j = json.loads(open(dict(args._get_kwargs())['in']).read())
if args.o == False and os.path.exists(args.out):
raise NameError("{} exists!! Pass -o to overrite it".format(args.out))
def time_to_txt(t):
h = np.floor(t / 3600)
t -= h * 3600
m = np.floor(t / 60)
t -= m * 60
return "{:02.0f}:{:02.0f}:{:02.0f}".format(h, m, t)
def time_to_txt2(t):
if t < 1e-6:
return '{:.0f} ns'.format(t / 1e-9)
if t < 1e-3:
return '{:.0f} \u03bcs'.format(t / 1e-6)
if t < 1:
return '{:.0f} ms'.format(t / 1e-3)
else:
return '{:.0f} s'.format(t)
def time_to_txt3(t):
if t < 1e-6:
return '{:.1f} ns'.format(t / 1e-9)
if t < 1e-3:
return '{:.1f} \u03bcs'.format(t / 1e-6)
if t < 1:
return '{:.1f} ms'.format(t / 1e-3)
else:
return '{:.1f} s'.format(t)
def count_to_txt(v):
if v <= 9999:
return '{:.0f}'.format(v)
if v <= 9999999:
return '{:.0f} K'.format(v / 1e3)
if v <= 9999999999:
return '{:.0f} M'.format(v / 1e6)
return '{:.0f} G'.format(v / 1e9)
def logn_to_txt(v):
if v == 0:
return "1"
v = 10**v
if v >= 1e9:
return '< {:.0f} G'.format(v / 1e9)
if v >= 1e6:
return '< {:.0f} M'.format(v / 1e6)
if v >= 1e3:
return '< {:.0f} K'.format(v / 1e3)
return '< {:.0f}'.format(v)
columns = []
for i, k in enumerate(sorted(j["histo_points"].keys())):
df = pd.DataFrame(j["histo_points"][k], columns=['n', 'center'])
n = df.n.sum()
total = (df.center * df.n).sum()
df["op"] = k
df["label"] = k + '\n' + count_to_txt(n) + '\n' + time_to_txt(total)
print(f"column {i:<2d}: k:{k:<15s} points:{len(df):<3d} "
f"samples:{n:<10,d} total:{total:<.9f}")
columns.append(df)
df = pd.concat(columns)
print("Stats per op -----------------")
df1 = df.copy()
df1['duration'] = df1.center * df1.n
df1 = df1.groupby("op").sum().drop(columns=['center']).reset_index()
df1['mean_duration'] = df1.duration / df1.n
df1['max_duration'] = df1.op.apply(lambda op: j["max_durations"][op][1])
df1['label'] = df.groupby("op").first().label.reset_index(drop=True)
print(df1)
print("All data points -----------------")
df["duration"] = df.center
df['logn'] = np.ceil(np.log10(df.n))
print(df)
# Seaborn plot ----------------
# https://seaborn.pydata.org/examples/scatter_bubbles.html
g = sns.relplot(
x="op",
y="duration",
size="logn",
palette="muted",
alpha=.5,
sizes=(20, 750),
height=6,
data=df,
legend="full",
# facet_kws=dict(legend_out=True, )
)
g.set(yscale="log")
plt.grid(axis='y')
v = plt.plot(df1["op"],
df1.max_duration,
'_',
color='black',
alpha=0.5,
ms=15,
label="max")
w = plt.plot(df1["op"],
df1.mean_duration,
'_',
color='red',
alpha=0.5,
ms=15,
label="mean")
for _, row in df1.iterrows():
plt.annotate(
time_to_txt3(row.mean_duration),
(row["op"], row.mean_duration),
xytext=(10, 0),
textcoords='offset pixels',
ha='left',
va='center',
size=8,
weight='bold',
)
plt.annotate(
time_to_txt3(row.max_duration),
(row["op"], row.max_duration),
xytext=(10, 0),
textcoords='offset pixels',
ha='left',
va='center',
size=8,
weight='bold',
)
plt.legend(handles=v + w, loc="upper right")
plt.xlabel('op name / call count / total time spent in op', weight="bold")
plt.ylabel('duration of call (log scale)', weight="bold")
# Legend ----------------
g.legend.set_title("Number of calls")
for txt in g.legend.texts:
print(float(txt.get_text()), logn_to_txt(float(txt.get_text())))
txt.set_text(logn_to_txt(float(txt.get_text())))
# Title ----------------
el_wall_inop = time_to_txt(df1.duration.sum())
el_wall = time_to_txt(float(j["elapsed"]))
el_cpu = time_to_txt(float(j["elapsed_cpu"]))
flatten = {
"0": False,
"1": True,
0: False,
1: True,
}[j["flatten"]]
plt.title(
("bench/tree.exe on the bootstrap trace / commits:{} / flatten:{} / inode-config:{}\n"
"wall in ops:{} / wall:{} / cpu:{} / revision:{}")
.format(
df[df["op"].str.contains("Commit")].n.sum(),
flatten,
j["inode_config"],
el_wall_inop, el_wall, el_cpu,
j["revision"],
), weight="bold")
# Tick label x ----------------
xticks, _ = plt.xticks()
plt.xticks(xticks, df1.label)
# Tick label y ----------------
a = min(df["duration"].min(), 1e-7)
b = max(pd.DataFrame(j["max_durations"]).T.iloc[:, 1].max(), 1e+3)
a, b = np.log10([a, b])
yticks = 10**np.arange(np.ceil(a), np.floor(b) + 1)
ymin = 10**(np.floor(a * 4) / 4)
ymax = 10**(np.ceil(b * 4) / 4)
plt.ylim(ymin, ymax)
plt.yticks(yticks, [time_to_txt2(v) for v in yticks])
plt.minorticks_off()
# Save ----------------
# https://stackoverflow.com/a/56970556
g.fig.set_figwidth(10)
g.fig.set_figheight(6)
g.tight_layout()
g.savefig(args.out)
"""Plot distribution of timings out of bench/tree.exe on boostrap trace
Formatted using YAPF
"""
import argparse
import json
import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
sns.set_theme(style="ticks", color_codes=True)
# plt.rcParams["legend.labelspacing"] = 1.7
p = argparse.ArgumentParser()
p.add_argument('--in',
help="""path to JSON file.
Pseudo schema:
{
"revision" : string;
"flatten": int;
"inode_config": string;
"max_durations": {string -> (int, float)};
"moving_average_points": {string -> {"x": float array; "y": float array}};
"histo_points": {string -> (int * float) array};
}
""")
p.add_argument('--out', help="Suffix of output filename")
p.add_argument('-o',
help="Overwrite if --out exists. Fail otherwise",
action="store_true")
args = p.parse_args()
print(args)
j = json.loads(open(dict(args._get_kwargs())['in']).read())
if args.o == False and os.path.exists(args.out):
raise NameError("{} exists!! Pass -o to overrite it".format(args.out))
def time_to_txt(t):
h = np.floor(t / 3600)
t -= h * 3600
m = np.floor(t / 60)
t -= m * 60
return "{:02.0f}:{:02.0f}:{:02.0f}".format(h, m, t)
def time_to_txt2(t):
if t < 1e-6:
return '{:.0f} ns'.format(t / 1e-9)
if t < 1e-3:
return '{:.0f} \u03bcs'.format(t / 1e-6)
if t < 1:
return '{:.0f} ms'.format(t / 1e-3)
else:
return '{:.0f} s'.format(t)
def time_to_txt3(t):
if t < 1e-6:
return '{:.1f}ns'.format(t / 1e-9)
if t < 1e-3:
return '{:.1f}\u03bcs'.format(t / 1e-6)
if t < 1:
return '{:.1f}ms'.format(t / 1e-3)
else:
return '{:.1f}s'.format(t)
def count_to_txt(v):
if v <= 9999:
return '{:.0f}'.format(v)
if v <= 9999999:
return '{:.0f} K'.format(v / 1e3)
if v <= 9999999999:
return '{:.0f} M'.format(v / 1e6)
return '{:.0f} G'.format(v / 1e9)
def logn_to_txt(v):
if v == 0:
return "1"
v = 10**v
if v >= 1e9:
return '< {:.0f} G'.format(v / 1e9)
if v >= 1e6:
return '< {:.0f} M'.format(v / 1e6)
if v >= 1e3:
return '< {:.0f} K'.format(v / 1e3)
return '< {:.0f}'.format(v)
columns = []
for i, k in enumerate(sorted(j["histo_points"].keys())):
df = pd.DataFrame(j["histo_points"][k], columns=['n', 'center'])
n = df.n.sum()
total = (df.center * df.n).sum()
df["op"] = k
df["label"] = k + '\n' + count_to_txt(n) + '\n' + time_to_txt(total)
print(f"column {i:<2d}: k:{k:<15s} points:{len(df):<3d} "
f"samples:{n:<10,d} total:{total:<.9f}")
columns.append(df)
print("Stats per op -----------------")
df1 = pd.concat(columns).copy()
df1['duration'] = df1.center * df1.n
df1 = df1.groupby("op").sum().drop(columns=['center']).reset_index()
df1['mean_duration'] = df1.duration / df1.n
df1['max_duration'] = df1.op.apply(lambda op: j["max_durations"][op][1])
df1['label'] = df.groupby("op").first().label.reset_index(drop=True)
print(df1)
colors = dict(
Add="brown",
Checkout="grey",
Commit="red",
Copy="pink",
Find="orange",
Mem="blue",
Mem_tree="yellow",
Remove="purple",
)
plt.figure(figsize=(10, 6))
plt.yscale("log")
ncommits = ...
columns = []
for i, k in enumerate(sorted(j["moving_average_points"].keys())):
df = pd.DataFrame(j["histo_points"][k], columns=['n', 'center'])
n = df.n.sum()
if k == "Commit": ncommits = n
df = pd.DataFrame(j["moving_average_points"][k])
if len(df) == 0: continue
c = colors.get(k, "black")
plt.plot(df["xs"], df["ys"], c=c)
maxi, maxd = j["max_durations"][k]
maxx = maxi / (n - 1)
print(k, maxi, n, maxx, maxd)
plt.plot([maxx], [maxd],
'X',
color=c,
alpha=0.5,
ms=10,
label="{}\n• {}\n• {}".format(k, time_to_txt3(maxd), maxi))
# label="{}, max at idx {}".format(k, maxi))
# plt.annotate(
# time_to_txt3(maxd),
# (maxx, maxd),
# xytext=(10, 0),
# textcoords='offset pixels',
# ha='left',
# va='center',
# size=8,
# weight='bold',
# )
columns.append(df)
df = pd.concat(columns)
print(df)
plt.xlabel('trace replay progress', weight="bold")
plt.ylabel('duration of call (log scale) (smoothed curve)', weight="bold")
plt.grid(axis='y')
# Title ----------------
el_wall_inop = time_to_txt(df1.duration.sum())
el_wall = time_to_txt(float(j["elapsed"]))
el_cpu = time_to_txt(float(j["elapsed_cpu"]))
flatten = {
"0": False,
"1": True,
0: False,
1: True,
}[j["flatten"]]
plt.title(
("bench/tree.exe on the bootstrap trace / commits:{} / flatten:{} / inode-config:{}\n"
"wall in ops:{} / wall:{} / cpu:{} / revision:{}")
.format(
ncommits,
flatten,
j["inode_config"],
el_wall_inop, el_wall, el_cpu,
j["revision"],
), weight="bold")
# Tick label x ----------------
xticks = np.linspace(0, 1, 10)
plt.xticks(xticks, [
time_to_txt(x * float(j["elapsed"])) for x in xticks
])
plt.xlim(0, 1)
# Tick label y ----------------
a = min(df["ys"].min(), 1e-7)
b = max(pd.DataFrame(j["max_durations"]).T.iloc[:, 1].max(), 1e+3)
print(a, b)
a, b = np.log10([a, b])
print(a, b)
a = np.floor(a)
b = np.ceil(b)
print(a, b)
print(10**a, 10**b)
yticks = 10**np.arange(a, b + 1)
ymin = 10**a
ymax = 10**b
plt.ylim(ymin, ymax)
plt.yticks(yticks, [time_to_txt2(v) for v in yticks])
plt.minorticks_off()
plt.legend(fontsize="small", bbox_to_anchor=(1.0, 1), loc='upper left',
title="Operation\n• len of max\n• idx of max")
# Save ----------------
# https://stackoverflow.com/a/56970556
# g.fig.set_figheight(6)
plt.tight_layout()
plt.savefig(args.out)
import datetime
import argparse
import json
import os
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
# import plotly.express as px
# import plotly.graph_objects as go
class BubbleChart:
def __init__(self, area, bubble_spacing=0):
"""
Setup for bubble collapse.
Parameters
----------
area : array-like
Area of the bubbles.
bubble_spacing : float, default: 0
Minimal spacing between bubbles after collapsing.
Notes
-----
If "area" is sorted, the results might look weird.
"""
area = np.asarray(area)
r = np.sqrt(area / np.pi)
self.bubble_spacing = bubble_spacing
self.bubbles = np.ones((len(area), 4))
self.bubbles[:, 2] = r
self.bubbles[:, 3] = area
self.maxstep = 2 * self.bubbles[:, 2].max() + self.bubble_spacing
self.step_dist = self.maxstep / 2
# calculate initial grid layout for bubbles
length = np.ceil(np.sqrt(len(self.bubbles)))
grid = np.arange(length) * self.maxstep
gx, gy = np.meshgrid(grid, grid)
self.bubbles[:, 0] = gx.flatten()[:len(self.bubbles)]
self.bubbles[:, 1] = gy.flatten()[:len(self.bubbles)]
self.com = self.center_of_mass()
def center_of_mass(self):
return np.average(
self.bubbles[:, :2], axis=0, weights=self.bubbles[:, 3]
)
def center_distance(self, bubble, bubbles):
return np.hypot(bubble[0] - bubbles[:, 0],
bubble[1] - bubbles[:, 1])
def outline_distance(self, bubble, bubbles):
center_distance = self.center_distance(bubble, bubbles)
return center_distance - bubble[2] - \
bubbles[:, 2] - self.bubble_spacing
def check_collisions(self, bubble, bubbles):
distance = self.outline_distance(bubble, bubbles)
return len(distance[distance < 0])
def collides_with(self, bubble, bubbles):
distance = self.outline_distance(bubble, bubbles)
idx_min = np.argmin(distance)
return idx_min if type(idx_min) == np.ndarray else [idx_min]
def collapse(self, n_iterations=50):
"""
Move bubbles to the center of mass.
Parameters
----------
n_iterations : int, default: 50
Number of moves to perform.
"""
for _i in range(n_iterations):
moves = 0
for i in range(len(self.bubbles)):
rest_bub = np.delete(self.bubbles, i, 0)
# try to move directly towards the center of mass
# direction vector from bubble to the center of mass
dir_vec = self.com - self.bubbles[i, :2]
# shorten direction vector to have length of 1
dir_vec = dir_vec / np.sqrt(dir_vec.dot(dir_vec))
# calculate new bubble position
new_point = self.bubbles[i, :2] + dir_vec * self.step_dist
new_bubble = np.append(new_point, self.bubbles[i, 2:4])
# check whether new bubble collides with other bubbles
if not self.check_collisions(new_bubble, rest_bub):
self.bubbles[i, :] = new_bubble
self.com = self.center_of_mass()
moves += 1
else:
# try to move around a bubble that you collide with
# find colliding bubble
for colliding in self.collides_with(new_bubble, rest_bub):
# calculate direction vector
dir_vec = rest_bub[colliding, :2] - self.bubbles[i, :2]
dir_vec = dir_vec / np.sqrt(dir_vec.dot(dir_vec))
# calculate orthogonal vector
orth = np.array([dir_vec[1], -dir_vec[0]])
# test which direction to go
new_point1 = (self.bubbles[i, :2] + orth *
self.step_dist)
new_point2 = (self.bubbles[i, :2] - orth *
self.step_dist)
dist1 = self.center_distance(
self.com, np.array([new_point1]))
dist2 = self.center_distance(
self.com, np.array([new_point2]))
new_point = new_point1 if dist1 < dist2 else new_point2
new_bubble = np.append(new_point, self.bubbles[i, 2:4])
if not self.check_collisions(new_bubble, rest_bub):
self.bubbles[i, :] = new_bubble
self.com = self.center_of_mass()
if moves / len(self.bubbles) < 0.1:
self.step_dist = self.step_dist / 2
def print_time_elapsed(s):
rhs = str(datetime.timedelta(seconds=s % 3600))[:-7]
lhs = s // 3600
if lhs == 0:
return rhs
else:
return f'{lhs:.0f}{rhs[1:]}'
p = argparse.ArgumentParser()
p.add_argument('--in', help="""path to JSON file""", required=True)
p.add_argument('--out', help="output path (e.g. a png or svg path)", required=True)
p.add_argument('-o',
help="Overwrite if --out exists. Fail otherwise",
action="store_true")
args = p.parse_args()
print(args)
if args.o == False and os.path.exists(args.out):
raise NameError("{} exists!! Pass -o to overrite it".format(args.out))
j = json.loads(open(dict(args._get_kwargs())['in']).read())
print(j.keys())
print(j['config'])
print(j['hostname'])
print()
print('> SPAN:')
print(j['span'].keys())
print(j['span']['mem'].keys())
print(j['span']['mem']['count'].keys())
print()
print('> GC:')
print(j['gc'].keys())
print(j['gc']['major_collections'].keys())
print(j['gc']['major_collections']['diff_per_block'].keys())
print()
print(j['span']['mem']['count']['min_value'])
print(j['span']['mem']['count']['max_value'])
print(j['span']['mem']['count']['mean'])
print(j['span']['mem']['cumu_count']['diff'])
block_count = j['block_count']
total_op_count = j['op_count']
total_wall = j['elapsed_wall']
print('total_op_count', total_op_count)
print('block_count', block_count)
print('total_wall', total_wall, total_wall / 3600)
colors = {
# https://coolors.co/palettes/trending
# # https://coolors.co/d9ed92-b5e48c-99d98c-76c893-52b69a-34a0a4-168aad-1a759f-1e6091-184e77
# 'checkout': '#d9ed92',
# 'find': '#b5e48c',
# 'mem': '#99d98c',
# 'mem_tree': '#76c893',
# 'add': '#52b69a',
# 'remove': '#34a0a4',
# 'copy': '#168aad',
# 'commit': '#1a759f',
# 'unseen': '#1e6091',
# 'buildup': '#184e77',
# https://coolors.co/03045e-023e8a-0077b6-0096c7-00b4d8-48cae4-90e0ef-ade8f4-caf0f8
'': '#03045e',
'copy': '#023e8a',
'mem': '#0077b6',
'commit': '#0096c7',
'add': '#00b4d8', 'checkout': '#00b4d8',
'remove': '#48cae4',
'find': '#90e0ef',
'mem_tree': '#ade8f4',
'unseen': '#caf0f8',
}
labels = dict(
unseen='in-between ops',
buildup='others',
)
# https://plotly.com/python/pie-charts/
# https://matplotlib.org/stable/gallery/misc/packed_bubbles.html#sphx-glr-gallery-misc-packed-bubbles-py
rows = []
for opk in sorted(j['span'].keys()):
rows.append(dict(label=labels.get(opk, opk),
key=opk,
average_duration=j['span'][opk]['duration']['mean'],
count_per_block=j['span'][opk]['count']['mean'],
explode=0.2 if opk == 'buildup' else 0,
color=colors.get(opk, 'grey')))
df0 = pd.DataFrame(rows)
# **************************************************************************************************
# **************************************************************************************************
# **************************************************************************************************
plt.close('all')
fig, ax = plt.subplots(figsize=np.asarray([10, 5]) * 0.6666)
ax2 = ax.twinx()
ax.set_yscale('log')
# ax2.set_yscale('linear')
y0 = np.asarray(j['index']['bytes_written']['value_after_commit']['evolution']).astype('float')
x = np.linspace(0, block_count - 1, y0.size)
ax.plot(x, y0, label='written so far', color=colors['mem'])
ax.annotate(
f"{y0[-1] / 1e12:.0f}TB",
[(block_count - 1) * 1.01 , y0[-1]], verticalalignment="center", horizontalalignment='left',
)
y1 = np.asarray([d['value_after_commit']['evolution'] for d in j['disk'].values()]).astype(float).sum(axis=0)
ax.plot(x, y1, label='irmin-pack', color=colors['find'])
ax.annotate(
f"{y1[-1] / 1e9:.0f}GB",
[(block_count - 1) * 1.01 , y1[-1]], verticalalignment="center", horizontalalignment='left',
)
y2 = y0 / y1
ax2.plot(x, y2, '--', label='write amplification', color='grey')
ax2.annotate(
f"x{y2[-1]:.0f}",
[(block_count - 1) * 1.01 , y2[-1]], verticalalignment="center", horizontalalignment='left',
)
ax.set_ylim(100_000_000, 10 ** (np.log10(y0.max()) * 1.025))
ax.set_yticks([
1e9,
1e10,
1e11,
1e12,
1e13,
# 1e14,
])
ax.minorticks_off()
ax2.set_ylim(1, np.nanmax(y2) * 1.2)
ax2.set_yticks([1, 100, 200, 300])
ax2.set_yticklabels(["x1", "x100", "x200", "x300"])
ax.set_yticklabels([
"1GB",
"10GB",
"100GB",
"1TB",
"10TB",
# "100TB",
])
ax.set_xticks(
[
0,
# 28_083,
204_762,
458_753,
655_361,
851_969,
1_212_417,
1_343_489,
# 1_466_367,
])
ax.set_xticklabels(
[
"genesis",
# "alpha II",
"alpha III",
"athens A",
"babylon",
"carthage",
"dephi",
'edo',
# "florence",
])
ax.set_xlim(0 - block_count * 0.05, block_count * 1.12)
ax.xaxis.grid()
# ax.grid(which='x')
ax.legend(loc='upper left')
ax2.legend(loc='lower right')
fig.tight_layout()
plt.savefig('write_amplif.png', dpi=150)
# **************************************************************************************************
# **************************************************************************************************
# **************************************************************************************************
plt.close('all')
fig, ax = plt.subplots(figsize=np.asarray([10, 4]) * 0.6666)
y = np.asarray(j['gc']['major_heap_bytes']['value_after_commit']['evolution']).astype('float') / 1e9
x = np.linspace(0, block_count - 1, y.size)
ax.plot(x, y, label='smoothed average', color=colors['copy'])
ax.annotate(
f"{y[-1]:.2f}GB",
[(block_count - 1) * 1.01 , y[-1]], verticalalignment="center", horizontalalignment='left',
)
y = np.asarray(j['gc']['major_heap_top_bytes']).astype('float') / 1e9
mask = np.r_[True, y[1:] != y[:-1]]
ax.plot([0, block_count - 1], [y.max(), y.max()], color=colors['remove'])
ax.plot([x[mask][-1]], [y[mask][-1]], 'x', label='highest recorded', color=colors['remove'])
ax.annotate(
f"{y.max():.2f}GB",
[(block_count - 1) * 1.01 , y.max()], verticalalignment="center", horizontalalignment='left',
)
ax.set_yticks([0, 1, 2, 3])
ax.set_yticklabels(
[
'0',
'1GB',
'2GB',
'3GB',
])
ax.set_ylim(0, y.max() * 1.08)
ax.set_xticks(
[
0,
# 28_083,
204_762,
458_753,
655_361,
851_969,
1_212_417,
1_343_489,
# 1_466_367,
])
ax.set_xticklabels(
[
"genesis",
# "alpha II",
"alpha III",
"athens A",
"babylon",
"carthage",
"dephi",
'edo',
# "florence",
])
ax.set_xlim(0 - (block_count / 40), block_count * 1.12)
ax.grid()
ax.legend(loc='lower right')
fig.tight_layout()
plt.savefig('memory.png', dpi=150)
# **************************************************************************************************
# **************************************************************************************************
# **************************************************************************************************
plt.close('all')
fig, ax = plt.subplots(subplot_kw=dict(aspect="equal"), figsize=(5, 5))
df = df0.set_index('key').loc['checkout find mem mem_tree add remove copy commit'.split(' ')].reset_index()
index = list(df.index)
seed = int(np.random.rand() * 1000)
seed = 642
np.random.RandomState(seed).shuffle(index)
print("seed!", seed)
df = df.loc[index]
print(df)
bubble_chart = BubbleChart(area=df['count_per_block'], bubble_spacing=4)
bubble_chart.collapse(5)
for i in range(len(bubble_chart.bubbles)):
row = df.iloc[i]
circ = plt.Circle(
bubble_chart.bubbles[i, :2], bubble_chart.bubbles[i, 2], color=row['color'])
ax.add_patch(circ)
text = row['label'] + '\n{:.1f}'.format(row['count_per_block'])
if row['label'] in 'commit remove checkout copy mem_tree'.split(' '):
ax.text(bubble_chart.bubbles[i, 0] + bubble_chart.bubbles[i, 2] / 2 * 1.8 + 1,
bubble_chart.bubbles[i, 1],
text,
horizontalalignment='left', verticalalignment='center',
)
else:
ax.text(*bubble_chart.bubbles[i, :2], text,
horizontalalignment='center', verticalalignment='center')
ax.axis("off")
ax.relim()
ax.autoscale_view()
# ax.set_title('Average Operation Count per Block')
plt.tight_layout()
plt.savefig('counts.png', dpi=100)
# **************************************************************************************************
# **************************************************************************************************
# **************************************************************************************************
plt.close('all')
fig, [ax0, ax1] = plt.subplots(ncols=2, subplot_kw=dict(aspect="equal"), figsize=np.asarray([10, 5]) * 0.75)
df = df0.set_index('key').loc['buildup commit unseen'.split(' ')].reset_index()
print(df)
def mypct(v):
return f'{v:.1f}%'
ax0.set_title('All')
wedges, labs, pcts = ax0.pie(df.average_duration,
labels=df.label,
explode=df['explode'],
autopct=mypct,
pctdistance=0.76,
# shadow=True,
# textprops=dict(fontsize=10),
rotatelabels=True,
labeldistance=1.03,
startangle=360 / df['average_duration'].sum() * df.set_index('key').loc['buildup', 'average_duration'] / -2,
colors=df['color'],
normalize=True,
)
for t in pcts:
t.set_fontsize(9)
df = df0.set_index('key').loc['copy find mem checkout mem_tree add remove'.split(' ')].reset_index()
print(df)
def mypct(v):
v *= df0.set_index('key').loc['buildup'].average_duration / df0.set_index('key').loc['block'].average_duration
return f'{v:.2f}%'
ax1.set_title('Others')
wedges, labs, pcts = ax1.pie(df.average_duration,
labels=df.label,
explode=df['explode'],
autopct=mypct,
pctdistance=0.76,
# shadow=True,
rotatelabels=True,
labeldistance=1.03,
startangle=360 / df['average_duration'].sum() * df.set_index('key').loc['copy', 'average_duration'] / -2 + 180,
colors=df['color'],
normalize=True,
)
for t in pcts:
t.set_fontsize(9)
plt.tight_layout()
plt.savefig('durations.png', dpi=150)
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"execution": {
"iopub.execute_input": "2021-02-05T13:28:18.026671Z",
"iopub.status.busy": "2021-02-05T13:28:18.025478Z",
"iopub.status.idle": "2021-02-05T13:28:18.028777Z",
"shell.execute_reply": "2021-02-05T13:28:18.029442Z"
},
"papermill": {
"duration": 0.020892,
"end_time": "2021-02-05T13:28:18.029850",
"exception": false,
"start_time": "2021-02-05T13:28:18.008958",
"status": "completed"
},
"tags": [
"parameters"
]
},
"outputs": [],
"source": [
"args = \"--help\""
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"execution": {
"iopub.execute_input": "2021-02-05T13:28:18.043793Z",
"iopub.status.busy": "2021-02-05T13:28:18.042796Z",
"iopub.status.idle": "2021-02-05T13:28:18.044819Z",
"shell.execute_reply": "2021-02-05T13:28:18.045196Z"
},
"papermill": {
"duration": 0.009787,
"end_time": "2021-02-05T13:28:18.045468",
"exception": false,
"start_time": "2021-02-05T13:28:18.035681",
"status": "completed"
},
"tags": [
"injected-parameters"
]
},
"outputs": [],
"source": [
"# Parameters\n",
"args = \"--in /Users/nico/r/irmin/tree_normal.json --out here.svg -o\"\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"execution": {
"iopub.execute_input": "2021-02-05T13:28:18.058241Z",
"iopub.status.busy": "2021-02-05T13:28:18.057618Z",
"iopub.status.idle": "2021-02-05T13:28:18.852934Z",
"shell.execute_reply": "2021-02-05T13:28:18.853286Z"
},
"papermill": {
"duration": 0.804709,
"end_time": "2021-02-05T13:28:18.853623",
"exception": false,
"start_time": "2021-02-05T13:28:18.048914",
"status": "completed"
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arguments: --in /Users/nico/r/irmin/tree_normal.json --out here.svg -o\n",
"Namespace(in='/Users/nico/r/irmin/tree_normal.json', out='here.svg', o=True)\n"
]
}
],
"source": [
"\"\"\"Plot distribution of timings out of bench/tree.exe on boostrap trace\n",
"\n",
"Formatted using YAPF\n",
"\n",
"To re-evalute from command line using papermill:\n",
"papermill tree.ipynb tree.ipynb --parameters_raw args '--in /Users/nico/r/irmin/tree_normal.json --out here.svg -o'\n",
"\n",
"To generate output from command line using papermill:\n",
"papermill tree.ipynb /dev/null --parameters_raw args '--in /Users/nico/r/irmin/tree_normal.json --out here.svg -o'\n",
"\n",
"\"\"\"\n",
"import argparse\n",
"import json\n",
"import os\n",
"\n",
"import pandas as pd\n",
"import numpy as np\n",
"import seaborn as sns\n",
"import matplotlib\n",
"import matplotlib.pyplot as plt\n",
"\n",
"# TODO: Stabilize width of plot and location of legend\n",
"# TODO: Legend: % / Total time / Total duration\n",
"sns.set_theme(style=\"ticks\", color_codes=True)\n",
"plt.rcParams[\"legend.labelspacing\"] = 1.7\n",
"\n",
"p = argparse.ArgumentParser()\n",
"p.add_argument('--in',\n",
" help=\"\"\"path to JSON file.\n",
"Pseudo schema:\n",
"{\n",
" \"revision\" : string;\n",
" \"flatten\": int;\n",
" \"inode_config\": string;\n",
" \"points\": (string -> (int * float) array) array;\n",
"}\n",
"\"\"\")\n",
"p.add_argument('--out', help=\"Output path (png, svg, etc...)\", required=True)\n",
"p.add_argument('-o',\n",
" help=\"Overwrite if --out exists. Fail otherwise\",\n",
" action=\"store_true\")\n",
"print(\"Arguments:\", args)\n",
"args = p.parse_args(args.split(\" \"))\n",
"print(args)\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"execution": {
"iopub.execute_input": "2021-02-05T13:28:18.869548Z",
"iopub.status.busy": "2021-02-05T13:28:18.868990Z",
"iopub.status.idle": "2021-02-05T13:28:18.898709Z",
"shell.execute_reply": "2021-02-05T13:28:18.899105Z"
},
"papermill": {
"duration": 0.042412,
"end_time": "2021-02-05T13:28:18.899346",
"exception": false,
"start_time": "2021-02-05T13:28:18.856934",
"status": "completed"
},
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"column 0 : k:Add points:32 samples:895,827 mean-sample:3.237279300\n",
"column 1 : k:Checkout points:32 samples:13,314 mean-sample:0.035112488\n",
"column 2 : k:Commit points:32 samples:13,315 mean-sample:50.901424000\n",
"column 3 : k:Copy points:32 samples:59 mean-sample:0.000813229\n",
"column 4 : k:Find points:32 samples:2,950,152 mean-sample:20.281050592\n",
"column 5 : k:Mem points:32 samples:669,692 mean-sample:3.754693640\n",
"column 6 : k:Mem_tree points:32 samples:439,329 mean-sample:0.560409150\n",
"column 7 : k:Remove points:32 samples:54,196 mean-sample:1.796043052\n",
"Stats per op -----------------\n",
" op n duration mean_duration\n",
"0 Add 895827 3.237279 0.000004\n",
"1 Checkout 13314 0.035112 0.000003\n",
"2 Commit 13315 50.901424 0.003823\n",
"3 Copy 59 0.000813 0.000014\n",
"4 Find 2950152 20.281051 0.000007\n",
"5 Mem 669692 3.754694 0.000006\n",
"6 Mem_tree 439329 0.560409 0.000001\n",
"7 Remove 54196 1.796043 0.000033\n",
"All data points -----------------\n",
" n center op duration of call (log scale) logn\n",
"0 887056 0.000002 Add 0.000002 6.0\n",
"1 3418 0.000109 Add 0.000109 4.0\n",
"2 3779 0.000184 Add 0.000184 4.0\n",
"3 722 0.000274 Add 0.000274 3.0\n",
"4 230 0.000349 Add 0.000349 3.0\n",
".. ... ... ... ... ...\n",
"27 3 0.002702 Remove 0.002702 1.0\n",
"28 1 0.002954 Remove 0.002954 0.0\n",
"29 1 0.003122 Remove 0.003122 0.0\n",
"30 1 0.005120 Remove 0.005120 0.0\n",
"31 1 0.019970 Remove 0.019970 0.0\n",
"\n",
"[256 rows x 5 columns]\n"
]
}
],
"source": [
"j = json.loads(open(dict(args._get_kwargs())['in']).read())\n",
"if args.o == False and os.path.exists(args.out):\n",
" raise NameError(\"{} exists!! Pass -o to overrite it\".format(args.out))\n",
"\n",
"columns = []\n",
"for i, k in enumerate(sorted(j[\"points\"].keys())):\n",
" df = pd.DataFrame(j[\"points\"][k], columns=['n', 'center'])\n",
" n = df.n.sum()\n",
" mean = (df.center * df.n).sum()\n",
" df['op'] = k\n",
" print(f\"column {i:<2d}: k:{k:<15s} points:{len(df):<3d} \"\n",
" f\"samples:{n:<10,d} mean-sample:{mean:<.9f}\")\n",
" columns.append(df)\n",
"df = pd.concat(columns)\n",
"\n",
"print(\"Stats per op -----------------\")\n",
"df1 = df.copy()\n",
"df1['duration'] = df1.center * df1.n\n",
"df1 = df1.groupby('op').sum().drop(columns=['center']).reset_index()\n",
"df1['mean_duration'] = df1.duration / df1.n\n",
"print(df1)\n",
"\n",
"print(\"All data points -----------------\")\n",
"ylab = 'duration of call (log scale)'\n",
"df[ylab] = df.center\n",
"df['logn'] = np.ceil(np.log10(df.n))\n",
"print(df)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"execution": {
"iopub.execute_input": "2021-02-05T13:28:18.945897Z",
"iopub.status.busy": "2021-02-05T13:28:18.945353Z",
"iopub.status.idle": "2021-02-05T13:28:19.643799Z",
"shell.execute_reply": "2021-02-05T13:28:19.644272Z"
},
"papermill": {
"duration": 0.741528,
"end_time": "2021-02-05T13:28:19.644513",
"exception": false,
"start_time": "2021-02-05T13:28:18.902985",
"status": "completed"
},
"tags": []
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAssAAAGkCAYAAADHQmjJAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8vihELAAAACXBIWXMAAAsTAAALEwEAmpwYAADjnUlEQVR4nOzdd5wU9f348ddsb9c73NEFROwloghR/GEDBWyoUTDWxG5EBYlEbGhI1IjGkGLUaNDYSNQYFRT8ChpjoSiClOMK19v2MjOf3x8LK+dxNIFr7+fjccrOzcy+Z2929r2f+XzeH00ppRBCCCGEEEK0YenoAIQQQgghhOisJFkWQgghhBCiHZIsCyGEEEII0Q5JloUQQgghhGiHJMtCCCGEEEK0Q5JlIYQQQggh2iHJcgf55JNPGDduXIc/j9/vZ/LkyQD89Kc/pbGxcb/H1BmVl5dzww03AFBRUcGRRx75g/b36quvcs011+yL0IDW8e3MzJkzWb169T573gO9/53529/+xvPPP98hz70zjz32GK+//joA8+bN47333tvjfSiluOOOO/jzn/+cWhYIBLjxxhsZN24cZ555JvPnz0/97uOPP2bSpEmcffbZXHDBBaxcubLV/uLxOJdffjlvv/12q/0deuihnHPOOamfjz/+eIfxrFu3jhtvvLHN8ldffZUf//jHXHHFFdx5552t4t2RQCDAZZddlnq8t69Pe+68805OOumkVsd0zjnnUFNTs9PthgwZsk+vdTfeeCPffvttq2V///vfW/3NfqhrrrmGV199dZ/tb29s//ff/rzfXaeccgqnnXYa//jHP3Z6fq9cuZLJkydzzjnnMH78eBYuXLjLfZumycMPP8xZZ53F+PHjuf7661N/47Vr13LkkUe2Okc2btyY+t2ll17KhAkTmDRpEqtXr6aqqopzzjmH4cOHs2rVqj06RtE92To6ANGx3n//fUaNGgXARx991MHRdJwtW7awadOmjg6jXbsb37Jly7jwwgv3Wxz7e/87s2jRIh544IEOee6duemmm1L//uSTTxg0aNAebb9hwwbuueceVq5cyeDBg1PLH3vsMQoKCvjd735HOBxm3LhxHHvssRxyyCHccsst/PnPf2bYsGG8//77TJs2jf/85z8AfPHFF8yePZuNGze2+lt9+eWXHHvssfzlL3/ZZUzvvfceY8aMabP89ddf55ZbbuGcc87hzjvv3OV+WlpaWiUbe/P67MrUqVO54oor9uk+90Q8HqesrIyDDjqo1fKLLrqogyLaf7b/+++tuXPncuihh3Lfffft8Pw+4ogjuPHGG3nggQc44YQTqK6uZuLEiRx++OH069ev3f2+8sorfPXVV7z22ms4HA4efvhh5syZw8MPP8wXX3zBuHHjuPfee1ttE4lEuOKKK7j//vsZPXo07733Hrfddhtvv/02Cxcu5JRTTtnr4xTdiyTLHSgcDnPjjTeyefNm0tPTmT17Nv379ycejzN37lw+/fRTDMNg2LBhzJw5E5/PxymnnMLEiRNZvnx56tvvzTffDMDLL7/M008/jcViISsri4ceeij1PLfccgsbN24kFotx3333ccwxxwDJBOT6669n+vTpAEyZMoX58+dzySWXcNhhh7F27VpuvfVWDjvsMGbPnk1VVRWJRIKzzjqLa6+9FoDPP/+cuXPnEolEsFgsXH/99Zx88sltjnfDhg3cf//9NDc3YxgGl156Keeddx6vvfYaTzzxBAsXLkTTNM4991yuueYaJkyYwOLFi/n9739PIpHA5XJxxx137LDV97333mPevHmYponX62X69OkcdthhPP7441RWVlJXV0dlZSUFBQX8+te/Jj8/P7WtYRjMnDmTmpoarrjiCu655x4Mw+Duu+9m1apVBAIBpk2bxmmnnQbA73//e9555x1M06R3797MmjWLgoKCNjHV1dVxxRVXUFtbS+/evbn33nvJy8ujurqaX/3qV1RWVqKUYsKECVx55ZXtHschhxzSKr4//OEP3HvvvXz++efY7XaKi4t58MEHmT9/PrW1tdx22208/PDDzJ07l4yMDDZu3MhFF13EoYceyq9//Wvi8Th1dXWccMIJPPDAA1RUVHDppZdy0kknsWLFCpRS3H333alzZJtHHnlkr/YPyS9ljz76KKZp4vF4uOeeexg6dOhunzt+v59wOExRUVGb3+3ovC8qKuLFF1/kueeew2KxkJubyy9/+Uv69+/PnXfeicvlYt26dTQ0NHDKKaeQmZnJ+++/T11dHffddx8jRozYo/UOOuggXC4Xq1ev5uGHH8ZqtZKVlcWcOXMwTRNItgyedtpprFq1ipkzZ6Zay55//nnOP/98evXq1eq47rrrLgzDSJ1L8XictLQ0HA4HS5cuxW63o5SivLycrKys1HbPPfccv/jFL/jDH/7Qan9ffPEFzc3NXHDBBcTjcS644AIuvvjiNq8nwJIlS9q0ij7wwAOsWrWKiooKmpqa2vwNXnzxRRKJBC0tLVx11VVcfPHFTJ8+nWg0yjnnnMMFF1zQ6vUZPXr0Xl3nrrrqKiZPnrzDZH57mzZtYvbs2YRCIerq6hg6dCiPPvooTqcztU5dXR133HFH6nhGjx6dep5//OMf/P3vf8c0TTIzM/nlL3/JwIED2zzPsmXLGDFiRJvljz/+OE1NTdx99907PZ72ztOamhruvPNOamtr6dWrFw0NDal9t3ct3ZG9eX/4fD7Wrl1LdXU1Q4YM4aGHHuKxxx5r9ff/5ptvOOigg7jiiitYsmQJc+fOxWKxcPDBB7Ns2TJeeOEFiouLOeecc7jvvvs49NBDW8XV3vkdj8e57rrrOOGEEwAoLCwkOzub6urqnSbLgwYN4vbbb8fhcAAwfPhwXnjhBSB57peXlzNx4kSsVitXX301Y8eO5aOPPqKkpITRo0cDMGbMGIqLi9t9DtGDKdEhPv74YzV06FD12WefKaWUWrBggTrvvPOUUko9/vjjas6cOco0TaWUUr/5zW/UrFmzlFJKnXzyyWrOnDlKKaWqq6vVoYceqsrKytSaNWvUj370I7VlyxallFJPP/20+uUvf6k+/vhjdfDBB6svv/wytfyyyy5TSikVi8XU2WefnYpp8ODBqqGhIfU88+bNS/3u0ksvVYsWLVJKKRWNRtWll16q3nzzTdXc3KzGjh2rysvLUzGNGjVKVVZWtjreRCKhzjzzTLV69WqllFJ+v1+dccYZ6osvvlBKKXXrrbeqWbNmqenTp6uZM2cqpZTatGmTGjdunGpsbFRKKbVu3Tp14oknqlAo1Grf69evVyeccIIqKytTSim1bNkydeKJJ6pAIKB+97vfqTFjxqhAIKCUUuqaa65Rjz322A7/HmeddZZSSqny8nI1ePBg9fbbbyullHrnnXfUmDFjlFJKvfbaa+rmm29WiUQi9Xe78sor2+zvlVdeUUcccYQqLS1N/Q1vuukmpZRSl1xyifrLX/6Seh3Gjx+v3njjjZ0ex/bxffrpp+r0009PnR8PP/xw6jw6+eST1cqVK5VSSv3kJz9R06dPT8V0yy23qI8//lgppVQwGFQ/+tGP1KpVq1LH+89//lMppdQHH3ygTjzxRBWPx9sc197sv66uTh199NHqq6++Ukop9Z///EddccUVu33uKKXUwoULW52P27R33i9btkydeuqpqfP5lVdeUWeccYYyTVPdcccd6vzzz1fxeFzV1taqwYMHq2effVYppdRf//pXdfnllyul1B6t96c//Sn1mvz73/9WSil12WWXqTfeeCMV569+9as28W9v+/1s7xe/+IUaPny4uuWWW5Su66nldXV1auTIkeqQQw5R7777bpvtto9FKaXmzZunHn/8cRWLxVR1dbUaO3bsDrerrq5WU6dO3WGM2+9zW7zBYFBdcMEFqffpF198oY444gilVPK9tO3f399+b65zO3rNRo4cqc4+++zUz0svvaSUUmrOnDnq9ddfV0opFY/H1bhx41Lv6W3Xunnz5qlf/vKXSimlQqGQuvnmm5Xf71effPKJuvjii1U4HFZKKfXhhx+q008/fYevyV133aU+/fTTNst/97vfqXvuuWenx7Oz8/TnP/+5euSRR5RSSpWWlqojjjhCvfLKK7u8lm5vb98fF154oYrFYioej6sJEyaol19+uc3fb9vfv7GxUR133HFqzZo1SimlXn31VTV48ODU+3p7218/tmnv/N5mwYIFavTo0SoSiezw9d+R5uZmddZZZ6nnnntOKaXUrFmz1N/+9jel67pav369Ov7449XKlSvV/Pnz1Q033KCmT5+uJk6cqKZMmZJ6XduLV/RM0rLcgYYMGcJRRx0FwMSJE/nVr35FIBDggw8+IBAIsGzZMgASiQQ5OTmp7ba1qBQUFJCTk0NLSwuffvopI0eOTLW8TZ06FUje9iwpKeHwww8HYOjQobzyyisALF++fIctIttsa1kMh8N8+umntLS08Nhjj6WWffPNN3i9Xurq6rjuuutS22maxtq1a1u1lJWWllJWVsaMGTNSy6LRKF9//TVHHHEE99xzD+eccw4ulyvVL++jjz6itrY2dSzb9l1WVsbQoUNTyz7++GOOP/54SkpKABgxYgTZ2dmpvrXHHXccPp8PgGHDhtHS0tLuMW9jt9tTLclDhw5Nteq8//77rFq1inPPPRdI9pOLRCI73McJJ5xA3759ATjvvPM477zzCIfDfP7556lb4WlpaUyaNImlS5fS3Nzc7nFompba7+DBg7FarZx//vmMHDmS0047jcMOO2yHMWzfOjxnzhyWLl3KU089lbrLEA6HyczMJCMjg/HjxwPJ1jWr1cratWsZPnz4Tl+n3dn/559/zkEHHcSwYcMAGDt2LGPHjmXJkiW7de5A8g7Iz3/+8zbPv3z58h2e9w8//DBnnnkm2dnZAEyaNIn777+fiooKAE4++WTsdjt5eXl4PB5OOukkAPr06UNzc3Nq/7u73o6cccYZzJ49m8WLF3PCCSdw66237nT99sydO5d77rmHG2+8kSeeeCLVlzg3N5cPP/yQr776iqlTpzJw4ED69+/f7n62f50LCgq48MILeffddzn11FNbrffee+/t0e1nr9fLU089xZIlSygtLeWbb74hHA7vcru9uc5te29sr71uGNOmTeOjjz7ij3/8I6WlpdTW1raJ66STTuLqq6+mqqqKE044gV/84hekpaXxwQcfsHnz5tR4Dkje3WhubiYzMzO1TCnFihUrmD179i6Pd0fH8+GHH7Z7ni5btow77rgDgL59+/KjH/0I2PW1dHt7+/446aSTUi20gwcP3uk183//+x8DBw5MXZMnTpzIfffdt8vXY5v2zm+A+fPn8+yzz/KnP/0Jl8u1W/srKyvjuuuu46ijjuKSSy4B4Fe/+lXq9wMHDuTMM8/k/fffx263s2TJEp599lkOP/xw3nvvPa6++mref//91PELAdINo0NZLK3HV2qahs1mwzRNZsyYkbo1FAqFiMViqfW2v42oaRpKKaxWa6uEKhqNUllZCSQTv++vD8kPxbPPPrvd+DweD5BMCJVSLFiwALfbDUBjYyNOp5NPPvmEgQMH8o9//CO1XU1NTeoivI1hGKSlpbUaqFFfX09aWhoADQ0NxGIx4vE4tbW1lJSUYJomI0aM4NFHH01tU1VV1aoLxbb4tj92SH6I6boO0Ooiu/3x78z3X7Ptn+vKK69M3b6Ox+PtfpBYrdZW2237237/+U3TRNf1nR7H9vGkp6ezcOFCPv/8cz7++GNuvvlmrrjiitQHw/a2/Q0BfvKTnzBkyBBOOukkzjjjjFSXi+/Hui2m7y/bkd3Z//fPTaUUa9euxTCM3Tp34vE4paWlDBkypM3zt3feb+v6sL3tz4nvfxDabDu+FO7uejsyefJkTj75ZD766CM+/PBD5s2bx9tvv93q/bszH374IYMHD6agoACv18tZZ53FO++8QyAQ4OOPP+b//b//B8AhhxzC0KFDWbdu3U6T5eeee44xY8akvogopXZ4PIsXL96t5G+b6upqLrzwQi644AKOPvpoTj/9dN5///1dbrc317k9ceutt2IYBmeccQY//vGPqaqqarOPww47jEWLFrF8+XI+/vhjzj//fP74xz9imibnnHMO06ZNS8VaW1tLRkZGq+2/+OILhg8f3uZaviM7Op6dnaffP+Ztf6udXUsfe+wxFi9eDCQH02VlZe3V+2NPrplWq7XN73fn9Wjv/Ibke/7OO+9k/fr1LFiwYLe7Rnz88cfccsstXHnllakvUIZhMH/+fC699NJUo8m2cz8/P5+BAwemGpNOPfVUZs6cSXl5+Q673IieS6phdKC1a9eyZs0aINlv7eijj8btdjNy5Eief/554vE4pmnyy1/+kt/+9rc73dePfvQjli9fTm1tLQALFizg17/+dbvrK6X48ssvUy3bkLzobbtYbs/n83HEEUfw9NNPA8kWlosuuohFixZxxBFHsHnzZj799FMA1qxZw2mnndZmNHr//v1xuVypC3xVVRXjxo1j9erVJBIJbr31Vm666Sauv/56brnlFhKJBCNGjOCjjz5iw4YNQLIf5dlnn000Gm217xEjRvB///d/lJeXA6T6BW67AO4Oq9VKIpHY5XojR47k5ZdfJhgMAslBWLfffvsO1/3kk0/YsmULkPx7jBo1Cp/Px+GHH56q6hAIBHj99dc54YQTdnoc28f3/vvvM3XqVI488khuuOEGJkyYkGpFb+9v6Pf7WbVqFbfddhtjx46lurqasrKy1IdmY2MjS5cuBZLJkt1ubzXYbPvXaU/3f/jhh7Nhw4ZUtYBFixYxbdq03T53li9fzvHHH7/D17i98/6kk07irbfeSo2Gf+WVV8jMzEy19O8v278+kydPZs2aNUyaNIl7770Xv99PXV3dbu/r3//+N0888QRKKeLxOP/+9785/vjjsVgszJgxg88++wyAb7/9lo0bN+7yfP/ss89S1Suam5t5+eWXOfPMM1utEwwGCQQC9O7de7fjXL16NdnZ2fz85z9n5MiRqUTZMAxsNhuGYbT6Urbt9dmb69ye+L//+z+uu+661DGuWLEi1Ud2m7lz5/Lkk09y6qmnctdddzFo0CC+/fZbRo4cyZtvvpk6r/7+978zZcqUNs+xaNGiNi3ze2Jn5+lJJ53Eiy++CCQH+H7yySfAzq+lN910EwsXLmThwoXcdNNNB+T9cdRRR6XuKAD85z//we/3t/ni/33tnd8At912G8FgcI8S5a+++orrr7+ehx56qNWdBqvVyuLFi3nppZcAqKys5J133uG0005j1KhRVFRUpK6fn376KZqmSb9l0Ya0LHegAQMGMG/ePMrLy8nJyWHOnDkA/PznP+ehhx5i4sSJGIbBwQcfvMuR50OGDGHatGmpgWJ5eXk88MADlJaW7nD9FStWMHz48Fath6effjqXXnopjz/+eJv1586dy7333sv48eOJx+OMGzcu1Sr9u9/9jocffphYLIZSiocffjh1sdl+cMeTTz7J/fffz5/+9Cd0Xeemm27i6KOP5qGHHiI3N5fzzz8fSLZ4P/LII9x+++3Mnj2bW2+9NdUS8Pvf/x6v19sqtkGDBjFr1iyuv/56DMPA5XLx1FNPpVqtd8egQYNwOp2cd955PPLII+2ud/7551NTU8MFF1yApmkUFRWl/m7fN3jwYGbMmEF9fT0DBgxItdbNnTuX2bNn8+qrrxKPxxk/fjyTJk1C07R2j2P7+F588UWWLl3KuHHj8Hg8ZGRkpEZ5/7//9/+YNm1aq9uOkGyNvvrqq5k4cSIej4eCggKOOuooNm/eTElJCU6nk4ULFzJ37lxcLhdPPPHEDluW92b/I0aMYO7cudxxxx0YhoHP5+ORRx4hOzt7p+fONosWLWq3/GF7531BQQFTp05lypQpmKZJdnY2f/jDH3arxeuHOOWUU/jtb39LIpHgtttu44EHHuDRRx9F0zSuv/56iouL2wzwa8+dd97JrFmzUt1jTj31VC677DIsFgtPPPEEDzzwALqu43A4mDt3LoWFhTvd3913383dd9/NWWedha7rXHLJJZx44omt1lmyZEmqOs7uOvHEE3n55Zc5/fTT0TSN4447juzsbDZv3kzfvn057LDDOOuss3j++edbvT57c52D3R/gd8stt3Ddddfh8Xjw+Xwce+yxlJWVtVpnypQp3HnnnYwbNw6Hw8GQIUM466yzcDgcXHXVVfz0pz9F0zR8Ph/z5s1rkwAuW7Zst0o6tufEE09s9zydNWsW06dP54wzzqCwsDDVzcHhcLR7Lf2+A/H+yMzM5Le//S133HEHFouF4cOHY7PZUnch2xvg1975/cUXX/Cf//yHfv36taooctttt6XKBO5of7/97W9RSvGb3/yG3/zmNwAUFxfzxBNPMHfuXGbNmsVrr72GYRjMmDEj1XL8xBNPcM899xCJRHA4HDz++OO7ffdH9Bya2tN7W0KIbqWiooLx48fzxRdfdHQoQoguJhgM8uSTT3LDDTfgdrv56quvuOaaa/jwww/bfLk45ZRTeOyxx9okunvikUce4eyzzz4g3ST2Rbyie5CWZSGEEELsFZ/Ph91u57zzzsNms2Gz2VJ3U3bktttu48orr0zdSdwTSil69+693xPlqqoqrr322lT3FSGkZVkIIYQQQoh2yAA/IYQQQggh2iHJshCi2/v73//eZka677vqqqtYv379AYoo6bHHHuP111/fq23POecc/H7/vg1ICCFEG9INQwghhBBCiHbIAD8hRKf3ySefcP/99+PxeAiFQtx000384Q9/IJFI4HK5uOOOOzjssMM45ZRTeOKJJ1IzD958880cd9xxNDQ00NTUxN13380LL7zAggULsNvtOJ1OZs+ezaBBg1qNfH/xxRd57rnnsFgs5Obm8stf/pL+/ftz55134vP5WLt2LdXV1QwZMoSHHnoIr9ebmt3ypptu4s4778TlcrFu3ToaGho45ZRTyMzM5P3336euro777ruPESNGcOedd3LQQQdxxRVX8Lvf/Y53330Xu91OVlYWDz74IPn5+e0uHzJkCMuXL+eDDz7g3XffxWKxsHnzZlwuFw899BADBw5k8+bNzJgxg5aWFvLy8lBKcfbZZzNp0qSO/HMKIUSXIsmyEKJL+Pbbb3nvvfdIJBLccMMNPPvss2RlZfHtt99y+eWX884773Duuefy6quvMnz4cFpaWli+fDn33nsvf/3rX4HkRBkPPPAAixcvJj8/n9dff53PPvuMQYMGpZ5n+fLl/OlPf+LFF18kOzubV199leuuu44333wTSE7C8eyzz6JpGhdccAFvv/025557LjfddFOreL/++muef/55mpubGTlyJDNnzmTBggU888wz/PGPf2w11XxVVRXPPPMMy5cvx+Fw8Je//IWVK1dyyCGH7HD59yfC+PTTT3njjTcoLCzk3nvvZf78+Tz00EPcfvvtnHPOOVx88cVs2LCBc889d6ezdgohhGhLkmUhRJdQVFRE7969ef7556mtrWXq1Kmp32maRllZGeeeey7nnXced955J2+88QannHJKq8lprFYrp59+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IYToRCwWC7/+9a+ZMGECI0eO3KNtx44dC0BJSQm5ubkMHToUgD59+tDS0pJab/LkyQAUFBRw4oknsnz5cqxWK7W1tUydOjW1nqZplJWVAXDEEUe0SZQBPv74Y44//nhKSkoAGDFiBNnZ2axevRpN09qNddmyZUybNg2AtLQ03njjDQDmzJnD0qVLeeqpp9i4cSOxWIxwOLzDZNlqtXL66aczefJkfvzjHzNy5EhGjx69W6+VDPATopPqledD00ABdpuFohyphiGEEKK1oqIi7rnnHu644w6amppSyzVNQ213RzKRSLTabvtuG3a7vd39WyzfpYqmaWKz2TBNkxEjRrBw4cLUz0svvcRBBx0EgMez488r0zTbJMVKKXRd3+kx2my2VtuVl5cTDAb5yU9+wpIlSxgwYADXXXcd+fn5rY75++bOnctTTz1Fnz59mD9/PrfeeutOn3cbSZaF6KT698rg5KNLOHZYAWOO6UNupiTLQggh2jr99NMZNWoUzzzzTGpZVlYWq1evBqCmpob//ve/e7Xv1157DYAtW7awfPlyRowYwYgRI/joo4/YsGEDAEuWLOHss88mGo3udF8jRozg//7v/ygvLwdg+fLlVFVVcfjhh+9yu1deeQWAQCDAlClTKC0tZdWqVdx2222MHTuW6upqysrKME1zh/tobGxk9OjRZGZmMnXqVG6++ebdrvQh3TCE6MQKc7wU5kgFDCGEEDs3c+ZMPvvss9TjSy+9lNtuu43TTjuN4uJijj/++L3abywWY+LEiSQSCWbOnEn//v0BmD17NrfeeitKqdSgQK93559XgwYNYtasWVx//fUYhoHL5eKpp54iLS1tp9vdfffd/OpXv2L8+PEopbjmmmsYPnw4V199NRMnTsTj8VBQUMBRRx3F5s2bU908tpednc3PfvYzpk6disvlwmq1ct999+3Wa6CpnbVXd1LbavE99dRTFBcX75N9VlRUMGbMGBYtWrTP9imEEEIIIbq2LtcNY8WKFVx00UWUlpZ2dChCCCGEEKKb63LJ8ksvvcSsWbPIz8/f4e+DwSBXX301kyZNYtKkSSxatOgARyiEEEIIIbqLLtdn+f7779/p799991169+7N/PnzWbNmDf/85z8ZM2ZMq3X8fj9+v7/Vsurq6n0eqxBCCCGE6Nq6XLK8K0ceeSS//e1vqamp4cc//jHX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jFhp9N5yrlRV5cknn+Sf//wner2eiy66iHnz5lFaWsqPf/xjhgwZwp49exg1ahTjxo1j1apV1NfX88c//pHCwkImTpzI1KlT+e9//4vBYOBHP/oRzzzzDAcPHuTuu+/mqquuYv78+Zx33nl8+eWXAHzzm9/kH//4R7efh4443XN22223xc5Zbm4uDz74IP/+97/ZsGEDv//974HoHQuz2cytt97ak0+xyzT9/z7vvPO4/fbbGTZsGNu3byctLY1HHnmElJQUXnvtNZ544gkcDgd5eXnYbLae7nZc2e12ioqK2LRpE+effz4A//3vf7nwwgsBWL9+PY8++ijhcJj8/Hx+/etfk5qa2q73U2/SExcFe/bsobq6usva7y6VlZVomobdbudPf/oTb731FpFIhIsvvph58+Zx5MiRdn0Gf/755yxZsoRAIEBqaiqLFy/G5/Mxb948Xn/9dSCaFvcf//gHTzzxRIvHUhSlh8+GaC+ZhhFn69atIzc3l8GDBzN58mReeuklgsEg8+fP59FHH2XlypVYLJbY4++++27uvPNOVq1a1SdKaH755ZcUFRXFApkmEyZMIC0tjaNHj7Jw4ULeeustqqqq+PDDD9m9ezcvv/wyf//731m9ejVpaWk8/fTTlJeXs3TpUp555hnefPNNIpEI69atA0DTNO69916ys7O56667qK6uZuHChfzxj3/k9ddf5+yzz242qnKiCy+8kIkTJ/KTn/ykRwJlOPW5Ki4u5t133+XVV19l1apVHDx4kL///e9ANIf43LlzWb16NZ999hlHjhzhpZdeYtq0abz00kuxdtLT01m5ciWFhYX86U9/4plnnuHBBx/kT3/6U7Pj3XvvvQC9PlCG0z9nu3bt4rvf/S5vvvkmhYWFLF++nKuuuoqPPvoIt9sNwBtvvME111zT7c+pK1RUVDSbgvGXv/yl2d937NjBnDlzeOONN3A6nbz++uuUl5fz0EMP8eKLL/LSSy/h8Xh6qPdd68orr4xNgdu6dSsjRozAaDRSU1PD73//e55++mlee+01Lr74Yh566KHYfu19P/UGdrudkSNHsmnTpti2Ey8KrrvuOmbMmMHtt99ObW0tABMnTuT3v/89s2bN4lvf+hbvvfceN910ExMmTGDNmjWtHq+hoYFHH32Ud999lyeeeIKVK1dy4403Mn36dP7whz9QVVXF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\n",
"text/plain": [
"<Figure size 720x432 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Seaborn plot ----------------\n",
"# https://seaborn.pydata.org/examples/scatter_bubbles.html\n",
"g = sns.relplot(\n",
" x=\"op\",\n",
" y=ylab,\n",
" size=\"logn\",\n",
" palette=\"muted\",\n",
" alpha=.5,\n",
" sizes=(20, 750),\n",
" height=6,\n",
" data=df,\n",
" legend=\"full\",\n",
" # facet_kws=dict(legend_out=True, )\n",
")\n",
"g.set(yscale=\"log\")\n",
"plt.grid(axis='y')\n",
"v = plt.plot(df1.op, df1.mean_duration, '_', color='red', alpha=0.66, ms=15, label=\"mean\")\n",
"\n",
"plt.legend(handles=v, loc=\"upper right\")\n",
"\n",
"# Legend ----------------\n",
"g.legend.set_title(\"Number of calls\")\n",
"\n",
"\n",
"def logn_to_txt(v):\n",
" if v == 0:\n",
" return \"1\"\n",
" v = 10**v\n",
" if v >= 1e9:\n",
" return '< {:.0f} G'.format(v / 1e9)\n",
" if v >= 1e6:\n",
" return '< {:.0f} M'.format(v / 1e6)\n",
" if v >= 1e3:\n",
" return '< {:.0f} K'.format(v / 1e3)\n",
" return '< {:.0f}'.format(v)\n",
"\n",
"\n",
"for txt in g.legend.texts:\n",
" # print(float(txt.get_text()), logn_to_txt(float(txt.get_text())))\n",
" txt.set_text(logn_to_txt(float(txt.get_text())))\n",
"\n",
"# Title ----------------\n",
"flatten = {\n",
" \"0\": False,\n",
" \"1\": True,\n",
" 0: False,\n",
" 1: True,\n",
"}[j[\"flatten\"]]\n",
"plt.title(\n",
" \"bench/tree.exe on the bootstrap trace / commits:{} / flatten:{} / inode-config:{}\\nrevision:{}\"\n",
" .format(\n",
" df.query('op == \"Commit\"').n.sum(),\n",
" flatten,\n",
" j[\"inode_config\"],\n",
" j[\"revision\"],\n",
" ))\n",
"\n",
"\n",
"# Tick label y ----------------\n",
"def time_to_txt(t):\n",
" if t < 1e-6:\n",
" return '{:.0f} ns'.format(t / 1e-9)\n",
" if t < 1e-3:\n",
" return '{:.0f} \\u03bcs'.format(t / 1e-6)\n",
" if t < 1:\n",
" return '{:.0f} ms'.format(t / 1e-3)\n",
" else:\n",
" return '{:.0f} s'.format(t)\n",
"\n",
"\n",
"locs, _ = plt.yticks()\n",
"plt.yticks(locs, [time_to_txt(v) for v in locs])\n",
"\n",
"# Save ----------------\n",
"# https://stackoverflow.com/a/56970556\n",
"g.fig.set_figwidth(10)\n",
"g.fig.set_figheight(6)\n",
"g.tight_layout()\n",
"g.savefig(args.out)\n"
]
}
],
"metadata": {
"celltoolbar": "Tags",
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.5"
},
"papermill": {
"default_parameters": {},
"duration": 2.991227,
"end_time": "2021-02-05T13:28:20.071048",
"environment_variables": {},
"exception": null,
"input_path": "tree.ipynb",
"output_path": "tree.ipynb",
"parameters": {
"args": "--in /Users/nico/r/irmin/tree_normal.json --out here.svg -o"
},
"start_time": "2021-02-05T13:28:17.079821",
"version": "2.3.2"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment