carm-roofline 1.0.2.dev1__tar.gz → 1.0.3.dev1__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.
Files changed (113) hide show
  1. {carm_roofline-1.0.2.dev1/carm_roofline.egg-info → carm_roofline-1.0.3.dev1}/PKG-INFO +15 -4
  2. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/README.md +14 -3
  3. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/__init__.py +8 -1
  4. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/architecture.py +6 -9
  5. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/arm.py +1 -1
  6. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/config.py +1 -2
  7. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/detect.py +2 -3
  8. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/identity.py +115 -13
  9. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/memory.py +1 -2
  10. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/riscv.py +4 -4
  11. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/x86.py +1 -1
  12. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/__init__.py +0 -3
  13. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/benchmark.py +1 -1
  14. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/benchmarking.py +1 -4
  15. carm_roofline-1.0.3.dev1/benchmark/generation/__init__.py +10 -0
  16. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/generation/code_gen/__init__.py +0 -4
  17. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/generation/code_gen/instruction.py +2 -2
  18. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/generation/code_gen/register.py +1 -1
  19. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/generation/parameters.py +4 -6
  20. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/arithmetic.py +2 -2
  21. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/common.py +1 -1
  22. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/jsonl.py +3 -3
  23. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/memory.py +2 -2
  24. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/memory_sweep.py +2 -2
  25. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/roofline.py +176 -55
  26. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/result.py +1 -1
  27. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/arithmetic.py +1 -1
  28. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/base.py +1 -1
  29. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/memory.py +2 -2
  30. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/memory_sweep.py +2 -2
  31. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/roofline.py +1 -1
  32. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/carm.py +5 -2
  33. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1/carm_roofline.egg-info}/PKG-INFO +15 -4
  34. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/carm_roofline.egg-info/SOURCES.txt +10 -9
  35. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/carm_roofline.egg-info/top_level.txt +2 -3
  36. carm_roofline-1.0.3.dev1/core/__init__.py +33 -0
  37. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/assets/style.css +7 -0
  38. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/components.py +20 -11
  39. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/data.py +157 -40
  40. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/factory.py +196 -83
  41. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/ids.py +1 -0
  42. carm_roofline-1.0.3.dev1/isa/__init__.py +44 -0
  43. {carm_roofline-1.0.2.dev1/benchmark/generation → carm_roofline-1.0.3.dev1/isa}/arm.py +5 -5
  44. carm_roofline-1.0.2.dev1/benchmark/generation/isa.py → carm_roofline-1.0.3.dev1/isa/base.py +9 -6
  45. {carm_roofline-1.0.2.dev1/benchmark/generation → carm_roofline-1.0.3.dev1/isa}/riscv.py +5 -5
  46. {carm_roofline-1.0.2.dev1/benchmark/generation → carm_roofline-1.0.3.dev1/isa}/x86.py +4 -4
  47. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/output_utils.py +7 -6
  48. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/__init__.py +5 -3
  49. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/aggregation.py +20 -20
  50. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/backends.py +1 -1
  51. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/config.py +17 -15
  52. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/output.py +6 -0
  53. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/papi_backend.py +50 -4
  54. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/papi_metrics.py +239 -6
  55. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/perf_backend.py +1 -1
  56. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/perf_metrics.py +1 -1
  57. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/shared.py +36 -27
  58. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/pyproject.toml +5 -27
  59. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/roofline_assembly.py +73 -82
  60. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test/test_gui_data.py +25 -8
  61. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test/test_isa_codegen_integration.py +6 -6
  62. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test/test_memory_suite_generation.py +2 -2
  63. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test/test_output_module.py +147 -34
  64. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test/test_roofline_assembly.py +267 -15
  65. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test/test_typed_benchmarks.py +3 -3
  66. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test_bench/builder.py +1 -1
  67. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test_bench/test_bench.c +2 -0
  68. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test_bench/test_bench.h +2 -0
  69. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test_bench/wrapper.inl +7 -0
  70. carm_roofline-1.0.2.dev1/benchmark/generation/__init__.py +0 -53
  71. carm_roofline-1.0.2.dev1/utils.py +0 -177
  72. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/LICENSE +0 -0
  73. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/frequency.py +0 -0
  74. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/arm/features.c +0 -0
  75. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/arm/frequency.h +0 -0
  76. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/arm/vlen.c +0 -0
  77. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/frequency.c +0 -0
  78. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/riscv/frequency.h +0 -0
  79. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/riscv/rvv_version.c +0 -0
  80. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/riscv/vlen.c +0 -0
  81. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/x86/cache.c +0 -0
  82. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/x86/features.c +0 -0
  83. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/x86/frequency.h +0 -0
  84. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/architecture/tests/x86/x86_avx512/frequency.h +0 -0
  85. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/arguments.py +0 -0
  86. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/interface.py +0 -0
  87. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/__init__.py +0 -0
  88. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/base.py +0 -0
  89. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/output/mixed.py +0 -0
  90. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/__init__.py +0 -0
  91. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/benchmark/suites/mixed.py +0 -0
  92. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/carm_roofline.egg-info/dependency_links.txt +0 -0
  93. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/carm_roofline.egg-info/entry_points.txt +0 -0
  94. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/carm_roofline.egg-info/requires.txt +0 -0
  95. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/context.py +0 -0
  96. {carm_roofline-1.0.2.dev1/benchmark/generation/code_gen → carm_roofline-1.0.3.dev1/core}/data_type.py +0 -0
  97. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1/core}/error.py +0 -0
  98. {carm_roofline-1.0.2.dev1/benchmark/generation/code_gen → carm_roofline-1.0.3.dev1/core}/operation.py +0 -0
  99. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1/core}/units.py +0 -0
  100. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/exec_interface.py +0 -0
  101. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/__init__.py +0 -0
  102. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/assets/CARM_icon.svg +0 -0
  103. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/assets/CHAMP_logo.svg +0 -0
  104. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/assets/menu_icon.png +0 -0
  105. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/gui/config.py +0 -0
  106. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/model.py +0 -0
  107. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/papi_loader.py +0 -0
  108. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/profiling/perf_loader.py +0 -0
  109. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/results_paths.py +0 -0
  110. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/run_config.py +0 -0
  111. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/setup.cfg +0 -0
  112. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/test_bench/__init__.py +0 -0
  113. {carm_roofline-1.0.2.dev1 → carm_roofline-1.0.3.dev1}/workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: carm-roofline
3
- Version: 1.0.2.dev1
3
+ Version: 1.0.3.dev1
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
- - GCC (for compiling benchmark binaries)
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` - coming soon
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
- - GCC (for compiling benchmark binaries)
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` - coming soon
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 MachineSignature, detect_machine_signature, generate_run_name, signature_from_architecture
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
  ]
@@ -5,13 +5,12 @@ from pathlib import Path
5
5
  from typing import TYPE_CHECKING, Any
6
6
 
7
7
  from arguments import InsertsArguments, positive_int
8
- from benchmark import generation as bench_gen
9
- from error import UserError
8
+ from core import Frequency, UserError
9
+ from isa import INCOMPATIBLE_ISAS, ISA_NAME_TO_CLASS
10
10
  from output_utils import configure_verbosity, debug, detail, format_if_container, warn
11
- from units import Frequency
12
11
 
13
12
  if TYPE_CHECKING:
14
- from benchmark.generation import BaseISA
13
+ from isa import BaseISA
15
14
 
16
15
  from .config import load_memory_topology_from_toml
17
16
  from .detect import DetectedArchitecture, detect_for_isa, native_detect
@@ -32,7 +31,7 @@ def check_isa_compatibility(selected_isas: list[type[BaseISA]]) -> None:
32
31
 
33
32
  # Check for special incompatibilities within the same family
34
33
  isa_set = set(selected_isas)
35
- for incompatible_pair in bench_gen.INCOMPATIBLE_ISAS:
34
+ for incompatible_pair in INCOMPATIBLE_ISAS:
36
35
  if incompatible_pair.issubset(isa_set):
37
36
  pair_names = ", ".join(isa.name for isa in incompatible_pair)
38
37
  raise UserError(f"Incompatible ISAs selected: {pair_names}")
@@ -245,10 +244,8 @@ class Architecture(InsertsArguments):
245
244
  detected = native_detect(threads=num_threads)
246
245
  isa_strs = detected.isa or []
247
246
 
248
- self.isa: list[type[BaseISA]] = [bench_gen.ISA_NAME_TO_CLASS[isa_str] for isa_str in isa_strs]
247
+ self.isa: list[type[BaseISA]] = [ISA_NAME_TO_CLASS[isa_str] for isa_str in isa_strs]
249
248
  else:
250
- from benchmark.generation import ISA_NAME_TO_CLASS
251
-
252
249
  self.isa = [ISA_NAME_TO_CLASS[isa_name] for isa_name in args.isa]
253
250
  # Verify that the selected ISAs are compatible
254
251
  check_isa_compatibility(self.isa)
@@ -279,7 +276,7 @@ class Architecture(InsertsArguments):
279
276
 
280
277
  @staticmethod
281
278
  def insert_arguments(parser: argparse.ArgumentParser) -> None:
282
- from benchmark.generation import ISA_NAME_TO_CLASS
279
+ from isa import ISA_NAME_TO_CLASS
283
280
 
284
281
  parser.add_argument(
285
282
  "-i",
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from architecture.detect import DetectedArchitecture, TestContext, run_generic_tests
4
- from benchmark.generation import ArmNeon, ArmScalar, ArmSVE
4
+ from isa import ArmNeon, ArmScalar, ArmSVE
5
5
 
6
6
 
7
7
  def detect(threads: int = 1) -> DetectedArchitecture:
@@ -18,8 +18,7 @@ from __future__ import annotations
18
18
  from pathlib import Path
19
19
  from typing import cast
20
20
 
21
- from error import UserError
22
- from units import Bytes
21
+ from core import Bytes, UserError
23
22
 
24
23
  from .memory import SimpleMemoryTopology
25
24
 
@@ -15,12 +15,11 @@ from dataclasses import dataclass
15
15
  from pathlib import Path
16
16
  from typing import TYPE_CHECKING, Any
17
17
 
18
- from error import UserError
18
+ from core import Frequency, UserError
19
19
  from output_utils import debug, detail, warn
20
- from units import Frequency
21
20
 
22
21
  if TYPE_CHECKING:
23
- from benchmark.generation import BaseISA
22
+ from isa import BaseISA
24
23
 
25
24
  from .memory import MemoryTopology
26
25
 
@@ -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
- levels_str = "|".join(
65
- f"{lvl.name}:{lvl.size_bytes}:{lvl.instances}:{lvl.num_sharing_threads}" for lvl in self.memory_levels
66
- )
67
- canonical = f"arch={self.arch};vendor={self.vendor};levels={levels_str}"
68
- return hashlib.sha256(canonical.encode("utf-8")).hexdigest()[:8]
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
- levels.append(
113
- MemoryLevelSignature(
114
- name=lvl.name,
115
- size_bytes=int(lvl.size),
116
- instances=lvl.instances,
117
- num_sharing_threads=lvl.num_sharing_threads,
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)
@@ -9,9 +9,8 @@ from enum import Enum
9
9
  from pathlib import Path
10
10
  from typing import Protocol, runtime_checkable
11
11
 
12
- from error import UserError
12
+ from core import Bytes, UserError
13
13
  from output_utils import debug, format_if_container
14
- from units import Bytes
15
14
 
16
15
  _CPU_ROOT = Path("/sys/devices/system/cpu")
17
16
 
@@ -3,8 +3,8 @@ from __future__ import annotations
3
3
  import tempfile
4
4
  from pathlib import Path
5
5
 
6
- from benchmark import generation as bench_gen
7
6
  from exec_interface import ExecutionInterface
7
+ from isa import RISCV_RVV, RISCV_RVV_071, RISCVScalar
8
8
 
9
9
  from .detect import ROOT, DetectedArchitecture, TestContext, run_generic_tests
10
10
 
@@ -24,7 +24,7 @@ def detect(threads: int = 1) -> DetectedArchitecture:
24
24
  detected = run_generic_tests(ctx, threads=threads)
25
25
 
26
26
  # Build ISA list with scalar as base
27
- isa_list = [bench_gen.RISCVScalar.name]
27
+ isa_list = [RISCVScalar.name]
28
28
 
29
29
  # Detect RVV version using RISC-V specific test
30
30
  exec_iface = _get_execution_interface()
@@ -33,9 +33,9 @@ def detect(threads: int = 1) -> DetectedArchitecture:
33
33
  if rvv_version_probe_path.exists():
34
34
  # Try compiling with RVV 1.0 flag first (most common)
35
35
  if _can_compile_rvv(exec_iface, rvv_version_probe_path, "RISCV_RVV"):
36
- isa_list.append(bench_gen.RISCV_RVV.name)
36
+ isa_list.append(RISCV_RVV.name)
37
37
  elif _can_compile_rvv(exec_iface, rvv_version_probe_path, "RISCV_RVV_0_7_1"):
38
- isa_list.append(bench_gen.RISCV_RVV_071.name)
38
+ isa_list.append(RISCV_RVV_071.name)
39
39
 
40
40
  detected.isa = isa_list
41
41
 
@@ -1,7 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from architecture.detect import ROOT, DetectedArchitecture, TestContext, run_generic_tests, run_test
4
- from units import Frequency
4
+ from core import Frequency
5
5
 
6
6
 
7
7
  def detect(threads: int = 1) -> DetectedArchitecture:
@@ -11,7 +11,6 @@ from .benchmark import (
11
11
  MixedBenchmarkResult,
12
12
  )
13
13
  from .benchmarking import Benchmarking, TestType
14
- from .generation import ALL_ISAS, BaseISA
15
14
  from .interface import generate_microbenchmarks, run_full_benchmark
16
15
  from .result import OutputFormat
17
16
  from .suites import (
@@ -23,13 +22,11 @@ from .suites import (
23
22
  )
24
23
 
25
24
  __all__ = [
26
- "ALL_ISAS",
27
25
  "ArithmeticBenchmark",
28
26
  "ArithmeticBenchmarkResult",
29
27
  "ArithmeticBenchmarkSuite",
30
28
  "BaseBenchmark",
31
29
  "BaseBenchmarkResult",
32
- "BaseISA",
33
30
  "Benchmarking",
34
31
  "ISABenchmarkSuite",
35
32
  "MemoryBenchmark",
@@ -8,9 +8,9 @@ from __future__ import annotations
8
8
  from abc import ABC, abstractmethod
9
9
  from dataclasses import dataclass, field
10
10
 
11
+ from core import ArithmeticIntensity, Bandwidth, Bytes, Performance, Seconds
11
12
  from output_utils import debug
12
13
  from test_bench.builder import MicrobenchmarkFunctionSpec
13
- from units import ArithmeticIntensity, Bandwidth, Bytes, Performance, Seconds
14
14
 
15
15
  from .generation import ArithmeticBenchmarkParams, BenchmarkParams, MemoryBenchmarkParams
16
16
 
@@ -10,11 +10,8 @@ from enum import Enum
10
10
  from typing import TypeVar
11
11
 
12
12
  from arguments import InsertsArguments, enum_action, positive_float, positive_int
13
- from benchmark.generation.code_gen.operation import ArithmeticOperation
13
+ from core import ArithmeticOperation, Bytes, DataType, Operations
14
14
  from output_utils import warn
15
- from units import Bytes, Operations
16
-
17
- from .generation import DataType
18
15
 
19
16
 
20
17
  class TestType(Enum):
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from .parameters import ArithmeticBenchmarkParams, BenchmarkParams, MemoryBenchmarkParams, MemoryLayoutMode
4
+
5
+ __all__ = [
6
+ "ArithmeticBenchmarkParams",
7
+ "BenchmarkParams",
8
+ "MemoryBenchmarkParams",
9
+ "MemoryLayoutMode",
10
+ ]
@@ -1,17 +1,13 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  from . import instruction
4
- from .data_type import DataType
5
4
  from .instruction import ControlInstructions, TypedInstructions, escape_for_inline_asm
6
- from .operation import Operation
7
5
  from .register import CyclicRegisterSet, HelperRegisterSet, TypedRegisterSets
8
6
 
9
7
  __all__ = [
10
8
  "ControlInstructions",
11
9
  "CyclicRegisterSet",
12
- "DataType",
13
10
  "HelperRegisterSet",
14
- "Operation",
15
11
  "TypedInstructions",
16
12
  "TypedRegisterSets",
17
13
  "escape_for_inline_asm",
@@ -3,8 +3,8 @@ from __future__ import annotations
3
3
  from enum import Enum, auto
4
4
  from typing import Union, overload
5
5
 
6
- from .data_type import DataType
7
- from .operation import ArithmeticOperation, MemoryOperation, Operation
6
+ from core import ArithmeticOperation, DataType, MemoryOperation, Operation
7
+
8
8
  from .register import CyclicRegisterSet
9
9
 
10
10
  # Type alias for objects that can be converted to string
@@ -3,7 +3,7 @@ from __future__ import annotations
3
3
  from collections.abc import Iterable, Iterator
4
4
  from typing import Union
5
5
 
6
- from .data_type import DataType
6
+ from core import DataType
7
7
 
8
8
  __all__ = [
9
9
  "CyclicRegisterSet",
@@ -4,14 +4,12 @@ from dataclasses import dataclass
4
4
  from enum import Enum
5
5
  from typing import TYPE_CHECKING
6
6
 
7
- import units
8
- from benchmark.generation.code_gen.operation import ArithmeticOperation
9
- from units import Bytes, Operations
7
+ from core import ArithmeticOperation, Bytes, Operations
10
8
 
11
9
  if TYPE_CHECKING:
12
10
  from benchmark.benchmarking import LoadStoreRatio
13
11
 
14
- from .code_gen import DataType
12
+ from core import DataType
15
13
 
16
14
 
17
15
  class BenchParamError(Exception):
@@ -52,14 +50,14 @@ class ArithmeticBenchmarkParams(BenchmarkParams):
52
50
  params = ArithmeticBenchmarkParams(
53
51
  data_type=DataType.f32,
54
52
  operation=ArithmeticOperation.fma,
55
- num_ops=units.Operations(1000),
53
+ num_ops=Operations(1000),
56
54
  thread_affinity=[0, 1, 2, 3],
57
55
  )
58
56
  spec = isa.generate_arithmetic(params)
59
57
  """
60
58
 
61
59
  operation: ArithmeticOperation
62
- num_ops: units.Operations
60
+ num_ops: Operations
63
61
 
64
62
  def __post_init__(self) -> None:
65
63
  super().__post_init__()
@@ -8,8 +8,8 @@ from typing import TYPE_CHECKING, Any
8
8
 
9
9
  from rich.table import Table
10
10
 
11
+ from core import Cycles
11
12
  from output_utils import error, get_console, warn
12
- from units import Cycles
13
13
 
14
14
  from .base import NON_ROOFLINE_CSV_ERROR_MSG, OutputHandler
15
15
  from .common import (
@@ -47,7 +47,7 @@ def _collect_gops_by_isa(isa_suites: dict[str, ISABenchmarkSuite]) -> dict[str,
47
47
 
48
48
  def _print_table(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite]) -> None:
49
49
  from benchmark.benchmark import ArithmeticBenchmarkResult
50
- from benchmark.generation.isa import BaseISA
50
+ from isa import BaseISA
51
51
 
52
52
  print_extra = context.run_config.verbose >= 3
53
53
 
@@ -11,7 +11,7 @@ from typing import TYPE_CHECKING, Any
11
11
  from output_utils import error, info, warn
12
12
 
13
13
  if TYPE_CHECKING:
14
- from benchmark.generation.code_gen import DataType
14
+ from core import DataType
15
15
 
16
16
 
17
17
  def format_precision_label(data_type: DataType) -> str:
@@ -13,16 +13,16 @@ from datetime import datetime
13
13
  from pathlib import Path
14
14
  from typing import TYPE_CHECKING
15
15
 
16
+ from core import Cycles
16
17
  from output_utils import info, warn
17
18
  from roofline_assembly import RecordType
18
- from units import Cycles
19
19
 
20
20
  if TYPE_CHECKING:
21
21
  from benchmark.benchmark import ArithmeticBenchmark, MemoryBenchmark
22
- from benchmark.generation.isa import BaseISA
23
22
  from benchmark.suites.base import ISABenchmarkSuite
24
23
  from context import CARMContext
25
- from units import Frequency
24
+ from core import Frequency
25
+ from isa import BaseISA
26
26
 
27
27
 
28
28
  def _serialize_arithmetic(
@@ -9,9 +9,9 @@ from typing import TYPE_CHECKING, Any
9
9
  from rich.table import Table
10
10
 
11
11
  from benchmark.benchmark import MemoryBenchmarkResult
12
- from benchmark.generation.isa import BaseISA
12
+ from core import Cycles
13
+ from isa import BaseISA
13
14
  from output_utils import error, warn
14
- from units import Cycles
15
15
 
16
16
  from .base import NON_ROOFLINE_CSV_ERROR_MSG, OutputHandler
17
17
  from .common import (
@@ -9,10 +9,10 @@ from typing import TYPE_CHECKING, Any
9
9
  from rich.table import Table
10
10
 
11
11
  from benchmark.benchmark import MemoryBenchmarkResult
12
- from benchmark.generation.isa import BaseISA
13
12
  from benchmark.suites import MemorySweepBenchmarkSuite
13
+ from core import Cycles
14
+ from isa import BaseISA
14
15
  from output_utils import error, warn
15
- from units import Cycles
16
16
 
17
17
  from .base import NON_ROOFLINE_CSV_ERROR_MSG, OutputHandler
18
18
  from .common import safe_matplotlib_import, save_or_show_plot