carm-roofline 1.0.2.dev1__tar.gz → 1.0.2.dev2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {carm_roofline-1.0.2.dev1/carm_roofline.egg-info → carm_roofline-1.0.2.dev2}/PKG-INFO +15 -4
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/README.md +14 -3
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/__init__.py +8 -1
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/identity.py +115 -13
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm.py +4 -1
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2/carm_roofline.egg-info}/PKG-INFO +15 -4
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/__init__.py +2 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/aggregation.py +20 -20
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/config.py +3 -10
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/output.py +6 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/shared.py +22 -14
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/pyproject.toml +1 -1
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test_bench/test_bench.c +2 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test_bench/test_bench.h +2 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test_bench/wrapper.inl +7 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/LICENSE +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/architecture.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/arm.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/config.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/detect.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/frequency.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/memory.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/riscv.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/arm/features.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/arm/frequency.h +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/arm/vlen.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/frequency.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/riscv/frequency.h +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/riscv/rvv_version.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/riscv/vlen.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/x86/cache.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/x86/features.c +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/x86/frequency.h +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/x86/x86_avx512/frequency.h +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/x86.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/arguments.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/benchmark.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/benchmarking.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/arm.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/data_type.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/instruction.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/operation.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/register.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/isa.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/parameters.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/riscv.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/x86.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/interface.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/arithmetic.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/base.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/common.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/jsonl.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/memory.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/memory_sweep.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/mixed.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/output/roofline.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/result.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/arithmetic.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/base.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/memory.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/memory_sweep.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/mixed.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/suites/roofline.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/SOURCES.txt +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/dependency_links.txt +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/entry_points.txt +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/requires.txt +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/top_level.txt +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/context.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/error.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/exec_interface.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/assets/CARM_icon.svg +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/assets/CHAMP_logo.svg +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/assets/menu_icon.png +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/assets/style.css +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/components.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/config.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/data.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/factory.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/gui/ids.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/output_utils.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/backends.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/model.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/papi_backend.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/papi_loader.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/papi_metrics.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/perf_backend.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/perf_loader.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/profiling/perf_metrics.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/results_paths.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/roofline_assembly.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/run_config.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/setup.cfg +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test/test_gui_data.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test/test_isa_codegen_integration.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test/test_memory_suite_generation.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test/test_output_module.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test/test_roofline_assembly.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test/test_typed_benchmarks.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test_bench/__init__.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/test_bench/builder.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/units.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/utils.py +0 -0
- {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carm-roofline
|
|
3
|
-
Version: 1.0.2.
|
|
3
|
+
Version: 1.0.2.dev2
|
|
4
4
|
Summary: CARM: Cache-Aware Roofline Model benchmarking and visualization toolkit
|
|
5
5
|
Author: CHaMP Team
|
|
6
6
|
License: Apache License
|
|
@@ -246,7 +246,6 @@ Dynamic: license-file
|
|
|
246
246
|
|
|
247
247
|
# The CARM Tool
|
|
248
248
|
|
|
249
|
-
|
|
250
249
|
Cache-Aware Roofline Model (CARM) toolkit - benchmark, visualize and profile Intel, AMD, ARM, RISC-V CPUs and NVIDIA, AMD GPUs.
|
|
251
250
|
|
|
252
251
|
The package provides:
|
|
@@ -258,6 +257,10 @@ The package provides:
|
|
|
258
257
|
> [!WARNING]
|
|
259
258
|
> The development branch and associated python package are still experimental, and do not include all features yet. For a stable release, please refer to the main branch.
|
|
260
259
|
|
|
260
|
+
## Documentation
|
|
261
|
+
|
|
262
|
+
You can find the full documentation at [https://champ-hub.github.io/carm-roofline](https://champ-hub.github.io/carm-roofline/).
|
|
263
|
+
|
|
261
264
|
## Installation
|
|
262
265
|
|
|
263
266
|
Install from PyPI:
|
|
@@ -279,10 +282,17 @@ source carm-env/bin/activate
|
|
|
279
282
|
pip install carm-roofline[all]
|
|
280
283
|
```
|
|
281
284
|
|
|
285
|
+
If cloning the repository directly (e.g. for development or access to example applications), use `--recurse-submodules` to also fetch the examples:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
git clone --recurse-submodules https://github.com/champ-hub/carm-roofline
|
|
289
|
+
```
|
|
290
|
+
|
|
282
291
|
## Requirements
|
|
283
292
|
|
|
284
293
|
- Python 3.9+
|
|
285
|
-
-
|
|
294
|
+
- C compiler (e.g. gcc, clang)
|
|
295
|
+
- Optional: [PAPI](https://github.com/icl-utk-edu/papi) headers and binaries for profiling
|
|
286
296
|
|
|
287
297
|
## Command-Line Interface
|
|
288
298
|
|
|
@@ -296,7 +306,7 @@ Available subcommands:
|
|
|
296
306
|
|
|
297
307
|
- `benchmark` - run benchmark suites
|
|
298
308
|
- `gui` - launch the results dashboard
|
|
299
|
-
- `profile` -
|
|
309
|
+
- `profile` - profile an application with PAPI or perf
|
|
300
310
|
|
|
301
311
|
Show help:
|
|
302
312
|
|
|
@@ -304,6 +314,7 @@ Show help:
|
|
|
304
314
|
carm --help
|
|
305
315
|
carm benchmark --help
|
|
306
316
|
carm gui --help
|
|
317
|
+
carm profile --help
|
|
307
318
|
```
|
|
308
319
|
|
|
309
320
|
## Basic Usage
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
|
|
2
2
|
# The CARM Tool
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
Cache-Aware Roofline Model (CARM) toolkit - benchmark, visualize and profile Intel, AMD, ARM, RISC-V CPUs and NVIDIA, AMD GPUs.
|
|
6
5
|
|
|
7
6
|
The package provides:
|
|
@@ -13,6 +12,10 @@ The package provides:
|
|
|
13
12
|
> [!WARNING]
|
|
14
13
|
> The development branch and associated python package are still experimental, and do not include all features yet. For a stable release, please refer to the main branch.
|
|
15
14
|
|
|
15
|
+
## Documentation
|
|
16
|
+
|
|
17
|
+
You can find the full documentation at [https://champ-hub.github.io/carm-roofline](https://champ-hub.github.io/carm-roofline/).
|
|
18
|
+
|
|
16
19
|
## Installation
|
|
17
20
|
|
|
18
21
|
Install from PyPI:
|
|
@@ -34,10 +37,17 @@ source carm-env/bin/activate
|
|
|
34
37
|
pip install carm-roofline[all]
|
|
35
38
|
```
|
|
36
39
|
|
|
40
|
+
If cloning the repository directly (e.g. for development or access to example applications), use `--recurse-submodules` to also fetch the examples:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
git clone --recurse-submodules https://github.com/champ-hub/carm-roofline
|
|
44
|
+
```
|
|
45
|
+
|
|
37
46
|
## Requirements
|
|
38
47
|
|
|
39
48
|
- Python 3.9+
|
|
40
|
-
-
|
|
49
|
+
- C compiler (e.g. gcc, clang)
|
|
50
|
+
- Optional: [PAPI](https://github.com/icl-utk-edu/papi) headers and binaries for profiling
|
|
41
51
|
|
|
42
52
|
## Command-Line Interface
|
|
43
53
|
|
|
@@ -51,7 +61,7 @@ Available subcommands:
|
|
|
51
61
|
|
|
52
62
|
- `benchmark` - run benchmark suites
|
|
53
63
|
- `gui` - launch the results dashboard
|
|
54
|
-
- `profile` -
|
|
64
|
+
- `profile` - profile an application with PAPI or perf
|
|
55
65
|
|
|
56
66
|
Show help:
|
|
57
67
|
|
|
@@ -59,6 +69,7 @@ Show help:
|
|
|
59
69
|
carm --help
|
|
60
70
|
carm benchmark --help
|
|
61
71
|
carm gui --help
|
|
72
|
+
carm profile --help
|
|
62
73
|
```
|
|
63
74
|
|
|
64
75
|
## Basic Usage
|
|
@@ -5,7 +5,13 @@ import contextvars
|
|
|
5
5
|
from exec_interface import ExecutionInterface
|
|
6
6
|
|
|
7
7
|
from .architecture import Architecture
|
|
8
|
-
from .identity import
|
|
8
|
+
from .identity import (
|
|
9
|
+
MachineSignature,
|
|
10
|
+
detect_machine_signature,
|
|
11
|
+
generate_run_name,
|
|
12
|
+
signature_from_architecture,
|
|
13
|
+
write_machine_json,
|
|
14
|
+
)
|
|
9
15
|
from .memory import SimpleMemoryTopology
|
|
10
16
|
|
|
11
17
|
# Context variable to hold the execution interface, for compatibility with simulation and native execution
|
|
@@ -31,4 +37,5 @@ __all__ = [
|
|
|
31
37
|
"get_execution_interface",
|
|
32
38
|
"set_execution_interface",
|
|
33
39
|
"signature_from_architecture",
|
|
40
|
+
"write_machine_json",
|
|
34
41
|
]
|
|
@@ -11,6 +11,8 @@ machine yields the same name across runs.
|
|
|
11
11
|
from __future__ import annotations
|
|
12
12
|
|
|
13
13
|
import hashlib
|
|
14
|
+
import json
|
|
15
|
+
import os
|
|
14
16
|
import platform
|
|
15
17
|
import re
|
|
16
18
|
from dataclasses import dataclass
|
|
@@ -22,6 +24,8 @@ from .memory import MemoryLevelInfo, MemoryTopology, MemoryTopologyLike
|
|
|
22
24
|
if TYPE_CHECKING:
|
|
23
25
|
from .architecture import Architecture
|
|
24
26
|
|
|
27
|
+
_BYTES_PER_GIB = 1024**3
|
|
28
|
+
|
|
25
29
|
|
|
26
30
|
@dataclass(frozen=True)
|
|
27
31
|
class CpuInfo:
|
|
@@ -55,17 +59,52 @@ class MachineSignature:
|
|
|
55
59
|
vendor: str
|
|
56
60
|
memory_levels: tuple[MemoryLevelSignature, ...]
|
|
57
61
|
|
|
62
|
+
def _canonical_hash_string(self) -> str:
|
|
63
|
+
"""Canonical string fed to SHA-256 for the config hash.
|
|
64
|
+
|
|
65
|
+
Format: ``arch=<arch>;vendor=<vendor>;levels=<levels>`` where
|
|
66
|
+
``<levels>`` is a ``|``-separated list of
|
|
67
|
+
``<name>:<size_bytes>:<instances>:<num_sharing_threads>``.
|
|
68
|
+
"""
|
|
69
|
+
levels_str = "|".join(
|
|
70
|
+
f"{lvl.name}:{lvl.size_bytes}:{lvl.instances}:{lvl.num_sharing_threads}" for lvl in self.memory_levels
|
|
71
|
+
)
|
|
72
|
+
return f"arch={self.arch};vendor={self.vendor};levels={levels_str}"
|
|
73
|
+
|
|
58
74
|
@property
|
|
59
75
|
def config_hash(self) -> str:
|
|
60
76
|
"""Deterministic 8-char hex SHA256 of non-model-name fields.
|
|
61
77
|
|
|
62
78
|
Hash inputs: arch, vendor, memory_levels (name, size, instances, sharing).
|
|
79
|
+
|
|
80
|
+
.. note::
|
|
81
|
+
DRAM ``size_bytes`` comes from ``/proc/zoneinfo`` ``present`` pages
|
|
82
|
+
(physical capacity, stable across reboots). Falls back to a
|
|
83
|
+
rounded-``MemTotal`` value when zoneinfo is unavailable.
|
|
84
|
+
``num_sharing_threads`` is set to 0 for DRAM (not a hardware
|
|
85
|
+
property; CPU online count may vary). Cache-level fields are
|
|
86
|
+
used verbatim.
|
|
63
87
|
"""
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return
|
|
88
|
+
return hashlib.sha256(self._canonical_hash_string().encode("utf-8")).hexdigest()[:8]
|
|
89
|
+
|
|
90
|
+
def to_dict(self) -> dict[str, object]:
|
|
91
|
+
"""Serialize all fields for machine.json debugging output."""
|
|
92
|
+
return {
|
|
93
|
+
"model_name": self.model_name,
|
|
94
|
+
"arch": self.arch,
|
|
95
|
+
"vendor": self.vendor,
|
|
96
|
+
"config_hash": self.config_hash,
|
|
97
|
+
"hash_input": self._canonical_hash_string(),
|
|
98
|
+
"memory_levels": [
|
|
99
|
+
{
|
|
100
|
+
"name": lvl.name,
|
|
101
|
+
"size_bytes": lvl.size_bytes,
|
|
102
|
+
"instances": lvl.instances,
|
|
103
|
+
"num_sharing_threads": lvl.num_sharing_threads,
|
|
104
|
+
}
|
|
105
|
+
for lvl in self.memory_levels
|
|
106
|
+
],
|
|
107
|
+
}
|
|
69
108
|
|
|
70
109
|
|
|
71
110
|
def read_cpuinfo() -> CpuInfo:
|
|
@@ -102,21 +141,69 @@ def read_cpuinfo() -> CpuInfo:
|
|
|
102
141
|
return CpuInfo(model_name=model_name, vendor=vendor)
|
|
103
142
|
|
|
104
143
|
|
|
144
|
+
def _get_physical_ram_bytes() -> int | None:
|
|
145
|
+
"""Total physical RAM (bytes) from ``/proc/zoneinfo``, or ``None``.
|
|
146
|
+
|
|
147
|
+
Sums the ``present`` field across all zones — this is the number of
|
|
148
|
+
physical pages present, derived from the firmware's e820/device-tree
|
|
149
|
+
memory map at boot. It reflects hardware capacity and is stable across
|
|
150
|
+
reboots, unlike ``MemTotal`` which subtracts kernel runtime reservations.
|
|
151
|
+
"""
|
|
152
|
+
try:
|
|
153
|
+
with open("/proc/zoneinfo") as f:
|
|
154
|
+
total_present = 0
|
|
155
|
+
for line in f:
|
|
156
|
+
parts = line.strip().split()
|
|
157
|
+
if len(parts) == 2 and parts[0] == "present":
|
|
158
|
+
total_present += int(parts[1])
|
|
159
|
+
return total_present * os.sysconf("SC_PAGE_SIZE")
|
|
160
|
+
except (OSError, ValueError):
|
|
161
|
+
return None
|
|
162
|
+
|
|
163
|
+
|
|
105
164
|
def _levels_from_topology(topology: MemoryTopologyLike | None) -> tuple[MemoryLevelSignature, ...]:
|
|
106
|
-
"""Convert a memory topology to a tuple of deterministic level signatures.
|
|
165
|
+
"""Convert a memory topology to a tuple of deterministic level signatures.
|
|
166
|
+
|
|
167
|
+
DRAM levels use the ``present`` page count from ``/proc/zoneinfo`` (a
|
|
168
|
+
hardware-capacity value stable across reboots). Falls back to rounding
|
|
169
|
+
the topology's ``MemTotal``-based size to the nearest GiB when zoneinfo
|
|
170
|
+
is unavailable (containers, odd kernels).
|
|
171
|
+
|
|
172
|
+
``num_sharing_threads`` is set to 0 for DRAM (not a hardware property;
|
|
173
|
+
``shared_cpu_list`` varies with CPU online count).
|
|
174
|
+
|
|
175
|
+
Cache levels (L1/L2/L3) are passed through unchanged.
|
|
176
|
+
"""
|
|
177
|
+
# Read physical RAM once — stable firmware value
|
|
178
|
+
physical_ram = _get_physical_ram_bytes()
|
|
179
|
+
|
|
107
180
|
if topology is None:
|
|
108
181
|
return ()
|
|
109
182
|
levels: list[MemoryLevelSignature] = []
|
|
110
183
|
for lvl in topology:
|
|
111
184
|
if isinstance(lvl, MemoryLevelInfo):
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
185
|
+
if lvl.name == "DRAM":
|
|
186
|
+
if physical_ram is not None:
|
|
187
|
+
size_bytes = physical_ram
|
|
188
|
+
else:
|
|
189
|
+
size_bytes = round(int(lvl.size) / _BYTES_PER_GIB) * _BYTES_PER_GIB
|
|
190
|
+
levels.append(
|
|
191
|
+
MemoryLevelSignature(
|
|
192
|
+
name=lvl.name,
|
|
193
|
+
size_bytes=size_bytes,
|
|
194
|
+
instances=lvl.instances,
|
|
195
|
+
num_sharing_threads=0,
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
else:
|
|
199
|
+
levels.append(
|
|
200
|
+
MemoryLevelSignature(
|
|
201
|
+
name=lvl.name,
|
|
202
|
+
size_bytes=int(lvl.size),
|
|
203
|
+
instances=lvl.instances,
|
|
204
|
+
num_sharing_threads=lvl.num_sharing_threads,
|
|
205
|
+
)
|
|
118
206
|
)
|
|
119
|
-
)
|
|
120
207
|
return tuple(levels)
|
|
121
208
|
|
|
122
209
|
|
|
@@ -206,3 +293,18 @@ def _short_model_name(name: str) -> str:
|
|
|
206
293
|
def generate_run_name(signature: MachineSignature) -> str:
|
|
207
294
|
"""Generate ``"<short_model>_<config_hash>"`` (e.g. ``"Ryzen-7-7735HS_59486dd1"``)."""
|
|
208
295
|
return f"{_short_model_name(signature.model_name)}_{signature.config_hash}"
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def write_machine_json(signature: MachineSignature, directory: Path) -> None:
|
|
299
|
+
"""Write machine.json to *directory* if it does not already exist.
|
|
300
|
+
|
|
301
|
+
The file contains the full MachineSignature serialized as JSON, including
|
|
302
|
+
all hash inputs and the computed hash, so future runs can debug why a
|
|
303
|
+
machine hash changed.
|
|
304
|
+
"""
|
|
305
|
+
path = directory / "machine.json"
|
|
306
|
+
if path.exists():
|
|
307
|
+
return
|
|
308
|
+
directory.mkdir(parents=True, exist_ok=True)
|
|
309
|
+
with open(path, "x", encoding="utf-8") as f:
|
|
310
|
+
json.dump(signature.to_dict(), f, indent=2, sort_keys=True)
|
|
@@ -17,6 +17,7 @@ from architecture import (
|
|
|
17
17
|
generate_run_name,
|
|
18
18
|
set_execution_interface,
|
|
19
19
|
signature_from_architecture,
|
|
20
|
+
write_machine_json,
|
|
20
21
|
)
|
|
21
22
|
from arguments import InsertsArguments, TopLevelHelpFormatter
|
|
22
23
|
from benchmark.interface import run_full_benchmark
|
|
@@ -58,8 +59,9 @@ def _handle_benchmark(args: argparse.Namespace) -> int:
|
|
|
58
59
|
# Make exec_iface globally available for architecture feature detection
|
|
59
60
|
set_execution_interface(exec_iface)
|
|
60
61
|
architecture = Architecture(args)
|
|
62
|
+
signature = signature_from_architecture(architecture)
|
|
61
63
|
if args.name is None:
|
|
62
|
-
args.name = generate_run_name(
|
|
64
|
+
args.name = generate_run_name(signature)
|
|
63
65
|
benchmarking = Benchmarking(args)
|
|
64
66
|
run_config = RunConfig(args)
|
|
65
67
|
|
|
@@ -73,6 +75,7 @@ def _handle_benchmark(args: argparse.Namespace) -> int:
|
|
|
73
75
|
detail("Dry run finished: benchmark code generated successfully.")
|
|
74
76
|
return 0
|
|
75
77
|
|
|
78
|
+
write_machine_json(signature, run_config.output_dir / run_config.name)
|
|
76
79
|
output_benchmark_results(context, benchmark_suites)
|
|
77
80
|
return 0
|
|
78
81
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carm-roofline
|
|
3
|
-
Version: 1.0.2.
|
|
3
|
+
Version: 1.0.2.dev2
|
|
4
4
|
Summary: CARM: Cache-Aware Roofline Model benchmarking and visualization toolkit
|
|
5
5
|
Author: CHaMP Team
|
|
6
6
|
License: Apache License
|
|
@@ -246,7 +246,6 @@ Dynamic: license-file
|
|
|
246
246
|
|
|
247
247
|
# The CARM Tool
|
|
248
248
|
|
|
249
|
-
|
|
250
249
|
Cache-Aware Roofline Model (CARM) toolkit - benchmark, visualize and profile Intel, AMD, ARM, RISC-V CPUs and NVIDIA, AMD GPUs.
|
|
251
250
|
|
|
252
251
|
The package provides:
|
|
@@ -258,6 +257,10 @@ The package provides:
|
|
|
258
257
|
> [!WARNING]
|
|
259
258
|
> The development branch and associated python package are still experimental, and do not include all features yet. For a stable release, please refer to the main branch.
|
|
260
259
|
|
|
260
|
+
## Documentation
|
|
261
|
+
|
|
262
|
+
You can find the full documentation at [https://champ-hub.github.io/carm-roofline](https://champ-hub.github.io/carm-roofline/).
|
|
263
|
+
|
|
261
264
|
## Installation
|
|
262
265
|
|
|
263
266
|
Install from PyPI:
|
|
@@ -279,10 +282,17 @@ source carm-env/bin/activate
|
|
|
279
282
|
pip install carm-roofline[all]
|
|
280
283
|
```
|
|
281
284
|
|
|
285
|
+
If cloning the repository directly (e.g. for development or access to example applications), use `--recurse-submodules` to also fetch the examples:
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
git clone --recurse-submodules https://github.com/champ-hub/carm-roofline
|
|
289
|
+
```
|
|
290
|
+
|
|
282
291
|
## Requirements
|
|
283
292
|
|
|
284
293
|
- Python 3.9+
|
|
285
|
-
-
|
|
294
|
+
- C compiler (e.g. gcc, clang)
|
|
295
|
+
- Optional: [PAPI](https://github.com/icl-utk-edu/papi) headers and binaries for profiling
|
|
286
296
|
|
|
287
297
|
## Command-Line Interface
|
|
288
298
|
|
|
@@ -296,7 +306,7 @@ Available subcommands:
|
|
|
296
306
|
|
|
297
307
|
- `benchmark` - run benchmark suites
|
|
298
308
|
- `gui` - launch the results dashboard
|
|
299
|
-
- `profile` -
|
|
309
|
+
- `profile` - profile an application with PAPI or perf
|
|
300
310
|
|
|
301
311
|
Show help:
|
|
302
312
|
|
|
@@ -304,6 +314,7 @@ Show help:
|
|
|
304
314
|
carm --help
|
|
305
315
|
carm benchmark --help
|
|
306
316
|
carm gui --help
|
|
317
|
+
carm profile --help
|
|
307
318
|
```
|
|
308
319
|
|
|
309
320
|
## Basic Usage
|
|
@@ -28,6 +28,7 @@ from .shared import (
|
|
|
28
28
|
MetricDefinition,
|
|
29
29
|
MetricResolutionConfig,
|
|
30
30
|
MetricType,
|
|
31
|
+
RooflinePoint,
|
|
31
32
|
compute_region_point,
|
|
32
33
|
sum_roofline_points,
|
|
33
34
|
)
|
|
@@ -43,6 +44,7 @@ __all__ = [
|
|
|
43
44
|
"ProfilerBackend",
|
|
44
45
|
"RankMetrics",
|
|
45
46
|
"RegionMetrics",
|
|
47
|
+
"RooflinePoint",
|
|
46
48
|
"RunMetadata",
|
|
47
49
|
"RunResults",
|
|
48
50
|
"ThreadMetrics",
|
|
@@ -25,6 +25,7 @@ from .shared import (
|
|
|
25
25
|
MetricContext,
|
|
26
26
|
MetricDefinition,
|
|
27
27
|
MetricType,
|
|
28
|
+
RooflinePoint,
|
|
28
29
|
compute_region_point,
|
|
29
30
|
sum_roofline_points,
|
|
30
31
|
)
|
|
@@ -59,7 +60,7 @@ def _region_points(
|
|
|
59
60
|
regions: list[RegionMetrics],
|
|
60
61
|
resolved: dict[MetricType, MetricDefinition],
|
|
61
62
|
metric_ctx: MetricContext,
|
|
62
|
-
) -> list[
|
|
63
|
+
) -> list[RooflinePoint]:
|
|
63
64
|
"""Compute (flops, bytes, time_s) for each region in a list."""
|
|
64
65
|
return [compute_region_point(r.counters, r.time_nsec, resolved, metric_ctx) for r in regions]
|
|
65
66
|
|
|
@@ -75,17 +76,16 @@ def aggregate_global(
|
|
|
75
76
|
total time (regions within a thread execute sequentially, threads within
|
|
76
77
|
a rank run in parallel).
|
|
77
78
|
"""
|
|
78
|
-
thread_totals: list[
|
|
79
|
+
thread_totals: list[RooflinePoint] = []
|
|
79
80
|
num_regions = 0
|
|
80
81
|
for rank in run.ranks:
|
|
81
82
|
for thread in rank.threads:
|
|
82
83
|
thread_points = _region_points(thread.regions, resolved, metric_ctx)
|
|
83
84
|
thread_totals.append(sum_roofline_points(thread_points))
|
|
84
85
|
num_regions += len(thread_points)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
total_time = max((p["time_s"] for p in thread_totals), default=0.0)
|
|
86
|
+
total_flops = sum(p.flops for p in thread_totals)
|
|
87
|
+
total_bytes = sum(p.bytes for p in thread_totals)
|
|
88
|
+
total_time = max((p.time_s for p in thread_totals), default=0.0)
|
|
89
89
|
num_threads = sum(len(r.threads) for r in run.ranks)
|
|
90
90
|
return AggregatedPoint(
|
|
91
91
|
label=run.metadata.name or "global",
|
|
@@ -110,16 +110,16 @@ def aggregate_per_rank(
|
|
|
110
110
|
"""
|
|
111
111
|
points: list[AggregatedPoint] = []
|
|
112
112
|
for rank in run.ranks:
|
|
113
|
-
thread_totals: list[
|
|
113
|
+
thread_totals: list[RooflinePoint] = []
|
|
114
114
|
num_regions = 0
|
|
115
115
|
for thread in rank.threads:
|
|
116
116
|
thread_points = _region_points(thread.regions, resolved, metric_ctx)
|
|
117
117
|
thread_totals.append(sum_roofline_points(thread_points))
|
|
118
118
|
num_regions += len(thread_points)
|
|
119
119
|
|
|
120
|
-
total_flops = sum(p
|
|
121
|
-
total_bytes = sum(p
|
|
122
|
-
total_time = max((p
|
|
120
|
+
total_flops = sum(p.flops for p in thread_totals)
|
|
121
|
+
total_bytes = sum(p.bytes for p in thread_totals)
|
|
122
|
+
total_time = max((p.time_s for p in thread_totals), default=0.0)
|
|
123
123
|
label = f"{run.metadata.name}_rank{rank.rank_id}" if run.metadata.name else f"rank{rank.rank_id}"
|
|
124
124
|
points.append(
|
|
125
125
|
AggregatedPoint(
|
|
@@ -154,9 +154,9 @@ def aggregate_per_thread(
|
|
|
154
154
|
points.append(
|
|
155
155
|
AggregatedPoint(
|
|
156
156
|
label=label,
|
|
157
|
-
total_flops=total
|
|
158
|
-
total_bytes=total
|
|
159
|
-
runtime_s=total
|
|
157
|
+
total_flops=total.flops,
|
|
158
|
+
total_bytes=total.bytes,
|
|
159
|
+
runtime_s=total.time_s,
|
|
160
160
|
num_ranks=1,
|
|
161
161
|
num_threads=1,
|
|
162
162
|
num_regions=len(thread_points),
|
|
@@ -177,7 +177,7 @@ def aggregate_per_region_merged(
|
|
|
177
177
|
(parallel execution).
|
|
178
178
|
"""
|
|
179
179
|
# by_region[region_name][(rank_id, thread_id)] = [point, point, ...]
|
|
180
|
-
by_region: dict[str, dict[tuple[int, int], list[
|
|
180
|
+
by_region: dict[str, dict[tuple[int, int], list[RooflinePoint]]] = {}
|
|
181
181
|
|
|
182
182
|
for rank in run.ranks:
|
|
183
183
|
for thread in rank.threads:
|
|
@@ -192,9 +192,9 @@ def aggregate_per_region_merged(
|
|
|
192
192
|
# Sum within each thread (sequential calls)
|
|
193
193
|
per_thread_sums = {key: sum_roofline_points(pt_list) for key, pt_list in thread_groups.items()}
|
|
194
194
|
|
|
195
|
-
total_flops = sum(p
|
|
196
|
-
total_bytes = sum(p
|
|
197
|
-
total_time = max((p
|
|
195
|
+
total_flops = sum(p.flops for p in per_thread_sums.values())
|
|
196
|
+
total_bytes = sum(p.bytes for p in per_thread_sums.values())
|
|
197
|
+
total_time = max((p.time_s for p in per_thread_sums.values()), default=0.0)
|
|
198
198
|
|
|
199
199
|
rank_ids: set[int] = {rk for (rk, _) in thread_groups}
|
|
200
200
|
label = f"{run.metadata.name}_{name}" if run.metadata.name else name
|
|
@@ -235,9 +235,9 @@ def aggregate_per_region_per_thread(
|
|
|
235
235
|
points.append(
|
|
236
236
|
AggregatedPoint(
|
|
237
237
|
label=label,
|
|
238
|
-
total_flops=region_point
|
|
239
|
-
total_bytes=region_point
|
|
240
|
-
runtime_s=region_point
|
|
238
|
+
total_flops=region_point.flops,
|
|
239
|
+
total_bytes=region_point.bytes,
|
|
240
|
+
runtime_s=region_point.time_s,
|
|
241
241
|
num_ranks=1,
|
|
242
242
|
num_threads=1,
|
|
243
243
|
num_regions=1,
|
|
@@ -6,7 +6,7 @@ import argparse
|
|
|
6
6
|
from enum import Enum
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from architecture import detect_machine_signature, generate_run_name
|
|
9
|
+
from architecture import MachineSignature, detect_machine_signature, generate_run_name
|
|
10
10
|
from arguments import InsertsArguments, add_verbose_argument, enum_action
|
|
11
11
|
from benchmark.generation import ISA_NAME_TO_CLASS, DataType
|
|
12
12
|
from results_paths import default_results_root
|
|
@@ -55,7 +55,6 @@ class ProfileConfig(InsertsArguments):
|
|
|
55
55
|
verbose: Verbosity level (0-4).
|
|
56
56
|
machine_name: Name for the results directory (each machine gets its own subdirectory).
|
|
57
57
|
app_name: Application name recorded in the output metadata.
|
|
58
|
-
results_dir: Directory to scan for existing profiling result files.
|
|
59
58
|
keep_artifacts: Whether to keep raw profiling output files.
|
|
60
59
|
papi_events: Optional comma-separated PAPI event override.
|
|
61
60
|
perf_events: Optional comma-separated perf event override.
|
|
@@ -71,11 +70,11 @@ class ProfileConfig(InsertsArguments):
|
|
|
71
70
|
self.aggregation: AggregationMode = args.aggregation
|
|
72
71
|
self.verbose: int = args.verbose
|
|
73
72
|
self.output_dir: Path = args.output_dir
|
|
73
|
+
self.machine_signature: MachineSignature = detect_machine_signature()
|
|
74
74
|
self.machine_name: str = (
|
|
75
|
-
args.machine_name if args.machine_name is not None else generate_run_name(
|
|
75
|
+
args.machine_name if args.machine_name is not None else generate_run_name(self.machine_signature)
|
|
76
76
|
)
|
|
77
77
|
self.app_name: str = args.app_name if args.app_name is not None else _default_app_name(args.command)
|
|
78
|
-
self.results_dir: Path = args.results_dir
|
|
79
78
|
self.keep_artifacts: bool = args.keep_artifacts
|
|
80
79
|
self.papi_events: str | None = args.papi_events
|
|
81
80
|
self.perf_events: str | None = args.perf_events
|
|
@@ -121,12 +120,6 @@ class ProfileConfig(InsertsArguments):
|
|
|
121
120
|
type=Path,
|
|
122
121
|
help="Directory to write result files (default: platform user data dir for app 'carm')",
|
|
123
122
|
)
|
|
124
|
-
parser.add_argument(
|
|
125
|
-
"--results-dir",
|
|
126
|
-
default=default_results_root() / "profile",
|
|
127
|
-
type=Path,
|
|
128
|
-
help="Directory to scan for existing profiling result files (default: <output-dir>/profile)",
|
|
129
|
-
)
|
|
130
123
|
parser.add_argument(
|
|
131
124
|
"--keep-artifacts",
|
|
132
125
|
action="store_true",
|
|
@@ -10,6 +10,7 @@ import csv
|
|
|
10
10
|
import json
|
|
11
11
|
from datetime import datetime
|
|
12
12
|
|
|
13
|
+
from architecture import write_machine_json
|
|
13
14
|
from output_utils import detail, info
|
|
14
15
|
|
|
15
16
|
from .aggregation import AggregatedPoint
|
|
@@ -28,7 +29,12 @@ def write_profile_results(
|
|
|
28
29
|
(GUI-compatible legacy format). JSONL is written to
|
|
29
30
|
``<output_dir>/<machine_name>/applications.jsonl`` (one appended line per run,
|
|
30
31
|
embedding run metadata and the aggregated points).
|
|
32
|
+
|
|
33
|
+
A ``machine.json`` debugging file is also written to
|
|
34
|
+
``<output_dir>/<machine_name>/machine.json`` on the first run.
|
|
31
35
|
"""
|
|
36
|
+
machine_dir = config.output_dir / config.machine_name
|
|
37
|
+
write_machine_json(config.machine_signature, machine_dir)
|
|
32
38
|
write_applications_csv(points, config, run)
|
|
33
39
|
write_profile_jsonl(run, config, points)
|
|
34
40
|
|
|
@@ -108,6 +108,22 @@ class MetricDefinition:
|
|
|
108
108
|
warning: str | None = None
|
|
109
109
|
|
|
110
110
|
|
|
111
|
+
@dataclass(frozen=True)
|
|
112
|
+
class RooflinePoint:
|
|
113
|
+
"""Computed roofline metrics for a single region or aggregated set."""
|
|
114
|
+
|
|
115
|
+
flops: float = 0.0
|
|
116
|
+
bytes: float = 0.0
|
|
117
|
+
time_s: float = 0.0
|
|
118
|
+
|
|
119
|
+
def __add__(self, other: RooflinePoint) -> RooflinePoint:
|
|
120
|
+
return RooflinePoint(
|
|
121
|
+
flops=self.flops + other.flops,
|
|
122
|
+
bytes=self.bytes + other.bytes,
|
|
123
|
+
time_s=self.time_s + other.time_s,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
111
127
|
# ---------------------------------------------------------------------------
|
|
112
128
|
# Computing roofline point data from raw counters
|
|
113
129
|
# ---------------------------------------------------------------------------
|
|
@@ -118,7 +134,7 @@ def compute_region_point(
|
|
|
118
134
|
time_nsec: int,
|
|
119
135
|
resolved: dict[MetricType, MetricDefinition],
|
|
120
136
|
metric_ctx: MetricContext,
|
|
121
|
-
) ->
|
|
137
|
+
) -> RooflinePoint:
|
|
122
138
|
"""Compute (flops, bytes, time_s) for a single region from raw counters.
|
|
123
139
|
|
|
124
140
|
Only metrics whose required events are all present in *counters* are
|
|
@@ -129,8 +145,7 @@ def compute_region_point(
|
|
|
129
145
|
time_nsec: Wall-clock time in nanoseconds for the region.
|
|
130
146
|
resolved: Resolved metric implementations from ``resolve_metrics()``.
|
|
131
147
|
|
|
132
|
-
|
|
133
|
-
A dict with keys ``flops``, ``bytes``, and ``time_s``.
|
|
148
|
+
A `RooflinePoint` with flops, bytes, and time_s.
|
|
134
149
|
"""
|
|
135
150
|
float_counters = {k: float(v) for k, v in counters.items()}
|
|
136
151
|
available_set = frozenset(counters)
|
|
@@ -147,23 +162,16 @@ def compute_region_point(
|
|
|
147
162
|
if impl.required_events <= available_set:
|
|
148
163
|
bytes_val = impl.compute(float_counters, metric_ctx)
|
|
149
164
|
|
|
150
|
-
return
|
|
151
|
-
"flops": flops,
|
|
152
|
-
"bytes": bytes_val,
|
|
153
|
-
"time_s": time_nsec / 1e9,
|
|
154
|
-
}
|
|
165
|
+
return RooflinePoint(flops=flops, bytes=bytes_val, time_s=time_nsec / 1e9)
|
|
155
166
|
|
|
156
167
|
|
|
157
|
-
def sum_roofline_points(points: list[
|
|
158
|
-
"""Sum a list of (flops, bytes, time_s)
|
|
168
|
+
def sum_roofline_points(points: list[RooflinePoint]) -> RooflinePoint:
|
|
169
|
+
"""Sum a list of (flops, bytes, time_s) RooflinePoints.
|
|
159
170
|
|
|
160
171
|
Flops, bytes, and time are all summed, all points in the list represent
|
|
161
172
|
sequential execution within a single thread.
|
|
162
173
|
"""
|
|
163
|
-
|
|
164
|
-
bytes_val = sum(p["bytes"] for p in points)
|
|
165
|
-
time_s = sum(p["time_s"] for p in points)
|
|
166
|
-
return {"flops": flops, "bytes": bytes_val, "time_s": time_s}
|
|
174
|
+
return sum(points, start=RooflinePoint())
|
|
167
175
|
|
|
168
176
|
|
|
169
177
|
def resolve_metrics(
|
|
@@ -170,6 +170,8 @@ measure_benchmark(const benchmark_metadata_t *metadata, wrapper_fn_t wrapper_fn,
|
|
|
170
170
|
tdata[i].read_ptr = (void *) ((char *) combined_data + thread_offset);
|
|
171
171
|
tdata[i].write_ptr = (void *) ((char *) combined_data + thread_offset + aligned_read);
|
|
172
172
|
tdata[i].freq = freq;
|
|
173
|
+
tdata[i].read_size = aligned_read;
|
|
174
|
+
tdata[i].write_size = aligned_write;
|
|
173
175
|
|
|
174
176
|
#if VERBOSITY >= 4
|
|
175
177
|
if (tdata[i].read_ptr != NULL) {
|
|
@@ -47,6 +47,8 @@ typedef struct {
|
|
|
47
47
|
void *read_ptr; /* Per-thread slice of the read (load) buffer */
|
|
48
48
|
void *write_ptr; /* Per-thread slice of the write (store) buffer */
|
|
49
49
|
float freq;
|
|
50
|
+
size_t read_size; /* Per-thread read buffer size (aligned, bytes) */
|
|
51
|
+
size_t write_size; /* Per-thread write buffer size (aligned, bytes) */
|
|
50
52
|
/* Timing results per thread (nanoseconds) */
|
|
51
53
|
uint64_t *elapsed_ns; /* Elapsed time in nanoseconds */
|
|
52
54
|
} thread_wrapper_data_t;
|
|
@@ -19,6 +19,13 @@ static void *_WRAPPER_EXPAND(UBENCH_NAME)(void *arg)
|
|
|
19
19
|
void *read_ptr = tdata->read_ptr;
|
|
20
20
|
void *write_ptr = tdata->write_ptr;
|
|
21
21
|
|
|
22
|
+
/* Force COW: write one byte per page so the kernel allocates real physical pages (not the shared zero page). This
|
|
23
|
+
* ensures NUMA-correct first-touch placement and prevents load-only benchmarks from measuring L1 bandwidth
|
|
24
|
+
* regardless of working set size. */
|
|
25
|
+
for (size_t off = 0; off < tdata->read_size; off += 4096)
|
|
26
|
+
((volatile char *) read_ptr)[off] = 0;
|
|
27
|
+
for (size_t off = 0; off < tdata->write_size; off += 4096)
|
|
28
|
+
((volatile char *) write_ptr)[off] = 0;
|
|
22
29
|
barrier_sync();
|
|
23
30
|
|
|
24
31
|
uint64_t reps = CARM_BENCH_START_REPS;
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/riscv/rvv_version.c
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/architecture/tests/x86/x86_avx512/frequency.h
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/__init__.py
RENAMED
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/data_type.py
RENAMED
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/instruction.py
RENAMED
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/operation.py
RENAMED
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/benchmark/generation/code_gen/register.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{carm_roofline-1.0.2.dev1 → carm_roofline-1.0.2.dev2}/carm_roofline.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|