|
20 | 20 | machine = "AMD-7800X3D" |
21 | 21 | # False -> on-disk benchmark, True -> in-memory benchmark |
22 | 22 | mem_mode = False |
| 23 | +# Whether we want to compare just compressed Blosc2 in-memory vs on-disk |
| 24 | +compare_disk_mem = False |
23 | 25 |
|
24 | 26 | # --------------------------------------------------------------------- |
25 | 27 | # Benchmark dictionaries (raw string form, as produced by driver script) |
|
273 | 275 | # --------------------------------------------------------------------- |
274 | 276 | # Plotting |
275 | 277 | # --------------------------------------------------------------------- |
276 | | -fig, ax = plt.subplots(figsize=(10, 6)) |
277 | 278 |
|
278 | | -styles = { |
279 | | - 'numpy/numexpr': {'color': 'blue', 'marker': 'o', 'label': 'NumPy/NumExpr'}, |
280 | | - 'blosc2': {'color': 'red', 'marker': 's', 'label': 'Blosc2 (compressed)'}, |
281 | | - 'blosc2-nocomp': {'color': 'green', 'marker': '^', 'label': 'Blosc2 (uncompressed)'}, |
282 | | -} |
| 279 | +if compare_disk_mem: |
| 280 | + # Comparison plot: Blosc2 disk vs memory for both machines |
| 281 | + fig, ax = plt.subplots(figsize=(10, 6)) |
| 282 | + |
| 283 | + comp_styles = { |
| 284 | + 'AMD-7800X3D-mem': {'color': 'blue', 'marker': 'v', 'label': 'AMD 7800X3D (in-memory)', 'offset': 0.87}, |
| 285 | + 'AMD-7800X3D-disk': {'color': 'red', 'marker': '^', 'label': 'AMD 7800X3D (on-disk)', 'offset': 0.87}, |
| 286 | + 'Apple-M4-Pro-mem': {'color': 'blue', 'marker': 's', 'label': 'Apple M4 Pro (in-memory)', 'offset': 1.15}, |
| 287 | + 'Apple-M4-Pro-disk': {'color': 'red', 'marker': 'o', 'label': 'Apple M4 Pro (on-disk)', 'offset': 1.15}, |
| 288 | + } |
| 289 | + |
| 290 | + # Plot Blosc2 results for both machines and both modes (mem first, then disk) |
| 291 | + for machine_name in ['AMD-7800X3D', 'Apple-M4-Pro']: |
| 292 | + for mode_name in ['mem', 'disk']: |
| 293 | + key = f'{machine_name}-{mode_name}' |
| 294 | + data_str = BENCH_DATA[machine_name][mode_name] |
| 295 | + data = ast.literal_eval(data_str) |
| 296 | + |
| 297 | + # Extract only Blosc2 (compressed) data |
| 298 | + if 'blosc2' in data: |
| 299 | + blosc2_data = data['blosc2'] |
| 300 | + intensities = [] |
| 301 | + gflops = [] |
283 | 302 |
|
284 | | -# Plot each backend's results |
285 | | -for backend, backend_results in results.items(): |
286 | | - intensities = [] |
287 | | - gflops = [] |
288 | | - labels = [] |
289 | | - for workload, metrics in backend_results.items(): |
290 | | - intensities.append(metrics['Intensity']) |
291 | | - gflops.append(metrics['GFLOPS']) |
292 | | - labels.append(workload) |
| 303 | + for workload, metrics in blosc2_data.items(): |
| 304 | + intensities.append(metrics['Intensity']) |
| 305 | + gflops.append(metrics['GFLOPS']) |
293 | 306 |
|
294 | | - style = styles[backend] |
295 | | - ax.loglog( |
296 | | - intensities, |
297 | | - gflops, |
298 | | - marker=style['marker'], |
299 | | - color=style['color'], |
300 | | - label=style['label'], |
301 | | - markersize=8, |
302 | | - linestyle='', |
303 | | - alpha=0.7, |
304 | | - ) |
| 307 | + style = comp_styles[key] |
| 308 | + # Apply horizontal offset to separate markers by machine |
| 309 | + offset_intensities = [i * style['offset'] for i in intensities] |
305 | 310 |
|
306 | | -# Build a single annotation per unique x (Intensity) |
307 | | -intensity_map = {} |
308 | | -for backend_results in results.values(): |
309 | | - for workload, metrics in backend_results.items(): |
| 311 | + ax.loglog( |
| 312 | + offset_intensities, |
| 313 | + gflops, |
| 314 | + marker=style['marker'], |
| 315 | + color=style['color'], |
| 316 | + label=style['label'], |
| 317 | + markersize=8, |
| 318 | + linestyle='', |
| 319 | + alpha=0.7, |
| 320 | + ) |
| 321 | + |
| 322 | + # Add single set of workload labels (from Apple M4 Pro disk data) |
| 323 | + apple_disk = ast.literal_eval(BENCH_DATA['Apple-M4-Pro']['disk']) |
| 324 | + intensity_map_comp = {} |
| 325 | + for workload, metrics in apple_disk['blosc2'].items(): |
310 | 326 | intensity = metrics['Intensity'] |
311 | 327 | gflop = metrics['GFLOPS'] |
312 | | - if intensity not in intensity_map: |
313 | | - intensity_map[intensity] = {'label': workload, 'gflops': []} |
314 | | - intensity_map[intensity]['gflops'].append(gflop) |
| 328 | + if intensity not in intensity_map_comp: |
| 329 | + intensity_map_comp[intensity] = {'label': workload, 'min_gflops': gflop} |
| 330 | + else: |
| 331 | + intensity_map_comp[intensity]['min_gflops'] = min(intensity_map_comp[intensity]['min_gflops'], gflop) |
| 332 | + |
| 333 | + ax.set_xlim(0.1, 5e4) |
| 334 | + ax.set_ylim(0.1, 1000.0) |
| 335 | + |
| 336 | + for intensity, info in sorted(intensity_map_comp.items()): |
| 337 | + safe_ypos = max(info['min_gflops'] * 0.3, 0.002) |
| 338 | + ax.annotate( |
| 339 | + info['label'], |
| 340 | + (intensity, safe_ypos), |
| 341 | + ha='center', |
| 342 | + va='top', |
| 343 | + fontsize=10, |
| 344 | + alpha=0.9, |
| 345 | + ) |
| 346 | + |
| 347 | + ax.set_xlabel('Arithmetic Intensity (FLOPs/element)', fontsize=12) |
| 348 | + ax.set_ylabel('Performance (GFLOPS/sec)', fontsize=12) |
| 349 | + ax.set_title('Roofline Comparison: Compressed Blosc2 Memory vs Disk', fontsize=14, fontweight='bold') |
| 350 | + ax.legend(loc='upper left') |
| 351 | + ax.grid(False) |
| 352 | + |
| 353 | + plt.tight_layout() |
| 354 | + plt.savefig('roofline_blosc2_comparison.png', dpi=300, bbox_inches='tight') |
| 355 | + plt.show() |
| 356 | + |
| 357 | +else: |
| 358 | + # Original single-mode plot |
| 359 | + fig, ax = plt.subplots(figsize=(10, 6)) |
| 360 | + |
| 361 | + styles = { |
| 362 | + 'numpy/numexpr': {'color': 'blue', 'marker': 'o', 'label': 'NumPy/NumExpr'}, |
| 363 | + 'blosc2': {'color': 'red', 'marker': 's', 'label': 'Blosc2 (compressed)'}, |
| 364 | + 'blosc2-nocomp': {'color': 'green', 'marker': '^', 'label': 'Blosc2 (uncompressed)'}, |
| 365 | + } |
| 366 | + |
| 367 | + # Plot each backend's results |
| 368 | + for backend, backend_results in results.items(): |
| 369 | + intensities = [] |
| 370 | + gflops = [] |
| 371 | + labels = [] |
| 372 | + for workload, metrics in backend_results.items(): |
| 373 | + intensities.append(metrics['Intensity']) |
| 374 | + gflops.append(metrics['GFLOPS']) |
| 375 | + labels.append(workload) |
| 376 | + |
| 377 | + style = styles[backend] |
| 378 | + ax.loglog( |
| 379 | + intensities, |
| 380 | + gflops, |
| 381 | + marker=style['marker'], |
| 382 | + color=style['color'], |
| 383 | + label=style['label'], |
| 384 | + markersize=8, |
| 385 | + linestyle='', |
| 386 | + alpha=0.7, |
| 387 | + ) |
| 388 | + |
| 389 | + # Build a single annotation per unique x (Intensity) |
| 390 | + intensity_map = {} |
| 391 | + for backend_results in results.values(): |
| 392 | + for workload, metrics in backend_results.items(): |
| 393 | + intensity = metrics['Intensity'] |
| 394 | + gflop = metrics['GFLOPS'] |
| 395 | + if intensity not in intensity_map: |
| 396 | + intensity_map[intensity] = {'label': workload, 'gflops': []} |
| 397 | + intensity_map[intensity]['gflops'].append(gflop) |
315 | 398 |
|
316 | | -# Axes limits |
317 | | -ax.set_xlim(0.1, 5e4) |
318 | | -ymin = 0.1 if mem_mode else 0.001 |
319 | | -ax.set_ylim(ymin, 2000.0) |
| 399 | + # Axes limits |
| 400 | + ax.set_xlim(0.1, 5e4) |
| 401 | + ymin = 0.1 if mem_mode else 0.001 |
| 402 | + ax.set_ylim(ymin, 2000.0) |
320 | 403 |
|
321 | | -# Annotate once per intensity, centered under the cluster of points |
322 | | -for intensity, info in sorted(intensity_map.items()): |
323 | | - raw_ypos = min(info['gflops']) * 0.6 |
324 | | - ymin_curr, ymax_curr = ax.get_ylim() |
325 | | - safe_ypos = max(raw_ypos, ymin_curr * 1.5 if ymin_curr > 0 else raw_ypos) |
326 | | - ax.annotate( |
327 | | - info['label'], |
328 | | - (intensity, safe_ypos), |
329 | | - ha='center', |
330 | | - va='top', |
331 | | - fontsize=10, |
332 | | - alpha=0.9, |
333 | | - ) |
| 404 | + # Annotate once per intensity, centered under the cluster of points |
| 405 | + for intensity, info in sorted(intensity_map.items()): |
| 406 | + raw_ypos = min(info['gflops']) * 0.6 |
| 407 | + ymin_curr, ymax_curr = ax.get_ylim() |
| 408 | + safe_ypos = max(raw_ypos, ymin_curr * 1.5 if ymin_curr > 0 else raw_ypos) |
| 409 | + ax.annotate( |
| 410 | + info['label'], |
| 411 | + (intensity, safe_ypos), |
| 412 | + ha='center', |
| 413 | + va='top', |
| 414 | + fontsize=10, |
| 415 | + alpha=0.9, |
| 416 | + ) |
334 | 417 |
|
335 | | -ax.set_xlabel('Arithmetic Intensity (FLOPs/element)', fontsize=12) |
336 | | -ax.set_ylabel('Performance (GFLOPS/sec)', fontsize=12) |
337 | | -machine2 = machine.replace("-", " ") |
338 | | -ax.set_title(f'Roofline Analysis: {machine2} ({legend})', fontsize=14, fontweight='bold') |
339 | | -ax.legend(loc='upper left') |
340 | | -ax.grid(False) |
| 418 | + ax.set_xlabel('Arithmetic Intensity (FLOPs/element)', fontsize=12) |
| 419 | + ax.set_ylabel('Performance (GFLOPS/sec)', fontsize=12) |
| 420 | + machine2 = machine.replace("-", " ") |
| 421 | + ax.set_title(f'Roofline Analysis: {machine2} ({legend})', fontsize=14, fontweight='bold') |
| 422 | + ax.legend(loc='upper left') |
| 423 | + ax.grid(False) |
341 | 424 |
|
342 | | -plt.tight_layout() |
343 | | -plt.savefig(f'roofline_plot-{machine}-{legend}.png', dpi=300, bbox_inches='tight') |
344 | | -plt.show() |
| 425 | + plt.tight_layout() |
| 426 | + plt.savefig(f'roofline_plot-{machine}-{legend}.png', dpi=300, bbox_inches='tight') |
| 427 | + plt.show() |
0 commit comments