Skip to content

Commit 1463485

Browse files
author
Subbarao Garlapati
committed
Make benchmarks easy to use in OSS
- Add __init__.py to make cinderx.benchmarks importable as a package - Add __main__.py unified runner (python -m cinderx.benchmarks) - Add symlink from PythonLib/cinderx/benchmarks -> ../../benchmarks - Fix fastmark.py to find pyperformance via import instead of filesystem - Add requirements-fastmark.txt and requirements-torchrec.txt - Add comprehensive README with lightweight/heavyweight/JIT categories - Add --iterations flag for configurable iteration count - Update compile_time.py docstring with OSS usage
1 parent 95846d0 commit 1463485

8 files changed

Lines changed: 312 additions & 4 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../../benchmarks

cinderx/benchmarks/README.md

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# CinderX Benchmarks
2+
3+
Benchmarks for measuring CinderX JIT performance on real-world Python workloads.
4+
5+
## Quick Start
6+
7+
```bash
8+
pip install cinderx
9+
python -m cinderx.benchmarks
10+
python -m cinderx.benchmarks --iterations 10
11+
```
12+
13+
This runs all benchmarks whose dependencies are available, skipping the rest with
14+
a helpful message about what to install. Lightweight benchmarks run with 3 iterations
15+
by default — use `--iterations N` for more:
16+
17+
## Lightweight Benchmarks
18+
19+
These benchmarks have no extra dependencies beyond cinderx itself:
20+
21+
```bash
22+
python -m cinderx.benchmarks.binary_trees 5
23+
python -m cinderx.benchmarks.fannkuch 3
24+
python -m cinderx.benchmarks.nbody 3
25+
python -m cinderx.benchmarks.richards 3
26+
python -m cinderx.benchmarks.spectral_norm 3
27+
```
28+
29+
The numeric argument controls the number of iterations (higher = longer run).
30+
31+
## JIT Compilation Time Benchmark
32+
33+
Measures how long the JIT takes to compile functions (not runtime performance):
34+
35+
```bash
36+
python -m cinderx.benchmarks.compile_time
37+
```
38+
39+
For a per-phase breakdown, pass the `jit-time` flag:
40+
41+
```bash
42+
python -X jit-time='*' -m cinderx.benchmarks.compile_time
43+
```
44+
45+
## Heavyweight Benchmarks
46+
47+
These require additional dependencies to be installed.
48+
49+
### Full Suite (fastmark)
50+
51+
The `fastmark` benchmark runs the full pyperformance suite with CinderX:
52+
53+
```bash
54+
pip install -r cinderx/benchmarks/requirements-fastmark.txt
55+
python -m cinderx.benchmarks.fastmark --cinderx
56+
```
57+
58+
Options:
59+
- `--scale N` — work scale factor (default 100, lower = faster)
60+
- `--json output.json` — save results as JSON
61+
- `--cinderx` — enable the CinderX JIT
62+
- `benchmarks...` — run only specific benchmarks (e.g. `richards chaos`)
63+
64+
### TorchRec Benchmarks
65+
66+
PT2 compilation benchmarks for TorchRec models:
67+
68+
```bash
69+
pip install -r cinderx/benchmarks/requirements-torchrec.txt
70+
python cinderx/benchmarks/torchrec_pt2/run_with_cinderx.py
71+
```
72+
73+
See [torchrec_pt2/README.md](torchrec_pt2/README.md) for details.
74+
75+
## Running Without CinderX JIT
76+
77+
To get a baseline comparison without JIT compilation, disable it via environment variable:
78+
79+
```bash
80+
# With JIT (default)
81+
python -m cinderx.benchmarks
82+
83+
# Without JIT (baseline)
84+
CINDERJIT_DISABLE=1 python -m cinderx.benchmarks
85+
```
86+
87+
## Benchmark Descriptions
88+
89+
| Benchmark | Description |
90+
|-----------|-------------|
91+
| `binary_trees` | Allocation-heavy workload building and traversing complete binary trees |
92+
| `fannkuch` | Combinatorial puzzle exercising array permutations and reversals |
93+
| `nbody` | N-body gravitational simulation with tight floating-point loops |
94+
| `richards` | Operating system task scheduler simulation (object-oriented workload) |
95+
| `spectral_norm` | Numerical computation of the spectral norm of a matrix |
96+
| `compile_time` | Measures JIT compilation speed (not runtime performance) |
97+
| `fastmark` | Full pyperformance suite (~60 benchmarks) with CinderX integration |
98+
| `torchrec_pt2` | TorchRec model compilation benchmarks with PT2 |
99+
100+
## Listing Available Benchmarks
101+
102+
```bash
103+
python -m cinderx.benchmarks --list
104+
```

cinderx/benchmarks/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.

cinderx/benchmarks/__main__.py

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
3+
# pyre-ignore-all-errors
4+
5+
"""
6+
Unified benchmark runner for CinderX.
7+
8+
Usage:
9+
python -m cinderx.benchmarks # Run all available benchmarks
10+
python -m cinderx.benchmarks binary_trees # Run specific benchmark(s)
11+
python -m cinderx.benchmarks --list # List available benchmarks
12+
"""
13+
14+
import os
15+
import subprocess
16+
import sys
17+
18+
# Lightweight benchmarks that only require cinderx itself.
19+
LIGHTWEIGHT_BENCHMARKS = [
20+
"binary_trees",
21+
"fannkuch",
22+
"nbody",
23+
"richards",
24+
"spectral_norm",
25+
]
26+
27+
# JIT compilation time benchmarks (measure compilation speed, not runtime).
28+
JIT_COMPILATION_BENCHMARKS = [
29+
"compile_time",
30+
]
31+
32+
# Heavyweight benchmarks with extra dependencies.
33+
HEAVYWEIGHT_BENCHMARKS = {
34+
"fastmark": "requirements-fastmark.txt",
35+
"torchrec_pt2": "requirements-torchrec.txt",
36+
}
37+
38+
ALL_BENCHMARK_NAMES = (
39+
LIGHTWEIGHT_BENCHMARKS
40+
+ JIT_COMPILATION_BENCHMARKS
41+
+ list(HEAVYWEIGHT_BENCHMARKS.keys())
42+
)
43+
44+
45+
def run_benchmark(name, iterations):
46+
"""Run a single benchmark as a subprocess. Returns True on success."""
47+
benchmarks_dir = os.path.dirname(os.path.abspath(__file__))
48+
49+
if name in LIGHTWEIGHT_BENCHMARKS:
50+
script = os.path.join(benchmarks_dir, f"{name}.py")
51+
cmd = [sys.executable, script, str(iterations)]
52+
elif name == "compile_time":
53+
cmd = [sys.executable, "-m", "cinderx.benchmarks.compile_time"]
54+
elif name == "fastmark":
55+
script = os.path.join(benchmarks_dir, "fastmark.py")
56+
cmd = [sys.executable, script, "--cinderx", "--scale", "10"]
57+
elif name == "torchrec_pt2":
58+
script = os.path.join(benchmarks_dir, "torchrec_pt2", "run_with_cinderx.py")
59+
cmd = [sys.executable, script]
60+
else:
61+
print(f"Unknown benchmark: {name}", file=sys.stderr)
62+
return False
63+
64+
print(f"\n{'='*60}")
65+
print(f"Running: {name}")
66+
print(f"{'='*60}")
67+
68+
try:
69+
result = subprocess.run(cmd, check=False)
70+
if result.returncode != 0:
71+
return False
72+
except FileNotFoundError:
73+
print(f" Error: could not execute {cmd[0]}", file=sys.stderr)
74+
return False
75+
76+
return True
77+
78+
79+
def check_deps(name):
80+
"""Check if a benchmark's dependencies are available."""
81+
if name in LIGHTWEIGHT_BENCHMARKS or name in JIT_COMPILATION_BENCHMARKS:
82+
return True
83+
elif name == "fastmark":
84+
try:
85+
import importlib.util
86+
87+
return importlib.util.find_spec("pyperformance") is not None
88+
except ImportError:
89+
return False
90+
elif name == "torchrec_pt2":
91+
try:
92+
import importlib.util
93+
94+
return importlib.util.find_spec("torchrec") is not None
95+
except ImportError:
96+
return False
97+
return True
98+
99+
100+
def main():
101+
args = sys.argv[1:]
102+
103+
# Parse --iterations N
104+
iterations = 3
105+
if "--iterations" in args:
106+
idx = args.index("--iterations")
107+
try:
108+
iterations = int(args[idx + 1])
109+
args = args[:idx] + args[idx + 2:]
110+
except (IndexError, ValueError):
111+
print("Error: --iterations requires an integer argument", file=sys.stderr)
112+
sys.exit(1)
113+
114+
if "--list" in args or "-l" in args:
115+
print("Available benchmarks:")
116+
print()
117+
print("Lightweight (no extra dependencies):")
118+
for name in LIGHTWEIGHT_BENCHMARKS:
119+
print(f" {name}")
120+
print()
121+
print("JIT compilation time:")
122+
for name in JIT_COMPILATION_BENCHMARKS:
123+
print(f" {name}")
124+
print()
125+
print("Heavyweight (extra dependencies required):")
126+
for name, req in HEAVYWEIGHT_BENCHMARKS.items():
127+
print(f" {name} (pip install -r {req})")
128+
return
129+
130+
if "--help" in args or "-h" in args:
131+
print(__doc__)
132+
print("Options:")
133+
print(" --list, -l List available benchmarks")
134+
print(" --iterations N Number of iterations for lightweight benchmarks (default: 3)")
135+
print(" --help, -h Show this help message")
136+
print()
137+
print("Examples:")
138+
print(" python -m cinderx.benchmarks")
139+
print(" python -m cinderx.benchmarks binary_trees fannkuch")
140+
print(" python -m cinderx.benchmarks compile_time")
141+
return
142+
143+
benchmarks_to_run = args if args else ALL_BENCHMARK_NAMES
144+
145+
# Validate names
146+
for name in benchmarks_to_run:
147+
if name not in ALL_BENCHMARK_NAMES:
148+
print(f"Unknown benchmark: {name}", file=sys.stderr)
149+
print(f"Run 'python -m cinderx.benchmarks --list' to see available benchmarks")
150+
sys.exit(1)
151+
152+
passed = 0
153+
skipped = 0
154+
failed = 0
155+
156+
for name in benchmarks_to_run:
157+
if not check_deps(name):
158+
req_file = HEAVYWEIGHT_BENCHMARKS.get(name)
159+
print(f"\nSkipping {name} — missing dependencies.")
160+
if req_file:
161+
print(f" Install with: pip install -r cinderx/benchmarks/{req_file}")
162+
skipped += 1
163+
continue
164+
165+
success = run_benchmark(name, iterations)
166+
if success:
167+
passed += 1
168+
else:
169+
failed += 1
170+
171+
print(f"\n{'='*60}")
172+
print(f"Results: {passed} passed, {skipped} skipped, {failed} failed")
173+
print(f"{'='*60}")
174+
175+
if failed:
176+
sys.exit(1)
177+
178+
179+
if __name__ == "__main__":
180+
main()

cinderx/benchmarks/compile_time.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
aggregate timing statistics.
1212
1313
Usage:
14+
python -m cinderx.benchmarks.compile_time
1415
buck run //cinderx/benchmarks:compile-time
1516
1617
For a per-phase breakdown of each function's compilation, pass the jit-time
1718
flag via Python's -X option:
19+
python -X jit-time='*' -m cinderx.benchmarks.compile_time
1820
buck run //cinderx/benchmarks:compile-time -- -X jit-time='*'
1921
"""
2022

cinderx/benchmarks/fastmark.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,17 @@ def ADD_PATH(path):
3333
sys.path.append(os.path.join(os.path.dirname(__file__), path))
3434

3535

36-
PYPERFORMANCE = os.path.join(os.path.dirname(__file__), "pyperformance")
37-
38-
if not os.path.exists(PYPERFORMANCE):
36+
try:
37+
import pyperformance
38+
except ImportError:
3939
print(
40-
f"Error: pyperformance directory not found at {PYPERFORMANCE}", file=sys.stderr
40+
"Error: pyperformance not found. Install it with: pip install pyperformance==1.14.0",
41+
file=sys.stderr,
4142
)
4243
sys.exit(1)
4344

45+
PYPERFORMANCE = os.path.dirname(pyperformance.__file__)
46+
4447
BENCHMARKS = os.path.join(PYPERFORMANCE, "data-files", "benchmarks")
4548

4649
ADD_PATH(os.path.join(BENCHMARKS, "bm_regex_compile"))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pyperformance==1.14.0
2+
coverage
3+
docutils
4+
dulwich
5+
genshi
6+
html5lib
7+
mako
8+
pyaes
9+
sqlalchemy<2.0
10+
sqlglot
11+
sympy
12+
tomli
13+
websockets
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
torch>=2.0
2+
torchrec
3+
fbgemm-gpu
4+
click

0 commit comments

Comments
 (0)