|
2 | 2 | import matplotlib.pyplot as plt |
3 | 3 | import numpy as np |
4 | 4 |
|
| 5 | +# Read the complete file |
5 | 6 | data = open("out.txt").read() |
6 | 7 |
|
| 8 | +# Use two regex patterns to extract benchmarks. |
| 9 | +# The first captures PostgreSQL tests and the second captures Doublets tests. |
7 | 10 | patterns = [ |
8 | 11 | r"test\s+(\w+)/(PSQL)_(\w+)\s+\.\.\.\s+bench:\s+(\d+)\s+ns/iter\s+\(\+/-\s+\d+\)", |
9 | 12 | r"test\s+(\w+)/(Doublets)_(\w+)_(\w+)\s+\.\.\.\s+bench:\s+(\d+)\s+ns/iter\s+\(\+/-\s+\d+\)" |
10 | 13 | ] |
11 | | -PSQL_Transaction = [] |
12 | | -PSQL_NonTransaction = [] |
13 | | -Doublets_United_Volatile = [] |
14 | | -Doublets_United_NonVolatile = [] |
15 | | -Doublets_Split_Volatile = [] |
16 | | -Doublets_Split_NonVolatile = [] |
17 | 14 |
|
| 15 | +# Instead of using lists, we use dictionaries mapping operation names to values. |
| 16 | +PSQL_Transaction = {} |
| 17 | +PSQL_NonTransaction = {} |
| 18 | +Doublets_United_Volatile = {} |
| 19 | +Doublets_United_NonVolatile = {} |
| 20 | +Doublets_Split_Volatile = {} |
| 21 | +Doublets_Split_NonVolatile = {} |
| 22 | + |
| 23 | +# Process each regex pattern |
18 | 24 | for pattern in patterns: |
19 | 25 | matches = re.findall(pattern, data) |
20 | 26 | for match in matches: |
| 27 | + op = match[0] # the operation name (e.g., Create, Update, etc.) |
21 | 28 | if match[1] == 'PSQL': |
22 | | - method, _category, transaction, time = match |
| 29 | + # For PostgreSQL: (operation, 'PSQL', transaction, time) |
| 30 | + transaction = match[2] |
| 31 | + time_val = int(match[3]) |
23 | 32 | if transaction == "Transaction": |
24 | | - PSQL_Transaction.append(int(time)) |
| 33 | + PSQL_Transaction[op] = time_val |
25 | 34 | else: |
26 | | - PSQL_NonTransaction.append(int(time)) |
| 35 | + PSQL_NonTransaction[op] = time_val |
27 | 36 | else: |
28 | | - method, _category, trees, storage, time = match |
| 37 | + # For Doublets: (operation, 'Doublets', trees, storage, time) |
| 38 | + trees = match[2] |
| 39 | + storage = match[3] |
| 40 | + time_val = int(match[4]) |
29 | 41 | if trees == 'United': |
30 | 42 | if storage == 'Volatile': |
31 | | - Doublets_United_Volatile.append(int(time)) |
| 43 | + Doublets_United_Volatile[op] = time_val |
32 | 44 | else: |
33 | | - Doublets_United_NonVolatile.append(int(time)) |
| 45 | + Doublets_United_NonVolatile[op] = time_val |
34 | 46 | else: |
35 | 47 | if storage == 'Volatile': |
36 | | - Doublets_Split_Volatile.append(int(time)) |
| 48 | + Doublets_Split_Volatile[op] = time_val |
37 | 49 | else: |
38 | | - Doublets_Split_NonVolatile.append(int(time)) |
39 | | - |
40 | | -labels = ['Create', 'Delete', 'Each Identity', 'Each Concrete', 'Each Outgoing', 'Each Incoming', 'Each All', 'Update'] |
| 50 | + Doublets_Split_NonVolatile[op] = time_val |
41 | 51 |
|
| 52 | +# Set the unified order. |
| 53 | +# First write operations then read operations exactly as in the sample table. |
| 54 | +ordered_ops = [ |
| 55 | + "Create", "Update", "Delete", # Write operations |
| 56 | + "Each All", "Each Identity", "Each Concrete", "Each Outgoing", "Each Incoming" # Read operations |
| 57 | +] |
42 | 58 |
|
| 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 | +def print_results_markdown(): |
| 75 | + # Define the header in Markdown format. |
| 76 | + header = ( |
| 77 | + "| Operation | Doublets United Volatile | Doublets United NonVolatile | " |
| 78 | + "Doublets Split Volatile | Doublets Split NonVolatile | PSQL NonTransaction | PSQL Transaction |\n" |
| 79 | + "|---------------|--------------------------|-----------------------------|-------------------------|----------------------------|---------------------|------------------|" |
| 80 | + ) |
| 81 | + lines = [header] |
| 82 | + |
| 83 | + # For each operation row, compute the minimum PostgreSQL time |
| 84 | + # and annotate each Doublets result with the relative speed-up. |
| 85 | + 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 | + |
| 107 | + 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} |" |
| 110 | + ) |
| 111 | + lines.append(row) |
| 112 | + |
| 113 | + table_md = "\n".join(lines) |
| 114 | + print(table_md) |
| 115 | + |
| 116 | +######################################### |
| 117 | +# Plotting Functions with Unified Order |
| 118 | +######################################### |
43 | 119 | def bench1(): |
44 | | - # Scale raw ns values for visualization purposes (divided by 10,000,000) |
45 | | - Doublets_United_Volatile_Timings = [max(1, x // 10000000) for x in Doublets_United_Volatile] |
46 | | - Doublets_United_NonVolatile_Timings = [max(1, x // 10000000) for x in Doublets_United_NonVolatile] |
47 | | - Doublets_Split_Volatile_Timigns = [max(1, x // 10000000) for x in Doublets_Split_Volatile] |
48 | | - Doublets_Split_NonVolatile_Timings = [max(1, x // 10000000) for x in Doublets_Split_NonVolatile] |
49 | | - PSQL_NonTransaction_Timings = [max(1, x // 10000000) for x in PSQL_NonTransaction] |
50 | | - PSQL_Transaction_Timings = [max(1, x // 10000000) for x in PSQL_Transaction] |
51 | | - |
52 | | - y = np.arange(len(labels)) |
| 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)) |
53 | 134 | width = 0.1 |
54 | 135 |
|
55 | 136 | fig, ax = plt.subplots(figsize=(12, 8)) |
56 | 137 |
|
57 | | - ax.barh(y - 2 * width, Doublets_United_Volatile_Timings, width, |
| 138 | + ax.barh(y - 2 * width, du_volatile_scaled, width, |
58 | 139 | label='Doublets United Volatile', color='salmon') |
59 | | - ax.barh(y - width, Doublets_United_NonVolatile_Timings, width, |
| 140 | + ax.barh(y - width, du_nonvolatile_scaled, width, |
60 | 141 | label='Doublets United NonVolatile', color='red') |
61 | | - ax.barh(y, Doublets_Split_Volatile_Timigns, width, |
| 142 | + ax.barh(y, ds_volatile_scaled, width, |
62 | 143 | label='Doublets Split Volatile', color='lightgreen') |
63 | | - ax.barh(y + width, Doublets_Split_NonVolatile_Timings, width, |
| 144 | + ax.barh(y + width, ds_nonvolatile_scaled, width, |
64 | 145 | label='Doublets Split NonVolatile', color='green') |
65 | | - ax.barh(y + 2 * width, PSQL_NonTransaction_Timings, width, |
| 146 | + ax.barh(y + 2 * width, psql_non_scaled, width, |
66 | 147 | label='PSQL NonTransaction', color='lightblue') |
67 | | - ax.barh(y + 3 * width, PSQL_Transaction_Timings, width, |
| 148 | + ax.barh(y + 3 * width, psql_trans_scaled, width, |
68 | 149 | label='PSQL Transaction', color='blue') |
69 | 150 |
|
70 | 151 | ax.set_xlabel('Time (ns) - Scaled to Pixels') |
71 | | - ax.set_title('Benchmark comparison for Doublets and PostgreSQL (Rust)') |
| 152 | + ax.set_title('Benchmark Comparison for Doublets and PostgreSQL (Rust)') |
72 | 153 | ax.set_yticks(y) |
73 | | - ax.set_yticklabels(labels) |
| 154 | + ax.set_yticklabels(ordered_ops) |
74 | 155 | ax.legend() |
75 | 156 |
|
76 | 157 | fig.tight_layout() |
77 | 158 | plt.savefig("bench_rust.png") |
78 | 159 | plt.close(fig) |
79 | 160 |
|
80 | | - |
81 | 161 | def bench2(): |
82 | | - y = np.arange(len(labels)) |
| 162 | + """ |
| 163 | + This function plots horizontal bar charts using raw nanosecond values on a logarithmic scale. |
| 164 | + """ |
| 165 | + y = np.arange(len(ordered_ops)) |
83 | 166 | width = 0.1 |
84 | 167 | fig, ax = plt.subplots(figsize=(12, 8)) |
85 | 168 |
|
86 | | - ax.barh(y - 2 * width, Doublets_United_Volatile, width, |
| 169 | + ax.barh(y - 2 * width, du_volatile_arr, width, |
87 | 170 | label='Doublets United Volatile', color='salmon') |
88 | | - ax.barh(y - width, Doublets_United_NonVolatile, width, |
| 171 | + ax.barh(y - width, du_nonvolatile_arr, width, |
89 | 172 | label='Doublets United NonVolatile', color='red') |
90 | | - ax.barh(y, Doublets_Split_Volatile, width, |
| 173 | + ax.barh(y, ds_volatile_arr, width, |
91 | 174 | label='Doublets Split Volatile', color='lightgreen') |
92 | | - ax.barh(y + width, Doublets_Split_NonVolatile, width, |
| 175 | + ax.barh(y + width, ds_nonvolatile_arr, width, |
93 | 176 | label='Doublets Split NonVolatile', color='green') |
94 | | - ax.barh(y + 2 * width, PSQL_NonTransaction, width, |
| 177 | + ax.barh(y + 2 * width, psql_non_arr, width, |
95 | 178 | label='PSQL NonTransaction', color='lightblue') |
96 | | - ax.barh(y + 3 * width, PSQL_Transaction, width, |
| 179 | + ax.barh(y + 3 * width, psql_trans_arr, width, |
97 | 180 | label='PSQL Transaction', color='blue') |
98 | 181 |
|
99 | 182 | ax.set_xlabel('Time (ns) - Logarithmic Scale') |
100 | | - ax.set_title('Benchmark comparison for Doublets and PostgreSQL (Rust)') |
| 183 | + ax.set_title('Benchmark Comparison for Doublets and PostgreSQL (Rust)') |
101 | 184 | ax.set_yticks(y) |
102 | | - ax.set_yticklabels(labels) |
| 185 | + ax.set_yticklabels(ordered_ops) |
103 | 186 | ax.legend() |
104 | 187 |
|
105 | 188 | ax.set_xscale('log') |
106 | 189 | fig.tight_layout() |
107 | 190 | plt.savefig("bench_rust_log_scale.png") |
108 | 191 | plt.close(fig) |
109 | 192 |
|
110 | | - |
111 | | -def print_results_table(): |
112 | | - # Print a header for the table of raw results |
113 | | - header = "{:<20} {:<30} {:<30} {:<30} {:<30} {:<30} {:<30}".format( |
114 | | - "Label", |
115 | | - "Doublets United Volatile", |
116 | | - "Doublets United NonVolatile", |
117 | | - "Doublets Split Volatile", |
118 | | - "Doublets Split NonVolatile", |
119 | | - "PSQL NonTransaction", |
120 | | - "PSQL Transaction" |
121 | | - ) |
122 | | - print(header) |
123 | | - print("-" * len(header)) |
124 | | - # Print each row with the corresponding raw data for each benchmark |
125 | | - for i, label in enumerate(labels): |
126 | | - du_vol = Doublets_United_Volatile[i] if i < len(Doublets_United_Volatile) else 'N/A' |
127 | | - du_nonvol = Doublets_United_NonVolatile[i] if i < len(Doublets_United_NonVolatile) else 'N/A' |
128 | | - ds_vol = Doublets_Split_Volatile[i] if i < len(Doublets_Split_Volatile) else 'N/A' |
129 | | - ds_nonvol = Doublets_Split_NonVolatile[i] if i < len(Doublets_Split_NonVolatile) else 'N/A' |
130 | | - psql_non = PSQL_NonTransaction[i] if i < len(PSQL_NonTransaction) else 'N/A' |
131 | | - psql_trans = PSQL_Transaction[i] if i < len(PSQL_Transaction) else 'N/A' |
132 | | - row = "{:<20} {:<30} {:<30} {:<30} {:<30} {:<30} {:<30}".format( |
133 | | - label, du_vol, du_nonvol, ds_vol, ds_nonvol, psql_non, psql_trans |
134 | | - ) |
135 | | - print(row) |
136 | | - |
137 | | -print_results_table() |
| 193 | +######################################### |
| 194 | +# Main section: print table and generate images |
| 195 | +######################################### |
| 196 | +print_results_markdown() |
138 | 197 | bench1() |
139 | 198 | bench2() |
0 commit comments