carm-roofline 1.0.0.dev2__tar.gz → 1.0.0.dev4__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.0.dev2 → carm_roofline-1.0.0.dev4}/PKG-INFO +26 -22
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/README.md +23 -20
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/benchmarking.py +4 -4
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/arithmetic.py +67 -64
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/roofline.py +24 -5
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/arithmetic.py +12 -26
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/memory_sweep.py +6 -4
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/roofline.py +1 -17
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm_roofline.egg-info/PKG-INFO +26 -22
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm_roofline.egg-info/SOURCES.txt +1 -7
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm_roofline.egg-info/requires.txt +2 -1
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm_roofline.egg-info/top_level.txt +1 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/config.py +3 -2
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/dashboard.py +16 -3
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/pyproject.toml +5 -3
- carm_roofline-1.0.0.dev4/results_paths.py +13 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/run_config.py +5 -4
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/test_bench/builder.py +3 -0
- carm_roofline-1.0.0.dev2/DBI_AI_Calculator.py +0 -940
- carm_roofline-1.0.0.dev2/PMU_AI_Calculator.py +0 -219
- carm_roofline-1.0.0.dev2/SDE_AI_Calculator.py +0 -804
- carm_roofline-1.0.0.dev2/architecture/tests/REFACTOR.md +0 -2
- carm_roofline-1.0.0.dev2/architecture/tests/frequency +0 -0
- carm_roofline-1.0.0.dev2/architecture/tests/x86/cache +0 -0
- carm_roofline-1.0.0.dev2/architecture/tests/x86/features +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/LICENSE +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/architecture.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/arm.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/config.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/detect.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/frequency.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/memory.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/riscv.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/arm/features.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/arm/frequency.h +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/arm/vlen.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/frequency.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/riscv/frequency.h +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/riscv/rvv_version.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/riscv/vlen.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/x86/cache.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/x86/features.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/x86/frequency.h +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/tests/x86/x86_avx512/frequency.h +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/architecture/x86.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/arguments.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/benchmark.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/arm.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/code_gen/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/code_gen/data_type.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/code_gen/instruction.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/code_gen/operation.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/code_gen/register.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/isa.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/parameters.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/riscv.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/generation/x86.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/interface.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/base.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/common.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/memory.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/memory_sweep.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/output/mixed.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/result.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/base.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/memory.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/benchmark/suites/mixed.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm.py +1 -1
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm_roofline.egg-info/dependency_links.txt +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/carm_roofline.egg-info/entry_points.txt +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/context.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/error.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/exec_interface.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/assets/CARM_icon.svg +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/assets/CHAMP_logo.svg +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/assets/menu_icon.png +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/assets/style.css +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/gui/gui_utils.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/output_utils.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/setup.cfg +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/test_bench/__init__.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/test_bench/test_bench.c +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/test_bench/test_bench.h +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/test_bench/wrapper.inl +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/units.py +0 -0
- {carm_roofline-1.0.0.dev2 → carm_roofline-1.0.0.dev4}/utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: carm-roofline
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev4
|
|
4
4
|
Summary: CARM: Cache-Aware Roofline Model benchmarking and visualization toolkit
|
|
5
5
|
Author: CHaMP Team
|
|
6
6
|
License: GNU LESSER GENERAL PUBLIC LICENSE
|
|
@@ -525,9 +525,10 @@ Description-Content-Type: text/markdown
|
|
|
525
525
|
License-File: LICENSE
|
|
526
526
|
Requires-Dist: rich>=14.3.2
|
|
527
527
|
Requires-Dist: rich-argparse>=1.7.0
|
|
528
|
-
Requires-Dist: numpy>=
|
|
528
|
+
Requires-Dist: numpy>=2.0.0
|
|
529
529
|
Requires-Dist: matplotlib>=3.7.2
|
|
530
530
|
Requires-Dist: tomli>=2.0.0
|
|
531
|
+
Requires-Dist: platformdirs>=4.0.0
|
|
531
532
|
Provides-Extra: gui
|
|
532
533
|
Requires-Dist: dash[diskcache]; extra == "gui"
|
|
533
534
|
Requires-Dist: dash-bootstrap-components; extra == "gui"
|
|
@@ -545,42 +546,45 @@ Requires-Dist: carm-roofline[dev,gui]; extra == "all"
|
|
|
545
546
|
Dynamic: license-file
|
|
546
547
|
|
|
547
548
|
|
|
548
|
-
# CARM
|
|
549
|
+
# The CARM Tool
|
|
549
550
|
|
|
550
|
-
|
|
551
|
+
|
|
552
|
+
Cache-Aware Roofline Model (CARM) toolkit - benchmark, visualize and profile Intel, AMD, ARM, RISC-V CPUs and NVIDIA, AMD GPUs.
|
|
551
553
|
|
|
552
554
|
The package provides:
|
|
553
555
|
|
|
554
|
-
- automatic
|
|
556
|
+
- automatic benchmarking for supported ISAs
|
|
555
557
|
- arithmetic, memory, and roofline benchmark modes
|
|
556
|
-
- CLI output in table, JSON, CSV, and plot formats
|
|
557
558
|
- optional web GUI for interactive result visualization
|
|
558
559
|
|
|
560
|
+
> [!WARNING]
|
|
561
|
+
> 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.
|
|
562
|
+
|
|
559
563
|
## Installation
|
|
560
564
|
|
|
561
565
|
Install from PyPI:
|
|
562
566
|
|
|
563
567
|
```bash
|
|
568
|
+
# command-line interface only:
|
|
564
569
|
pip install carm-roofline
|
|
570
|
+
# with GUI extras:
|
|
571
|
+
pip install carm-roofline[gui]
|
|
572
|
+
# with all extras (GUI + development tools):
|
|
573
|
+
pip install carm-roofline[all]
|
|
565
574
|
```
|
|
566
575
|
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
```bash
|
|
570
|
-
pip install "carm-roofline[gui]"
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
Install all extras (GUI + development tools):
|
|
576
|
+
To avoid conflicts with other packages, we recommend installing in a virtual environment:
|
|
574
577
|
|
|
575
578
|
```bash
|
|
576
|
-
|
|
579
|
+
python -m venv carm-env
|
|
580
|
+
source carm-env/bin/activate
|
|
581
|
+
pip install carm-roofline[all]
|
|
577
582
|
```
|
|
578
583
|
|
|
579
584
|
## Requirements
|
|
580
585
|
|
|
581
|
-
- Python 3.
|
|
582
|
-
-
|
|
583
|
-
- GCC toolchain (for compiling benchmark binaries)
|
|
586
|
+
- Python 3.9+
|
|
587
|
+
- GCC (for compiling benchmark binaries)
|
|
584
588
|
|
|
585
589
|
## Command-Line Interface
|
|
586
590
|
|
|
@@ -594,7 +598,7 @@ Available subcommands:
|
|
|
594
598
|
|
|
595
599
|
- `benchmark` - run benchmark suites
|
|
596
600
|
- `gui` - launch the results dashboard
|
|
597
|
-
- `profile` -
|
|
601
|
+
- `profile` - coming soon
|
|
598
602
|
|
|
599
603
|
Show help:
|
|
600
604
|
|
|
@@ -627,12 +631,12 @@ carm benchmark --dry-run --test arithmetic --test-time 1 --verbose 4
|
|
|
627
631
|
|
|
628
632
|
## Output and Results
|
|
629
633
|
|
|
630
|
-
By default, results are written under `
|
|
634
|
+
By default, results are written under the platform user data directory for the `carm` app (via platformdirs). On linux, this is typically `~/.local/share/carm/`, on Windows, `%APPDATA%\carm\`, and on MacOS, `~/Library/Application Support/carm/`.
|
|
631
635
|
|
|
632
636
|
Control output directory and format(s):
|
|
633
637
|
|
|
634
638
|
```bash
|
|
635
|
-
carm benchmark --output-dir carm_results --output-fmt table json csv plot
|
|
639
|
+
carm benchmark --output-dir ./carm_results --output-fmt table json csv plot
|
|
636
640
|
```
|
|
637
641
|
|
|
638
642
|
Use `--name` to label result files:
|
|
@@ -652,12 +656,12 @@ carm gui
|
|
|
652
656
|
Custom results location and port:
|
|
653
657
|
|
|
654
658
|
```bash
|
|
655
|
-
carm gui --results-dir carm_results --gui-port 8050
|
|
659
|
+
carm gui --results-dir ./carm_results --gui-port 8050
|
|
656
660
|
```
|
|
657
661
|
|
|
658
662
|
## Publications and Citation
|
|
659
663
|
|
|
660
|
-
If you use CARM in papers or reports, please cite:
|
|
664
|
+
If you use the CARM and the CARM Tool in papers or reports, please cite:
|
|
661
665
|
|
|
662
666
|
<p>
|
|
663
667
|
<a href="https://doi.org/10.1109/L-CA.2013.6" alt="Publication">
|
|
@@ -1,40 +1,43 @@
|
|
|
1
1
|
|
|
2
|
-
# CARM
|
|
2
|
+
# The CARM Tool
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
|
|
5
|
+
Cache-Aware Roofline Model (CARM) toolkit - benchmark, visualize and profile Intel, AMD, ARM, RISC-V CPUs and NVIDIA, AMD GPUs.
|
|
5
6
|
|
|
6
7
|
The package provides:
|
|
7
8
|
|
|
8
|
-
- automatic
|
|
9
|
+
- automatic benchmarking for supported ISAs
|
|
9
10
|
- arithmetic, memory, and roofline benchmark modes
|
|
10
|
-
- CLI output in table, JSON, CSV, and plot formats
|
|
11
11
|
- optional web GUI for interactive result visualization
|
|
12
12
|
|
|
13
|
+
> [!WARNING]
|
|
14
|
+
> 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
|
+
|
|
13
16
|
## Installation
|
|
14
17
|
|
|
15
18
|
Install from PyPI:
|
|
16
19
|
|
|
17
20
|
```bash
|
|
21
|
+
# command-line interface only:
|
|
18
22
|
pip install carm-roofline
|
|
23
|
+
# with GUI extras:
|
|
24
|
+
pip install carm-roofline[gui]
|
|
25
|
+
# with all extras (GUI + development tools):
|
|
26
|
+
pip install carm-roofline[all]
|
|
19
27
|
```
|
|
20
28
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
pip install "carm-roofline[gui]"
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Install all extras (GUI + development tools):
|
|
29
|
+
To avoid conflicts with other packages, we recommend installing in a virtual environment:
|
|
28
30
|
|
|
29
31
|
```bash
|
|
30
|
-
|
|
32
|
+
python -m venv carm-env
|
|
33
|
+
source carm-env/bin/activate
|
|
34
|
+
pip install carm-roofline[all]
|
|
31
35
|
```
|
|
32
36
|
|
|
33
37
|
## Requirements
|
|
34
38
|
|
|
35
|
-
- Python 3.
|
|
36
|
-
-
|
|
37
|
-
- GCC toolchain (for compiling benchmark binaries)
|
|
39
|
+
- Python 3.9+
|
|
40
|
+
- GCC (for compiling benchmark binaries)
|
|
38
41
|
|
|
39
42
|
## Command-Line Interface
|
|
40
43
|
|
|
@@ -48,7 +51,7 @@ Available subcommands:
|
|
|
48
51
|
|
|
49
52
|
- `benchmark` - run benchmark suites
|
|
50
53
|
- `gui` - launch the results dashboard
|
|
51
|
-
- `profile` -
|
|
54
|
+
- `profile` - coming soon
|
|
52
55
|
|
|
53
56
|
Show help:
|
|
54
57
|
|
|
@@ -81,12 +84,12 @@ carm benchmark --dry-run --test arithmetic --test-time 1 --verbose 4
|
|
|
81
84
|
|
|
82
85
|
## Output and Results
|
|
83
86
|
|
|
84
|
-
By default, results are written under `
|
|
87
|
+
By default, results are written under the platform user data directory for the `carm` app (via platformdirs). On linux, this is typically `~/.local/share/carm/`, on Windows, `%APPDATA%\carm\`, and on MacOS, `~/Library/Application Support/carm/`.
|
|
85
88
|
|
|
86
89
|
Control output directory and format(s):
|
|
87
90
|
|
|
88
91
|
```bash
|
|
89
|
-
carm benchmark --output-dir carm_results --output-fmt table json csv plot
|
|
92
|
+
carm benchmark --output-dir ./carm_results --output-fmt table json csv plot
|
|
90
93
|
```
|
|
91
94
|
|
|
92
95
|
Use `--name` to label result files:
|
|
@@ -106,12 +109,12 @@ carm gui
|
|
|
106
109
|
Custom results location and port:
|
|
107
110
|
|
|
108
111
|
```bash
|
|
109
|
-
carm gui --results-dir carm_results --gui-port 8050
|
|
112
|
+
carm gui --results-dir ./carm_results --gui-port 8050
|
|
110
113
|
```
|
|
111
114
|
|
|
112
115
|
## Publications and Citation
|
|
113
116
|
|
|
114
|
-
If you use CARM in papers or reports, please cite:
|
|
117
|
+
If you use the CARM and the CARM Tool in papers or reports, please cite:
|
|
115
118
|
|
|
116
119
|
<p>
|
|
117
120
|
<a href="https://doi.org/10.1109/L-CA.2013.6" alt="Publication">
|
|
@@ -102,7 +102,7 @@ class Benchmarking(InsertsArguments):
|
|
|
102
102
|
self.data_type: DataType = args.data_type
|
|
103
103
|
self.threads: int = args.threads
|
|
104
104
|
self.interleaved: bool = args.interleaved
|
|
105
|
-
self.
|
|
105
|
+
self.instructions: set[ArithmeticOperation] = set(args.instruction)
|
|
106
106
|
self.num_ops: Operations = Operations(args.num_ops)
|
|
107
107
|
self.ld_st_ratio: LoadStoreRatio = args.ld_st_ratio
|
|
108
108
|
self.arith_mem_ratio: int = args.arith_mem_ratio
|
|
@@ -163,10 +163,10 @@ class Benchmarking(InsertsArguments):
|
|
|
163
163
|
)
|
|
164
164
|
parser.add_argument(
|
|
165
165
|
"--instruction",
|
|
166
|
-
default=ArithmeticOperation.fma,
|
|
167
|
-
nargs="
|
|
166
|
+
default=[ArithmeticOperation.add, ArithmeticOperation.fma],
|
|
167
|
+
nargs="+",
|
|
168
168
|
action=enum_action(ArithmeticOperation),
|
|
169
|
-
help="Arithmetic instruction
|
|
169
|
+
help="Arithmetic instruction(s) to benchmark (Default: add fma)",
|
|
170
170
|
)
|
|
171
171
|
parser.add_argument(
|
|
172
172
|
"--ld-st-ratio",
|
|
@@ -29,26 +29,19 @@ def _collect_gops_by_isa(isa_suites: dict[str, ISABenchmarkSuite]) -> dict[str,
|
|
|
29
29
|
gops_by_isa: dict[str, float] = {}
|
|
30
30
|
|
|
31
31
|
for isa, suite in sorted(isa_suites.items(), key=lambda kv: kv[0]):
|
|
32
|
-
benches: dict[str, Any]
|
|
33
|
-
if hasattr(suite, "get_arithmetic_benchmarks"):
|
|
34
|
-
benches = suite.get_arithmetic_benchmarks()
|
|
35
|
-
else:
|
|
36
|
-
benches = getattr(suite, "benchmarks", {})
|
|
37
|
-
|
|
38
32
|
values: list[float] = []
|
|
39
|
-
for bench in
|
|
40
|
-
|
|
41
|
-
if not isinstance(res, ArithmeticBenchmarkResult):
|
|
33
|
+
for bench in suite.get_arithmetic_benchmarks().values():
|
|
34
|
+
if not isinstance(bench.results, ArithmeticBenchmarkResult):
|
|
42
35
|
continue
|
|
43
36
|
|
|
44
|
-
gops_value = float(
|
|
37
|
+
gops_value = float(bench.results.performance.value) / 1e9
|
|
45
38
|
if not math.isfinite(gops_value):
|
|
46
39
|
warn(f"Skipping invalid GOPS value for ISA {isa}: {gops_value}")
|
|
47
40
|
continue
|
|
48
41
|
values.append(gops_value)
|
|
49
42
|
|
|
50
43
|
if values:
|
|
51
|
-
gops_by_isa[isa] =
|
|
44
|
+
gops_by_isa[isa] = max(values)
|
|
52
45
|
|
|
53
46
|
return gops_by_isa
|
|
54
47
|
|
|
@@ -64,47 +57,53 @@ def _print_table(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite])
|
|
|
64
57
|
isa_cls.name: isa_cls.from_architecture(context.architecture) for isa_cls in context.architecture.isa
|
|
65
58
|
}
|
|
66
59
|
|
|
67
|
-
arithmetic_metrics:
|
|
60
|
+
arithmetic_metrics: list[dict[str, Any]] = []
|
|
68
61
|
|
|
69
62
|
for isa, suite in sorted(isa_suites.items(), key=lambda kv: kv[0]):
|
|
70
63
|
frequency = context.architecture.get_frequency_for_isa(isa)
|
|
71
|
-
benches = suite.get_arithmetic_benchmarks()
|
|
72
|
-
assert len(benches) == 1, "Expected exactly one arithmetic benchmark per ISA for summary output"
|
|
73
|
-
benchmark_name, benchmark = next(iter(benches.items()))
|
|
74
|
-
res = benchmark.results
|
|
75
|
-
assert isinstance(res, ArithmeticBenchmarkResult), "Expected ArithmeticBenchmarkResult for arithmetic summary"
|
|
76
|
-
|
|
77
64
|
isa_instance = isa_instances.get(isa)
|
|
78
65
|
if isa_instance is None:
|
|
79
66
|
warn(f"No ISA instance available for {isa}; skipping metrics")
|
|
80
67
|
continue
|
|
81
68
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
69
|
+
benches = suite.get_arithmetic_benchmarks()
|
|
70
|
+
for benchmark_name, benchmark in benches.items():
|
|
71
|
+
res = benchmark.results
|
|
72
|
+
assert isinstance(res, ArithmeticBenchmarkResult), (
|
|
73
|
+
"Expected ArithmeticBenchmarkResult for arithmetic summary"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
ops_per_inst = isa_instance.ops_per_inst(benchmark.params.data_type, benchmark.params.operation)
|
|
77
|
+
total_insts = (benchmark.params.num_ops.value // ops_per_inst) * res.num_repetitions if ops_per_inst else 0
|
|
78
|
+
cycles = Cycles.from_time_and_frequency(res.time_taken, frequency)
|
|
79
|
+
ipc = 0.0 if cycles.value == 0 else total_insts / cycles.value
|
|
80
|
+
ops_per_cycle = ops_per_inst * ipc
|
|
81
|
+
|
|
82
|
+
arithmetic_metrics.append(
|
|
83
|
+
{
|
|
84
|
+
"isa": isa,
|
|
85
|
+
"operation": benchmark.params.operation.name,
|
|
86
|
+
"benchmark": benchmark_name,
|
|
87
|
+
"gops": float(res.performance.value) / 1e9,
|
|
88
|
+
"gops_display": str(res.performance),
|
|
89
|
+
"ipc": ipc,
|
|
90
|
+
"frequency_hz": float(frequency.value),
|
|
91
|
+
"frequency_display": str(frequency),
|
|
92
|
+
"ops_per_instruction": ops_per_inst,
|
|
93
|
+
"ops_per_cycle": ops_per_cycle,
|
|
94
|
+
"time_seconds": float(res.time_taken.value),
|
|
95
|
+
"time_display": str(res.time_taken),
|
|
96
|
+
"repetitions": int(res.num_repetitions),
|
|
97
|
+
"cycles": float(cycles.value),
|
|
98
|
+
"cycles_display": str(cycles),
|
|
99
|
+
}
|
|
100
|
+
)
|
|
103
101
|
|
|
104
102
|
table = Table(title="Arithmetic Performance Summary")
|
|
105
103
|
|
|
106
104
|
# normal output columns
|
|
107
105
|
table.add_column("ISA", style="cyan")
|
|
106
|
+
table.add_column("Op", style="magenta")
|
|
108
107
|
table.add_column("GOPS", justify="right")
|
|
109
108
|
table.add_column("IPC", justify="right")
|
|
110
109
|
table.add_column("Frequency", justify="right")
|
|
@@ -116,7 +115,8 @@ def _print_table(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite])
|
|
|
116
115
|
table.add_column("Repetitions", justify="right")
|
|
117
116
|
table.add_column("Cycles", justify="right")
|
|
118
117
|
|
|
119
|
-
|
|
118
|
+
# sort rows by ISA and operation
|
|
119
|
+
for metrics in sorted(arithmetic_metrics, key=lambda row: (row["isa"], row["operation"])):
|
|
120
120
|
ipc = float(metrics["ipc"])
|
|
121
121
|
|
|
122
122
|
if print_extra:
|
|
@@ -130,7 +130,8 @@ def _print_table(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite])
|
|
|
130
130
|
extra_args = ()
|
|
131
131
|
|
|
132
132
|
table.add_row(
|
|
133
|
-
isa,
|
|
133
|
+
metrics["isa"],
|
|
134
|
+
metrics["operation"],
|
|
134
135
|
str(metrics["gops_display"]),
|
|
135
136
|
f"{ipc:.2f}",
|
|
136
137
|
str(metrics["frequency_display"]),
|
|
@@ -152,34 +153,36 @@ def _write_json(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite])
|
|
|
152
153
|
|
|
153
154
|
for isa, suite in sorted(isa_suites.items(), key=lambda kv: kv[0]):
|
|
154
155
|
frequency = context.architecture.get_frequency_for_isa(isa)
|
|
155
|
-
benches = suite.get_arithmetic_benchmarks()
|
|
156
|
-
assert len(benches) == 1, "Expected exactly one arithmetic benchmark per ISA for JSON output"
|
|
157
|
-
benchmark_name, benchmark = next(iter(benches.items()))
|
|
158
|
-
res = benchmark.results
|
|
159
|
-
assert isinstance(res, ArithmeticBenchmarkResult), "Expected ArithmeticBenchmarkResult for arithmetic JSON"
|
|
160
|
-
|
|
161
156
|
isa_instance = isa_instances.get(isa)
|
|
162
157
|
if isa_instance is None:
|
|
163
158
|
warn(f"No ISA instance available for {isa}; skipping metrics")
|
|
164
159
|
continue
|
|
165
160
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
161
|
+
benches = suite.get_arithmetic_benchmarks()
|
|
162
|
+
isa_results: dict[str, object] = {}
|
|
163
|
+
for benchmark_name, benchmark in benches.items():
|
|
164
|
+
res = benchmark.results
|
|
165
|
+
assert isinstance(res, ArithmeticBenchmarkResult), "Expected ArithmeticBenchmarkResult for arithmetic JSON"
|
|
166
|
+
|
|
167
|
+
ops_per_inst = isa_instance.ops_per_inst(benchmark.params.data_type, benchmark.params.operation)
|
|
168
|
+
total_insts = (benchmark.params.num_ops.value // ops_per_inst) * res.num_repetitions if ops_per_inst else 0
|
|
169
|
+
cycles = Cycles.from_time_and_frequency(res.time_taken, frequency)
|
|
170
|
+
ipc = 0.0 if cycles.value == 0 else total_insts / cycles.value
|
|
171
|
+
|
|
172
|
+
isa_results[benchmark.params.operation.name] = {
|
|
173
|
+
"benchmark": benchmark_name,
|
|
174
|
+
"operation": benchmark.params.operation.name,
|
|
175
|
+
"gops": float(res.performance.value) / 1e9,
|
|
176
|
+
"ipc": ipc,
|
|
177
|
+
"frequency_hz": float(frequency.value),
|
|
178
|
+
"ops_per_instruction": ops_per_inst,
|
|
179
|
+
"ops_per_cycle": ops_per_inst * ipc,
|
|
180
|
+
"time_seconds": float(res.time_taken.value),
|
|
181
|
+
"repetitions": int(res.num_repetitions),
|
|
182
|
+
"cycles": float(cycles.value),
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
results[isa] = isa_results
|
|
183
186
|
|
|
184
187
|
out_dir = context.run_config.output_dir / "arithmetic"
|
|
185
188
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -8,6 +8,7 @@ from datetime import datetime
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from typing import TYPE_CHECKING
|
|
10
10
|
|
|
11
|
+
from benchmark.generation.code_gen.operation import ArithmeticOperation
|
|
11
12
|
from output_utils import info, warn
|
|
12
13
|
from units import Cycles
|
|
13
14
|
|
|
@@ -167,7 +168,12 @@ def _collect_memory_metrics(
|
|
|
167
168
|
return bandwidth_by_level, ipc_by_level
|
|
168
169
|
|
|
169
170
|
|
|
170
|
-
def _collect_fp_metrics(
|
|
171
|
+
def _collect_fp_metrics(
|
|
172
|
+
context: CARMContext,
|
|
173
|
+
suite: ISABenchmarkSuite,
|
|
174
|
+
isa_name: str,
|
|
175
|
+
operation: ArithmeticOperation | None = None,
|
|
176
|
+
) -> tuple[float, float]:
|
|
171
177
|
frequency = context.architecture.get_frequency_for_isa(isa_name)
|
|
172
178
|
fp_gflops = 0.0
|
|
173
179
|
fp_ipc = 0.0
|
|
@@ -179,6 +185,8 @@ def _collect_fp_metrics(context: CARMContext, suite: ISABenchmarkSuite, isa_name
|
|
|
179
185
|
for bench in suite.get_arithmetic_benchmarks().values():
|
|
180
186
|
if bench.results is None:
|
|
181
187
|
continue
|
|
188
|
+
if operation is not None and bench.params.operation != operation:
|
|
189
|
+
continue
|
|
182
190
|
fp_gflops = float(bench.results.performance.value) / 1e9
|
|
183
191
|
ops_per_inst = isa_instance.ops_per_inst(bench.params.data_type, bench.params.operation)
|
|
184
192
|
total_insts = (
|
|
@@ -214,8 +222,19 @@ def _write_csv(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite], o
|
|
|
214
222
|
|
|
215
223
|
bandwidth_by_level, icycle_by_level = _collect_memory_metrics(context, suite, isa)
|
|
216
224
|
|
|
217
|
-
|
|
218
|
-
|
|
225
|
+
# Select primary instruction: prefer non-fma if available, else fall back to fma
|
|
226
|
+
primary_instruction = next(
|
|
227
|
+
(op for op in context.benchmarking.instructions if op != ArithmeticOperation.fma),
|
|
228
|
+
ArithmeticOperation.fma,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
fp_inst = primary_instruction.name
|
|
232
|
+
fp_gflops, fp_icycle = _collect_fp_metrics(context, suite, isa, operation=primary_instruction)
|
|
233
|
+
|
|
234
|
+
fma_gflops = 0.0
|
|
235
|
+
fma_icycle = 0.0
|
|
236
|
+
if ArithmeticOperation.fma in context.benchmarking.instructions:
|
|
237
|
+
fma_gflops, fma_icycle = _collect_fp_metrics(context, suite, isa, operation=ArithmeticOperation.fma)
|
|
219
238
|
|
|
220
239
|
def round_helper(x: float) -> str:
|
|
221
240
|
return f"{x:.3g}" if x < 1 else f"{x:.3f}"
|
|
@@ -240,8 +259,8 @@ def _write_csv(context: CARMContext, isa_suites: dict[str, ISABenchmarkSuite], o
|
|
|
240
259
|
round_helper(icycle_by_level["DRAM"]),
|
|
241
260
|
round_helper(fp_gflops),
|
|
242
261
|
round_helper(fp_icycle),
|
|
243
|
-
|
|
244
|
-
|
|
262
|
+
round_helper(fma_gflops),
|
|
263
|
+
round_helper(fma_icycle),
|
|
245
264
|
]
|
|
246
265
|
|
|
247
266
|
secondary_headers = [
|
|
@@ -5,8 +5,6 @@ from __future__ import annotations
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
from units import Performance
|
|
9
|
-
|
|
10
8
|
from ..benchmark import ArithmeticBenchmark
|
|
11
9
|
from ..generation import ArithmeticBenchmarkParams
|
|
12
10
|
from .base import ISABenchmarkSuite
|
|
@@ -19,7 +17,7 @@ if TYPE_CHECKING:
|
|
|
19
17
|
class ArithmeticBenchmarkSuite(ISABenchmarkSuite):
|
|
20
18
|
"""Suite for arithmetic-only benchmarks (TestType.ARITHMETIC).
|
|
21
19
|
|
|
22
|
-
Measures peak arithmetic performance
|
|
20
|
+
Measures peak arithmetic performance across one or more operations.
|
|
23
21
|
"""
|
|
24
22
|
|
|
25
23
|
@classmethod
|
|
@@ -61,29 +59,17 @@ class ArithmeticBenchmarkSuite(ISABenchmarkSuite):
|
|
|
61
59
|
# This also helps us deal with SMT, ensuring threads are properly distributed across cores
|
|
62
60
|
thread_affinity = architecture.memory_topology.plan_thread_affinity(benchmark.threads, 1)
|
|
63
61
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
62
|
+
for operation in benchmark.instructions:
|
|
63
|
+
params = ArithmeticBenchmarkParams(
|
|
64
|
+
data_type=benchmark.data_type,
|
|
65
|
+
thread_affinity=thread_affinity.cpu_ids,
|
|
66
|
+
operation=operation,
|
|
67
|
+
num_ops=benchmark.num_ops,
|
|
68
|
+
)
|
|
69
|
+
spec = isa.generate_arithmetic(params, context)
|
|
72
70
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
# Add to ISA suite using the benchmark's authoritative name
|
|
72
|
+
arith_benchmark = ArithmeticBenchmark(params=params, spec=spec)
|
|
73
|
+
suite.add_benchmark(arith_benchmark.name, arith_benchmark)
|
|
76
74
|
|
|
77
75
|
return suite
|
|
78
|
-
|
|
79
|
-
def get_peak_performance(self) -> Performance:
|
|
80
|
-
"""Get peak GOPS from arithmetic portion of roofline suite.
|
|
81
|
-
|
|
82
|
-
Returns:
|
|
83
|
-
Peak GOPS from arithmetic benchmarks, or None if unavailable.
|
|
84
|
-
"""
|
|
85
|
-
arith_benchmarks = self.get_arithmetic_benchmarks()
|
|
86
|
-
if len(arith_benchmarks) > 1:
|
|
87
|
-
raise ValueError("Expected exactly one arithmetic benchmark for peak performance calculation")
|
|
88
|
-
|
|
89
|
-
return super().get_peak_performance()
|
|
@@ -16,7 +16,7 @@ from output_utils import debug
|
|
|
16
16
|
from units import Bandwidth, Bytes
|
|
17
17
|
|
|
18
18
|
from ..benchmark import MemoryBenchmark
|
|
19
|
-
from ..generation import MemoryBenchmarkParams
|
|
19
|
+
from ..generation import MemoryBenchmarkParams, MemoryLayoutMode
|
|
20
20
|
from .base import ISABenchmarkSuite
|
|
21
21
|
|
|
22
22
|
if TYPE_CHECKING:
|
|
@@ -92,8 +92,7 @@ class MemorySweepBenchmarkSuite(ISABenchmarkSuite):
|
|
|
92
92
|
(level_num, level_info.name)
|
|
93
93
|
for level_num, level_info in zip(
|
|
94
94
|
topology.available_cache_levels(),
|
|
95
|
-
topology,
|
|
96
|
-
strict=True,
|
|
95
|
+
iter(topology),
|
|
97
96
|
)
|
|
98
97
|
]
|
|
99
98
|
|
|
@@ -159,13 +158,15 @@ class MemorySweepBenchmarkSuite(ISABenchmarkSuite):
|
|
|
159
158
|
size_per_thread = Bytes(int(size_bytes))
|
|
160
159
|
|
|
161
160
|
# Classify: find the smallest cache level whose per-thread capacity
|
|
162
|
-
# is
|
|
161
|
+
# is >= the sweep size. Fall back to DRAM label if none matches.
|
|
163
162
|
assigned_level_name: str = dram_level_name
|
|
164
163
|
assigned_affinity: CacheAwareThreadAffinity = dram_affinity
|
|
165
164
|
for _lvl_num, lvl_name, avail, aff in cache_levels_for_classification:
|
|
166
165
|
if size_per_thread <= avail:
|
|
167
166
|
assigned_level_name = lvl_name
|
|
168
167
|
assigned_affinity = aff
|
|
168
|
+
# L1 can suffer from 4k aliasing - use single-array layout to prevent speculative forwarding issues
|
|
169
|
+
mem_layout = MemoryLayoutMode.single if _lvl_num == 1 else MemoryLayoutMode.split
|
|
169
170
|
break
|
|
170
171
|
|
|
171
172
|
# Use sweep{i:02d} as memory_level_name to guarantee unique C
|
|
@@ -178,6 +179,7 @@ class MemorySweepBenchmarkSuite(ISABenchmarkSuite):
|
|
|
178
179
|
load_store_ratio=benchmark.ld_st_ratio,
|
|
179
180
|
size_per_thread=size_per_thread,
|
|
180
181
|
memory_level_name=sweep_label,
|
|
182
|
+
layout_mode=mem_layout,
|
|
181
183
|
)
|
|
182
184
|
|
|
183
185
|
bench_spec = isa.generate_memory(params, context)
|
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from dataclasses import dataclass
|
|
6
6
|
from typing import TYPE_CHECKING
|
|
7
7
|
|
|
8
|
-
from units import ArithmeticIntensity, Bandwidth
|
|
8
|
+
from units import ArithmeticIntensity, Bandwidth
|
|
9
9
|
|
|
10
10
|
from .arithmetic import ArithmeticBenchmarkSuite
|
|
11
11
|
from .base import ISABenchmarkSuite
|
|
@@ -53,22 +53,6 @@ class RooflineBenchmarkSuite(ISABenchmarkSuite):
|
|
|
53
53
|
|
|
54
54
|
return suite
|
|
55
55
|
|
|
56
|
-
def get_peak_performance(self) -> Performance:
|
|
57
|
-
"""Get peak GOPS from arithmetic portion of roofline suite.
|
|
58
|
-
|
|
59
|
-
Returns:
|
|
60
|
-
Peak GOPS from arithmetic benchmarks, or None if unavailable.
|
|
61
|
-
"""
|
|
62
|
-
arith_benchmarks = self.get_arithmetic_benchmarks()
|
|
63
|
-
if len(arith_benchmarks) > 1:
|
|
64
|
-
raise ValueError("Expected exactly one arithmetic benchmark for peak performance calculation")
|
|
65
|
-
|
|
66
|
-
arith_benchmark = next(iter(arith_benchmarks.values()))
|
|
67
|
-
if arith_benchmark.results is None:
|
|
68
|
-
raise ValueError("Arithmetic benchmark missing performance result for roofline benchmarking")
|
|
69
|
-
|
|
70
|
-
return arith_benchmark.results.performance
|
|
71
|
-
|
|
72
56
|
def get_bandwidth_by_level(self) -> dict[str, Bandwidth]:
|
|
73
57
|
"""Get peak bandwidth for each cache level from memory benchmarks.
|
|
74
58
|
|