|
1 | 1 | import re |
| 2 | +import logging |
2 | 3 | import matplotlib.pyplot as plt |
3 | 4 | import numpy as np |
4 | 5 |
|
| 6 | +# Enable detailed tracing. Set to False to disable verbose output. |
| 7 | +DEBUG = True |
| 8 | +logging.basicConfig(level=logging.INFO if DEBUG else logging.WARNING, |
| 9 | + format="%(message)s") |
| 10 | + |
5 | 11 | # Read the complete file |
6 | 12 | data = open("out.txt").read() |
| 13 | +if DEBUG: |
| 14 | + logging.info("Loaded out.txt, length: %d characters", len(data)) |
7 | 15 |
|
8 | 16 | # Use two regex patterns to extract benchmarks. |
9 | 17 | # The first captures PostgreSQL tests and the second captures Doublets tests. |
|
23 | 31 | # Process each regex pattern |
24 | 32 | for pattern in patterns: |
25 | 33 | matches = re.findall(pattern, data) |
| 34 | + if DEBUG: |
| 35 | + logging.info("Pattern %s matched %d entries", pattern, len(matches)) |
26 | 36 | for match in matches: |
27 | | - op = match[0] # the operation name (e.g., Create, Update, etc.) |
| 37 | + # ─── FIX: normalise name ──────────────────────────────────────────── |
| 38 | + op = match[0].replace("_", " ") # Create, Each All, … |
| 39 | + # ──────────────────────────────────────────────────────────────────── |
28 | 40 | if match[1] == 'PSQL': |
29 | | - # For PostgreSQL: (operation, 'PSQL', transaction, time) |
| 41 | + # (operation, 'PSQL', transaction, time) |
30 | 42 | transaction = match[2] |
31 | 43 | time_val = int(match[3]) |
| 44 | + if DEBUG: |
| 45 | + logging.info("PSQL %s - %s: %d ns", op, transaction, time_val) |
32 | 46 | if transaction == "Transaction": |
33 | 47 | PSQL_Transaction[op] = time_val |
34 | 48 | else: |
35 | 49 | PSQL_NonTransaction[op] = time_val |
36 | 50 | else: |
37 | | - # For Doublets: (operation, 'Doublets', trees, storage, time) |
| 51 | + # (operation, 'Doublets', trees, storage, time) |
38 | 52 | trees = match[2] |
39 | 53 | storage = match[3] |
40 | 54 | time_val = int(match[4]) |
| 55 | + if DEBUG: |
| 56 | + logging.info("Doublets %s - %s %s: %d ns", op, trees, storage, time_val) |
41 | 57 | if trees == 'United': |
42 | 58 | if storage == 'Volatile': |
43 | 59 | Doublets_United_Volatile[op] = time_val |
|
49 | 65 | else: |
50 | 66 | Doublets_Split_NonVolatile[op] = time_val |
51 | 67 |
|
52 | | -# Set the unified order. |
53 | | -# First write operations then read operations exactly as in the sample table. |
| 68 | +# Operation order for table and plots |
54 | 69 | ordered_ops = [ |
55 | | - "Create", "Update", "Delete", # Write operations |
56 | | - "Each All", "Each Identity", "Each Concrete", "Each Outgoing", "Each Incoming" # Read operations |
| 70 | + "Create", "Update", "Delete", |
| 71 | + "Each All", "Each Identity", "Each Concrete", "Each Outgoing", "Each Incoming" |
57 | 72 | ] |
58 | 73 |
|
59 | | -# Prepare arrays for plotting by reassembling results in the desired order. |
60 | | -def get_series(data_dict): |
61 | | - # If an operation is missing in the dictionary, default to 0. |
62 | | - return [data_dict.get(op, 0) for op in ordered_ops] |
63 | | - |
64 | | -du_volatile_arr = get_series(Doublets_United_Volatile) |
65 | | -du_nonvolatile_arr = get_series(Doublets_United_NonVolatile) |
66 | | -ds_volatile_arr = get_series(Doublets_Split_Volatile) |
67 | | -ds_nonvolatile_arr = get_series(Doublets_Split_NonVolatile) |
68 | | -psql_non_arr = get_series(PSQL_NonTransaction) |
69 | | -psql_trans_arr = get_series(PSQL_Transaction) |
70 | | - |
71 | | -######################################### |
72 | | -# Print the Markdown Table to Console |
73 | | -######################################### |
| 74 | +if DEBUG: |
| 75 | + logging.info("\nFinal dictionaries (after parsing):") |
| 76 | + logging.info("PSQL_Transaction: %s", PSQL_Transaction) |
| 77 | + logging.info("PSQL_NonTransaction: %s", PSQL_NonTransaction) |
| 78 | + logging.info("Doublets_United_Volatile: %s", Doublets_United_Volatile) |
| 79 | + logging.info("Doublets_United_NonVolatile: %s", Doublets_United_NonVolatile) |
| 80 | + logging.info("Doublets_Split_Volatile: %s", Doublets_Split_Volatile) |
| 81 | + logging.info("Doublets_Split_NonVolatile: %s", Doublets_Split_NonVolatile) |
| 82 | + |
| 83 | +# Assemble series in the desired order. |
| 84 | +def get_series(d): return [d.get(op, 0) for op in ordered_ops] |
| 85 | + |
| 86 | +du_volatile_arr = get_series(Doublets_United_Volatile) |
| 87 | +du_nonvolatile_arr= get_series(Doublets_United_NonVolatile) |
| 88 | +ds_volatile_arr = get_series(Doublets_Split_Volatile) |
| 89 | +ds_nonvolatile_arr= get_series(Doublets_Split_NonVolatile) |
| 90 | +psql_non_arr = get_series(PSQL_NonTransaction) |
| 91 | +psql_trans_arr = get_series(PSQL_Transaction) |
| 92 | + |
| 93 | +# ───────────────────────────────────────────────────────────────────────────── |
| 94 | +# Markdown Table |
| 95 | +# ───────────────────────────────────────────────────────────────────────────── |
74 | 96 | def print_results_markdown(): |
75 | | - # Define the header in Markdown format. |
76 | 97 | header = ( |
77 | 98 | "| Operation | Doublets United Volatile | Doublets United NonVolatile | " |
78 | 99 | "Doublets Split Volatile | Doublets Split NonVolatile | PSQL NonTransaction | PSQL Transaction |\n" |
79 | 100 | "|---------------|--------------------------|-----------------------------|-------------------------|----------------------------|---------------------|------------------|" |
80 | 101 | ) |
81 | 102 | lines = [header] |
82 | | - |
83 | | - # For each operation row, compute the minimum PostgreSQL time |
84 | | - # and annotate each Doublets result with the relative speed-up. |
| 103 | + |
85 | 104 | for i, op in enumerate(ordered_ops): |
86 | | - # Get PostgreSQL values. If one is missing, use the other. |
87 | | - psql_val1 = psql_non_arr[i] if psql_non_arr[i] != 0 else float('inf') |
88 | | - psql_val2 = psql_trans_arr[i] if psql_trans_arr[i] != 0 else float('inf') |
89 | | - min_psql = min(psql_val1, psql_val2) |
90 | | - |
91 | | - def annotate(doublets_val): |
92 | | - if doublets_val == 0: |
93 | | - return "N/A" |
94 | | - # Compute the factor (using the fastest PostgreSQL result). |
95 | | - factor = min_psql / doublets_val |
96 | | - return f"{doublets_val} ({factor:.1f}+ times faster)" |
97 | | - |
98 | | - du_vol_str = annotate(du_volatile_arr[i]) |
99 | | - du_nonvol_str = annotate(du_nonvolatile_arr[i]) |
100 | | - ds_vol_str = annotate(ds_volatile_arr[i]) |
101 | | - ds_nonvol_str = annotate(ds_nonvolatile_arr[i]) |
102 | | - |
103 | | - # For PostgreSQL values, just show the raw number or N/A if missing. |
104 | | - psql_non_str = str(psql_non_arr[i]) if psql_non_arr[i] != 0 else "N/A" |
105 | | - psql_trans_str = str(psql_trans_arr[i]) if psql_trans_arr[i] != 0 else "N/A" |
106 | | - |
| 105 | + psql_val1 = psql_non_arr[i] if psql_non_arr[i] else float('inf') |
| 106 | + psql_val2 = psql_trans_arr[i] if psql_trans_arr[i] else float('inf') |
| 107 | + min_psql = min(psql_val1, psql_val2) |
| 108 | + |
| 109 | + def annotate(v): |
| 110 | + if v == 0: return "N/A" |
| 111 | + if min_psql == float('inf'): return f"{v}" |
| 112 | + return f"{v} ({min_psql / v:.1f}+ times faster)" |
| 113 | + |
107 | 114 | row = ( |
108 | | - f"| {op:<13} | {du_vol_str:<24} | {du_nonvol_str:<27} | " |
109 | | - f"{ds_vol_str:<23} | {ds_nonvol_str:<26} | {psql_non_str:<19} | {psql_trans_str:<16} |" |
| 115 | + f"| {op:<13} | {annotate(du_volatile_arr[i]):<24} | " |
| 116 | + f"{annotate(du_nonvolatile_arr[i]):<27} | " |
| 117 | + f"{annotate(ds_volatile_arr[i]):<23} | " |
| 118 | + f"{annotate(ds_nonvolatile_arr[i]):<26} | " |
| 119 | + f"{psql_non_arr[i] or 'N/A':<19} | {psql_trans_arr[i] or 'N/A':<16} |" |
110 | 120 | ) |
111 | 121 | lines.append(row) |
112 | | - |
| 122 | + |
113 | 123 | table_md = "\n".join(lines) |
114 | 124 | print(table_md) |
| 125 | + if DEBUG: logging.info("\nGenerated Markdown Table:\n%s", table_md) |
115 | 126 |
|
116 | | -######################################### |
117 | | -# Plotting Functions with Unified Order |
118 | | -######################################### |
| 127 | +# ───────────────────────────────────────────────────────────────────────────── |
| 128 | +# Plots |
| 129 | +# ───────────────────────────────────────────────────────────────────────────── |
119 | 130 | def bench1(): |
120 | | - """ |
121 | | - This function plots horizontal bar charts with scaled times. |
122 | | - Scaled by dividing each raw nanosecond (ns) value by 10,000,000. |
123 | | - """ |
124 | | - # Scale the Doublets and PostgreSQL arrays. |
125 | | - scale_factor = 10000000 |
126 | | - du_volatile_scaled = [max(1, x // scale_factor) for x in du_volatile_arr] |
127 | | - du_nonvolatile_scaled = [max(1, x // scale_factor) for x in du_nonvolatile_arr] |
128 | | - ds_volatile_scaled = [max(1, x // scale_factor) for x in ds_volatile_arr] |
129 | | - ds_nonvolatile_scaled = [max(1, x // scale_factor) for x in ds_nonvolatile_arr] |
130 | | - psql_non_scaled = [max(1, x // scale_factor) for x in psql_non_arr] |
131 | | - psql_trans_scaled = [max(1, x // scale_factor) for x in psql_trans_arr] |
132 | | - |
133 | | - y = np.arange(len(ordered_ops)) |
134 | | - width = 0.1 |
135 | | - |
| 131 | + """Horizontal bars – scaled (divide by 10 000 000).""" |
| 132 | + scale = lambda arr: [max(1, x // 10_000_000) for x in arr] |
| 133 | + y, w = np.arange(len(ordered_ops)), 0.1 |
136 | 134 | fig, ax = plt.subplots(figsize=(12, 8)) |
137 | 135 |
|
138 | | - ax.barh(y - 2 * width, du_volatile_scaled, width, |
139 | | - label='Doublets United Volatile', color='salmon') |
140 | | - ax.barh(y - width, du_nonvolatile_scaled, width, |
141 | | - label='Doublets United NonVolatile', color='red') |
142 | | - ax.barh(y, ds_volatile_scaled, width, |
143 | | - label='Doublets Split Volatile', color='lightgreen') |
144 | | - ax.barh(y + width, ds_nonvolatile_scaled, width, |
145 | | - label='Doublets Split NonVolatile', color='green') |
146 | | - ax.barh(y + 2 * width, psql_non_scaled, width, |
147 | | - label='PSQL NonTransaction', color='lightblue') |
148 | | - ax.barh(y + 3 * width, psql_trans_scaled, width, |
149 | | - label='PSQL Transaction', color='blue') |
150 | | - |
151 | | - ax.set_xlabel('Time (ns) - Scaled to Pixels') |
152 | | - ax.set_title('Benchmark Comparison for Doublets and PostgreSQL (Rust)') |
153 | | - ax.set_yticks(y) |
154 | | - ax.set_yticklabels(ordered_ops) |
155 | | - ax.legend() |
156 | | - |
157 | | - fig.tight_layout() |
158 | | - plt.savefig("bench_rust.png") |
159 | | - plt.close(fig) |
| 136 | + ax.barh(y - 2*w, scale(du_volatile_arr), w, label='Doublets United Volatile', color='salmon') |
| 137 | + ax.barh(y - w, scale(du_nonvolatile_arr),w, label='Doublets United NonVolatile',color='red') |
| 138 | + ax.barh(y , scale(ds_volatile_arr), w, label='Doublets Split Volatile', color='lightgreen') |
| 139 | + ax.barh(y + w, scale(ds_nonvolatile_arr), w, label='Doublets Split NonVolatile', color='green') |
| 140 | + ax.barh(y + 2*w, scale(psql_non_arr), w, label='PSQL NonTransaction', color='lightblue') |
| 141 | + ax.barh(y + 3*w, scale(psql_trans_arr), w, label='PSQL Transaction', color='blue') |
| 142 | + |
| 143 | + ax.set_xlabel('Time (ns) – scaled') |
| 144 | + ax.set_title ('Benchmark Comparison (Rust)') |
| 145 | + ax.set_yticks(y); ax.set_yticklabels(ordered_ops); ax.legend() |
| 146 | + fig.tight_layout(); plt.savefig("bench_rust.png"); plt.close(fig) |
| 147 | + if DEBUG: logging.info("bench_rust.png saved.") |
160 | 148 |
|
161 | 149 | def bench2(): |
162 | | - """ |
163 | | - This function plots horizontal bar charts using raw nanosecond values on a logarithmic scale. |
164 | | - """ |
165 | | - y = np.arange(len(ordered_ops)) |
166 | | - width = 0.1 |
| 150 | + """Horizontal bars – raw values on a log scale.""" |
| 151 | + y, w = np.arange(len(ordered_ops)), 0.1 |
167 | 152 | fig, ax = plt.subplots(figsize=(12, 8)) |
168 | 153 |
|
169 | | - ax.barh(y - 2 * width, du_volatile_arr, width, |
170 | | - label='Doublets United Volatile', color='salmon') |
171 | | - ax.barh(y - width, du_nonvolatile_arr, width, |
172 | | - label='Doublets United NonVolatile', color='red') |
173 | | - ax.barh(y, ds_volatile_arr, width, |
174 | | - label='Doublets Split Volatile', color='lightgreen') |
175 | | - ax.barh(y + width, ds_nonvolatile_arr, width, |
176 | | - label='Doublets Split NonVolatile', color='green') |
177 | | - ax.barh(y + 2 * width, psql_non_arr, width, |
178 | | - label='PSQL NonTransaction', color='lightblue') |
179 | | - ax.barh(y + 3 * width, psql_trans_arr, width, |
180 | | - label='PSQL Transaction', color='blue') |
181 | | - |
182 | | - ax.set_xlabel('Time (ns) - Logarithmic Scale') |
183 | | - ax.set_title('Benchmark Comparison for Doublets and PostgreSQL (Rust)') |
184 | | - ax.set_yticks(y) |
185 | | - ax.set_yticklabels(ordered_ops) |
186 | | - ax.legend() |
187 | | - |
188 | | - ax.set_xscale('log') |
189 | | - fig.tight_layout() |
190 | | - plt.savefig("bench_rust_log_scale.png") |
191 | | - plt.close(fig) |
192 | | - |
193 | | -######################################### |
194 | | -# Main section: print table and generate images |
195 | | -######################################### |
| 154 | + ax.barh(y - 2*w, du_volatile_arr, w, label='Doublets United Volatile', color='salmon') |
| 155 | + ax.barh(y - w, du_nonvolatile_arr,w, label='Doublets United NonVolatile',color='red') |
| 156 | + ax.barh(y , ds_volatile_arr, w, label='Doublets Split Volatile', color='lightgreen') |
| 157 | + ax.barh(y + w, ds_nonvolatile_arr, w, label='Doublets Split NonVolatile', color='green') |
| 158 | + ax.barh(y + 2*w, psql_non_arr, w, label='PSQL NonTransaction', color='lightblue') |
| 159 | + ax.barh(y + 3*w, psql_trans_arr, w, label='PSQL Transaction', color='blue') |
| 160 | + |
| 161 | + ax.set_xlabel('Time (ns) – log scale') |
| 162 | + ax.set_title ('Benchmark Comparison (Rust)') |
| 163 | + ax.set_yticks(y); ax.set_yticklabels(ordered_ops); ax.set_xscale('log'); ax.legend() |
| 164 | + fig.tight_layout(); plt.savefig("bench_rust_log_scale.png"); plt.close(fig) |
| 165 | + if DEBUG: logging.info("bench_rust_log_scale.png saved.") |
| 166 | + |
| 167 | +# ───────────────────────────────────────────────────────────────────────────── |
| 168 | +# Run |
| 169 | +# ───────────────────────────────────────────────────────────────────────────── |
196 | 170 | print_results_markdown() |
197 | 171 | bench1() |
198 | 172 | bench2() |
0 commit comments