Skip to content

Commit 8166cea

Browse files
author
Can Gokmen
committed
Added the graphs creation folder
1 parent 4332325 commit 8166cea

7 files changed

Lines changed: 449 additions & 0 deletions

File tree

‎graphs/plot.py‎

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env python3
2+
"""Parse test_kfp output and draw the two bar charts (x = the 4 workloads).
3+
4+
timings.png — grouped bars: QuART_kfp<3,FF> vs ART insertion time (ms).
5+
stats.png — stacked bars: FP_INSERT / BRIDGE / NO_MATCH classification counts.
6+
7+
Usage: plot.py <times_raw.txt> <stats_raw.txt> <out_dir>
8+
"""
9+
import re
10+
import sys
11+
12+
import matplotlib
13+
14+
matplotlib.use("Agg")
15+
import matplotlib.pyplot as plt
16+
import numpy as np
17+
18+
WL_RE = re.compile(r"^Workload:\s*(.+?)\s*$")
19+
QUART_RE = re.compile(r"^QuART_kfp<3,FF>:\s*([\d.]+)\s*ms")
20+
ART_RE = re.compile(r"^ART:\s*([\d.]+)\s*ms")
21+
STATS_RE = re.compile(r"FP_INSERT=(\d+)\s+BRIDGE=(\d+)\s+NO_MATCH=(\d+)")
22+
23+
24+
def parse_times(path):
25+
"""Return ordered [(workload, quart_ms, art_ms), ...]."""
26+
rows, wl, quart = [], None, None
27+
for line in open(path):
28+
line = line.strip()
29+
m = WL_RE.match(line)
30+
if m:
31+
wl, quart = m.group(1), None
32+
continue
33+
m = QUART_RE.match(line)
34+
if m:
35+
quart = float(m.group(1))
36+
continue
37+
m = ART_RE.match(line)
38+
if m and wl is not None:
39+
rows.append((wl, quart, float(m.group(1))))
40+
wl = None
41+
return rows
42+
43+
44+
def parse_stats(path):
45+
"""Return ordered [(workload, fp_insert, bridge, no_match), ...]."""
46+
rows, wl = [], None
47+
for line in open(path):
48+
line = line.strip()
49+
m = WL_RE.match(line)
50+
if m:
51+
wl = m.group(1)
52+
continue
53+
m = STATS_RE.search(line)
54+
if m and wl is not None:
55+
rows.append((wl, int(m.group(1)), int(m.group(2)), int(m.group(3))))
56+
wl = None
57+
return rows
58+
59+
60+
def plot_timings(rows, out):
61+
labels = [r[0] for r in rows]
62+
quart = [r[1] for r in rows]
63+
art = [r[2] for r in rows]
64+
x = np.arange(len(labels))
65+
w = 0.38
66+
67+
fig, ax = plt.subplots(figsize=(9, 5.5))
68+
b1 = ax.bar(x - w / 2, quart, w, label="QuART_kfp<3,FF>", color="#2b8cbe")
69+
b2 = ax.bar(x + w / 2, art, w, label="ART", color="#bdbdbd")
70+
ax.set_ylabel("Insertion time (ms, lower is better)")
71+
ax.set_title("Insertion time by workload (stats OFF — clean timing)")
72+
ax.set_xticks(x)
73+
ax.set_xticklabels(labels, rotation=12, ha="right")
74+
ax.legend()
75+
ax.bar_label(b1, fmt="%.0f", padding=2, fontsize=8)
76+
ax.bar_label(b2, fmt="%.0f", padding=2, fontsize=8)
77+
# Annotate speedup over ART above each pair.
78+
for i, (_, q, a) in enumerate(rows):
79+
if q:
80+
ax.text(x[i], max(q, a) * 1.06, f"{a / q:.2f}x",
81+
ha="center", fontsize=9, fontweight="bold", color="#08589e")
82+
ax.margins(y=0.18)
83+
fig.tight_layout()
84+
fig.savefig(out, dpi=130)
85+
print("wrote", out)
86+
87+
88+
def plot_stats(rows, out):
89+
labels = [r[0] for r in rows]
90+
fp = np.array([r[1] for r in rows], dtype=float)
91+
bridge = np.array([r[2] for r in rows], dtype=float)
92+
nomatch = np.array([r[3] for r in rows], dtype=float)
93+
x = np.arange(len(labels))
94+
M = 1e6 # show counts in millions
95+
96+
fig, ax = plt.subplots(figsize=(9, 5.5))
97+
p1 = ax.bar(x, fp / M, label="FP_INSERT", color="#31a354")
98+
p2 = ax.bar(x, bridge / M, bottom=fp / M, label="BRIDGE", color="#fdae6b")
99+
p3 = ax.bar(x, nomatch / M, bottom=(fp + bridge) / M, label="NO_MATCH",
100+
color="#de2d26")
101+
ax.set_ylabel("Inserts (millions)")
102+
ax.set_title("k-fp classification by workload (stats ON)")
103+
ax.set_xticks(x)
104+
ax.set_xticklabels(labels, rotation=12, ha="right")
105+
ax.legend()
106+
# Percent-of-total label for the dominant FP_INSERT segment.
107+
total = fp + bridge + nomatch
108+
for i in range(len(labels)):
109+
if total[i] > 0:
110+
ax.text(x[i], (fp[i] / M) / 2, f"{100 * fp[i] / total[i]:.1f}%",
111+
ha="center", va="center", fontsize=8, color="white",
112+
fontweight="bold")
113+
fig.tight_layout()
114+
fig.savefig(out, dpi=130)
115+
print("wrote", out)
116+
117+
118+
def main():
119+
times_path, stats_path, out_dir = sys.argv[1], sys.argv[2], sys.argv[3]
120+
trows = parse_times(times_path)
121+
srows = parse_stats(stats_path)
122+
if not trows:
123+
sys.exit(f"no timing rows parsed from {times_path}")
124+
if not srows:
125+
sys.exit(f"no stat rows parsed from {stats_path}")
126+
plot_timings(trows, f"{out_dir}/timings.png")
127+
plot_stats(srows, f"{out_dir}/stats.png")
128+
129+
130+
if __name__ == "__main__":
131+
main()

‎graphs/run.log‎

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
==> [1/2] Building test_kfp with stats OFF (clean timings)
2+
In file included from /scratch/cgokmen/QuART/trees/QuART.h:247,
3+
from /scratch/cgokmen/QuART/trees/QuART_kfp.h:7,
4+
from /scratch/cgokmen/QuART/test_kfp.cpp:34:
5+
/scratch/cgokmen/QuART/trees/../QuArtNodeMethods.cpp: In member function ‘void ART::Node4::insertNode4PreserveFpPrefixExpansion(ART::ART*, ART::ArtNode**, uint8_t, ART::ArtNode*)’:
6+
/scratch/cgokmen/QuART/trees/../QuArtNodeMethods.cpp:152:65: warning: unused parameter ‘nodeRef’ [-Wunused-parameter]
7+
152 | ArtNode** nodeRef,
8+
| ~~~~~~~~~~^~~~~~~
9+
In file included from /scratch/cgokmen/QuART/test_kfp.cpp:35:
10+
/scratch/cgokmen/QuART/QuArtNodeBulkLoadMethods.cpp: In member function ‘void ART::Node256::bulkLoadInsertNode256(ART::ART*, ART::ArtNode**, uint8_t, ART::ArtNode*, ART::ArtNode*&)’:
11+
/scratch/cgokmen/QuART/QuArtNodeBulkLoadMethods.cpp:121:55: warning: unused parameter ‘bl_ptr’ [-Wunused-parameter]
12+
121 | ArtNode* child, ArtNode*& bl_ptr) {
13+
| ~~~~~~~~~~^~~~~~
14+
==> Running (max_keys_per_stream=50000000) ...
15+
════════════════════════════════════════════════════════════
16+
Workload: 3x K=L=0
17+
════════════════════════════════════════════════════════════
18+
Loaded stream 0: 200000000 keys
19+
Loaded stream 1: 200000000 keys
20+
Loaded stream 2: 200000000 keys
21+
Using 50000000 keys per stream (150000000 total)
22+
23+
Pre-loading 75000000 keys (50%) before timed run
24+
25+
QuART_kfp<3,FF>: 738 ms (101.5 M inserts/s, 75000000 timed keys)
26+
ART: 1470 ms (51.0 M inserts/s, 75000000 timed keys)
27+
28+
Speedup vs ART: FREQ_FILTER=1.99x
29+
30+
════════════════════════════════════════════════════════════
31+
Workload: 3x K=L=1
32+
════════════════════════════════════════════════════════════
33+
Loaded stream 0: 200000000 keys
34+
Loaded stream 1: 200000000 keys
35+
Loaded stream 2: 200000000 keys
36+
Using 50000000 keys per stream (150000000 total)
37+
38+
Pre-loading 75000000 keys (50.00%) before timed run
39+
40+
QuART_kfp<3,FF>: 845 ms (88.7 M inserts/s, 75000000 timed keys)
41+
ART: 1312 ms (57.1 M inserts/s, 75000000 timed keys)
42+
43+
Speedup vs ART: FREQ_FILTER=1.55x
44+
45+
════════════════════════════════════════════════════════════
46+
Workload: 3x K=L=25
47+
════════════════════════════════════════════════════════════
48+
Loaded stream 0: 200000000 keys
49+
Loaded stream 1: 200000000 keys
50+
Loaded stream 2: 200000000 keys
51+
Using 50000000 keys per stream (150000000 total)
52+
53+
Pre-loading 75000000 keys (50.00%) before timed run
54+
55+
QuART_kfp<3,FF>: 3747 ms (20.0 M inserts/s, 75000000 timed keys)
56+
ART: 3585 ms (20.9 M inserts/s, 75000000 timed keys)
57+
58+
Speedup vs ART: FREQ_FILTER=0.96x
59+
60+
════════════════════════════════════════════════════════════
61+
Workload: mixed K=L=0/1/25
62+
════════════════════════════════════════════════════════════
63+
Loaded stream 0: 200000000 keys
64+
Loaded stream 1: 200000000 keys
65+
Loaded stream 2: 200000000 keys
66+
Using 50000000 keys per stream (150000000 total)
67+
68+
Pre-loading 75000000 keys (50.00%) before timed run
69+
70+
QuART_kfp<3,FF>: 1896 ms (39.5 M inserts/s, 75000000 timed keys)
71+
ART: 2311 ms (32.4 M inserts/s, 75000000 timed keys)
72+
73+
Speedup vs ART: FREQ_FILTER=1.22x
74+
75+
76+
==> [2/2] Building test_kfp with stats ON (classification counts)
77+
In file included from /scratch/cgokmen/QuART/trees/QuART.h:247,
78+
from /scratch/cgokmen/QuART/trees/QuART_kfp.h:7,
79+
from /scratch/cgokmen/QuART/test_kfp.cpp:34:
80+
/scratch/cgokmen/QuART/trees/../QuArtNodeMethods.cpp: In member function ‘void ART::Node4::insertNode4PreserveFpPrefixExpansion(ART::ART*, ART::ArtNode**, uint8_t, ART::ArtNode*)’:
81+
/scratch/cgokmen/QuART/trees/../QuArtNodeMethods.cpp:152:65: warning: unused parameter ‘nodeRef’ [-Wunused-parameter]
82+
152 | ArtNode** nodeRef,
83+
| ~~~~~~~~~~^~~~~~~
84+
In file included from /scratch/cgokmen/QuART/test_kfp.cpp:35:
85+
/scratch/cgokmen/QuART/QuArtNodeBulkLoadMethods.cpp: In member function ‘void ART::Node256::bulkLoadInsertNode256(ART::ART*, ART::ArtNode**, uint8_t, ART::ArtNode*, ART::ArtNode*&)’:
86+
/scratch/cgokmen/QuART/QuArtNodeBulkLoadMethods.cpp:121:55: warning: unused parameter ‘bl_ptr’ [-Wunused-parameter]
87+
121 | ArtNode* child, ArtNode*& bl_ptr) {
88+
| ~~~~~~~~~~^~~~~~
89+
==> Running (max_keys_per_stream=50000000) ...
90+
════════════════════════════════════════════════════════════
91+
Workload: 3x K=L=0
92+
════════════════════════════════════════════════════════════
93+
Loaded stream 0: 200000000 keys
94+
Loaded stream 1: 200000000 keys
95+
Loaded stream 2: 200000000 keys
96+
Using 50000000 keys per stream (150000000 total)
97+
98+
Pre-loading 75000000 keys (50%) before timed run
99+
100+
QuART_kfp<3,FF>: 742 ms (101.0 M inserts/s, 75000000 timed keys)
101+
FP_INSERT=149414061 BRIDGE=585936 NO_MATCH=2 NO_MATCH_untracked=0 (fp_insert%=99.6%)
102+
hot-path fp types: Node4=1750947 Node16=7003788 Node48=18676768 Node256=120814965 (Node256%=81.5%)
103+
fp_not_last_byte=1167593
104+
105+
════════════════════════════════════════════════════════════
106+
Workload: 3x K=L=1
107+
════════════════════════════════════════════════════════════
108+
Loaded stream 0: 200000000 keys
109+
Loaded stream 1: 200000000 keys
110+
Loaded stream 2: 200000000 keys
111+
Using 50000000 keys per stream (150000000 total)
112+
113+
Pre-loading 75000000 keys (50.0%) before timed run
114+
115+
QuART_kfp<3,FF>: 873 ms (85.8 M inserts/s, 75000000 timed keys)
116+
FP_INSERT=147913112 BRIDGE=586326 NO_MATCH=1500561 NO_MATCH_untracked=1500427 (fp_insert%=98.6%)
117+
hot-path fp types: Node4=1442269 Node16=7024158 Node48=18749904 Node256=120530245 (Node256%=81.6%)
118+
fp_not_last_byte=166536
119+
120+
════════════════════════════════════════════════════════════
121+
Workload: 3x K=L=25
122+
════════════════════════════════════════════════════════════
123+
Loaded stream 0: 200000000 keys
124+
Loaded stream 1: 200000000 keys
125+
Loaded stream 2: 200000000 keys
126+
Using 50000000 keys per stream (150000000 total)
127+
128+
Pre-loading 75000000 keys (50.0%) before timed run
129+
130+
QuART_kfp<3,FF>: 3865 ms (19.4 M inserts/s, 75000000 timed keys)
131+
FP_INSERT=112945036 BRIDGE=586408 NO_MATCH=36468555 NO_MATCH_untracked=36468426 (fp_insert%=75.3%)
132+
hot-path fp types: Node4=84752 Node16=1322735 Node48=13679886 Node256=97847893 (Node256%=86.6%)
133+
fp_not_last_byte=9770
134+
135+
════════════════════════════════════════════════════════════
136+
Workload: mixed K=L=0/1/25
137+
════════════════════════════════════════════════════════════
138+
Loaded stream 0: 200000000 keys
139+
Loaded stream 1: 200000000 keys
140+
Loaded stream 2: 200000000 keys
141+
Using 50000000 keys per stream (150000000 total)
142+
143+
Pre-loading 75000000 keys (50.0%) before timed run
144+
145+
QuART_kfp<3,FF>: 1942 ms (38.6 M inserts/s, 75000000 timed keys)
146+
FP_INSERT=136760315 BRIDGE=586238 NO_MATCH=12653446 NO_MATCH_untracked=12653321 (fp_insert%=91.2%)
147+
hot-path fp types: Node4=1092734 Node16=5117188 Node48=17037483 Node256=113064749 (Node256%=82.9%)
148+
fp_not_last_byte=448161
149+
150+
151+
==> Plotting
152+
wrote /scratch/cgokmen/QuART/graphs/timings.png
153+
wrote /scratch/cgokmen/QuART/graphs/stats.png
154+
==> Done. Wrote:
155+
/scratch/cgokmen/QuART/graphs/timings.png
156+
/scratch/cgokmen/QuART/graphs/stats.png

‎graphs/run_and_plot.sh‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
#!/usr/bin/env bash
2+
# graphs/run_and_plot.sh — produce the two test_kfp bar charts (x = 4 workloads).
3+
#
4+
# 1. Configure+build test_kfp with QUART_KFP_STATS=OFF, run it, capture timings.
5+
# 2. Configure+build test_kfp with QUART_KFP_STATS=ON, run it, capture stats.
6+
# 3. Plot graphs/timings.png and graphs/stats.png from the two captures.
7+
#
8+
# The stat counters add a per-insert increment to the QuART_kfp hot path, so the
9+
# timings MUST come from the stats-OFF build (clean) and the counts from the
10+
# stats-ON build — hence two separate configure/build/run passes.
11+
#
12+
# Usage: graphs/run_and_plot.sh [max_keys_per_stream]
13+
# default 0 = use the full stream size (all 200M keys per stream).
14+
set -euo pipefail
15+
16+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
17+
ROOT="$(cd "$HERE/.." && pwd)"
18+
BUILD="$ROOT/build"
19+
KEY_LIMIT="${1:-0}"
20+
21+
cd "$ROOT"
22+
23+
echo "==> [1/2] Building test_kfp with stats OFF (clean timings)"
24+
cmake -S . -B "$BUILD" -DCMAKE_BUILD_TYPE=Release -DQUART_KFP_STATS=OFF >/dev/null
25+
cmake --build "$BUILD" --target test_kfp -j"$(nproc)" >/dev/null
26+
echo "==> Running (max_keys_per_stream=$KEY_LIMIT) ..."
27+
"$BUILD/test_kfp" both "$KEY_LIMIT" | tee "$HERE/times_raw.txt"
28+
29+
echo
30+
echo "==> [2/2] Building test_kfp with stats ON (classification counts)"
31+
cmake -S . -B "$BUILD" -DCMAKE_BUILD_TYPE=Release -DQUART_KFP_STATS=ON >/dev/null
32+
cmake --build "$BUILD" --target test_kfp -j"$(nproc)" >/dev/null
33+
echo "==> Running (max_keys_per_stream=$KEY_LIMIT) ..."
34+
"$BUILD/test_kfp" ff "$KEY_LIMIT" | tee "$HERE/stats_raw.txt"
35+
36+
echo
37+
echo "==> Plotting"
38+
python3 "$HERE/plot.py" "$HERE/times_raw.txt" "$HERE/stats_raw.txt" "$HERE"
39+
40+
echo "==> Done. Wrote:"
41+
echo " $HERE/timings.png"
42+
echo " $HERE/stats.png"

‎graphs/stats.png‎

44.1 KB
Loading

‎graphs/stats_raw.txt‎

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
════════════════════════════════════════════════════════════
2+
Workload: 3x K=L=0
3+
════════════════════════════════════════════════════════════
4+
Loaded stream 0: 200000000 keys
5+
Loaded stream 1: 200000000 keys
6+
Loaded stream 2: 200000000 keys
7+
Using 200000000 keys per stream (600000000 total)
8+
9+
Pre-loading 300000000 keys (50%) before timed run
10+
11+
QuART_kfp<3,FF>: 2969 ms (101.0 M inserts/s, 300000000 timed keys)
12+
FP_INSERT=597656247 BRIDGE=2343750 NO_MATCH=2 NO_MATCH_untracked=0 (fp_insert%=99.6%)
13+
hot-path fp types: Node4=7003785 Node16=28015134 Node48=74706979 Node256=483260724 (Node256%=81.5%)
14+
fp_not_last_byte=4669625
15+
16+
════════════════════════════════════════════════════════════
17+
Workload: 3x K=L=1
18+
════════════════════════════════════════════════════════════
19+
Loaded stream 0: 200000000 keys
20+
Loaded stream 1: 200000000 keys
21+
Loaded stream 2: 200000000 keys
22+
Using 200000000 keys per stream (600000000 total)
23+
24+
Pre-loading 300000000 keys (50.0%) before timed run
25+
26+
QuART_kfp<3,FF>: 3459 ms (86.7 M inserts/s, 300000000 timed keys)
27+
FP_INSERT=591655083 BRIDGE=2345188 NO_MATCH=5999728 NO_MATCH_untracked=5999197 (fp_insert%=98.6%)
28+
hot-path fp types: Node4=5752245 Node16=28095846 Node48=74999688 Node256=482154578 (Node256%=81.6%)
29+
fp_not_last_byte=652726
30+
31+
════════════════════════════════════════════════════════════
32+
Workload: 3x K=L=25
33+
════════════════════════════════════════════════════════════
34+
Loaded stream 0: 200000000 keys
35+
Loaded stream 1: 200000000 keys
36+
Loaded stream 2: 200000000 keys
37+
Using 200000000 keys per stream (600000000 total)
38+
39+
Pre-loading 300000000 keys (50.0%) before timed run
40+
41+
QuART_kfp<3,FF>: 15156 ms (19.8 M inserts/s, 300000000 timed keys)
42+
FP_INSERT=447654639 BRIDGE=2345372 NO_MATCH=149999988 NO_MATCH_untracked=149999443 (fp_insert%=74.6%)
43+
hot-path fp types: Node4=84755 Node16=1323232 Node48=36689274 Node256=409547606 (Node256%=91.5%)
44+
fp_not_last_byte=9772
45+
46+
════════════════════════════════════════════════════════════
47+
Workload: mixed K=L=0/1/25
48+
════════════════════════════════════════════════════════════
49+
Loaded stream 0: 200000000 keys
50+
Loaded stream 1: 200000000 keys
51+
Loaded stream 2: 200000000 keys
52+
Using 200000000 keys per stream (600000000 total)
53+
54+
Pre-loading 300000000 keys (50.0%) before timed run
55+
56+
QuART_kfp<3,FF>: 7504 ms (40.0 M inserts/s, 300000000 timed keys)
57+
FP_INSERT=545654867 BRIDGE=2344855 NO_MATCH=52000277 NO_MATCH_untracked=51999634 (fp_insert%=90.9%)
58+
hot-path fp types: Node4=4280408 Node16=19144952 Node48=62131299 Node256=458320858 (Node256%=84.3%)
59+
fp_not_last_byte=1777350
60+

0 commit comments

Comments
 (0)