counted-float 0.9.0__tar.gz → 0.9.2__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 (59) hide show
  1. {counted_float-0.9.0 → counted_float-0.9.2}/.gitignore +4 -1
  2. {counted_float-0.9.0 → counted_float-0.9.2}/PKG-INFO +92 -60
  3. {counted_float-0.9.0 → counted_float-0.9.2}/README.md +88 -59
  4. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/__init__.py +3 -1
  5. counted_float-0.9.2/counted_float/_core/_cli.py +23 -0
  6. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/benchmarking/__init__.py +1 -1
  7. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/benchmarking/_flops_benchmark_suite.py +4 -3
  8. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/benchmarking/_flops_micro_benchmark.py +1 -1
  9. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/benchmarking/_micro_benchmark.py +18 -6
  10. counted_float-0.9.2/counted_float/_core/benchmarking/_time_utils.py +1 -0
  11. counted_float-0.9.2/counted_float/_core/counting/_builtin_data.py +292 -0
  12. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/_context_managers.py +1 -1
  13. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/_counted_float.py +2 -1
  14. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/_global_counter.py +1 -1
  15. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/config/_config.py +2 -1
  16. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/config/_defaults.py +1 -2
  17. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/__init__.py +1 -1
  18. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_flop_weights.py +5 -0
  19. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_flops_benchmark_result.py +2 -8
  20. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_fpu_specs.py +1 -1
  21. counted_float-0.9.0/counted_float/_core/benchmarking/_models.py → counted_float-0.9.2/counted_float/_core/models/_micro_benchmark_result.py +11 -1
  22. counted_float-0.9.2/counted_float/_core/utils/__init__.py +5 -0
  23. counted_float-0.9.2/counted_float/_core/utils/_formatting.py +48 -0
  24. counted_float-0.9.2/counted_float/_core/utils/_latency.py +3 -0
  25. counted_float-0.9.2/counted_float/_core/utils/_timer.py +35 -0
  26. {counted_float-0.9.0 → counted_float-0.9.2}/pyproject.toml +7 -3
  27. counted_float-0.9.0/counted_float/_core/benchmarking/_time_utils.py +0 -70
  28. counted_float-0.9.0/counted_float/_core/counting/_builtin_data.py +0 -147
  29. counted_float-0.9.0/counted_float/_core/utils/__init__.py +0 -2
  30. {counted_float-0.9.0 → counted_float-0.9.2}/LICENSE +0 -0
  31. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/__init__.py +0 -0
  32. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/compatibility/__init__.py +0 -0
  33. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/compatibility/_numba.py +0 -0
  34. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/compatibility/_strenum.py +0 -0
  35. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/__init__.py +0 -0
  36. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/counting/config/__init__.py +0 -0
  37. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_base.py +0 -0
  38. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_flop_counts.py +0 -0
  39. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_flop_type.py +0 -0
  40. {counted_float-0.9.0/counted_float/_core/counting → counted_float-0.9.2/counted_float/_core}/models/_fpu_instruction.py +0 -0
  41. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/utils/_geo_mean.py +0 -0
  42. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/_core/utils/_missing_data.py +0 -0
  43. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/benchmarking/__init__.py +0 -0
  44. {counted_float-0.9.0 → counted_float-0.9.2}/counted_float/config/__init__.py +0 -0
  45. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/benchmarks/arm/apple/m3_max_macbook_pro_16.json +0 -0
  46. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/benchmarks/x86/intel/gen12_i7_1265u.json +0 -0
  47. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/benchmarks/x86/intel/gen7_i5_7200u.json +0 -0
  48. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/arm/arm_v7a_cortex_a9.json +0 -0
  49. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/arm/arm_v8_cortex_a55.json +0 -0
  50. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/arm/arm_v8_cortex_a76.json +0 -0
  51. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/arm/arm_v9_cortex_x1.json +0 -0
  52. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/arm/arm_v9_cortex_x2.json +0 -0
  53. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/arm/arm_v9_cortex_x3.json +0 -0
  54. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/x86/amd/zen3_r7_5800x.json +0 -0
  55. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/x86/amd/zen4_r9_7900x.json +0 -0
  56. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/x86/amd/zen5_r7_9800x3d.json +0 -0
  57. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/x86/intel/gen09_coffee_lake.json +0 -0
  58. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/x86/intel/gen10_cannon_lake.json +0 -0
  59. {counted_float-0.9.0/counted_float/_core → counted_float-0.9.2/counted_float}/data/specs/x86/intel/gen11_tiger_lake.json +0 -0
@@ -30,4 +30,7 @@ Thumbs.db
30
30
 
31
31
  # IDE files
32
32
  .idea
33
- .vscode
33
+ .vscode
34
+
35
+ # other local files
36
+ .local
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: counted-float
3
- Version: 0.9.0
3
+ Version: 0.9.2
4
4
  Summary: Count floating-point operations in Python code & benchmark relative flop costs.
5
5
  Project-URL: Source, https://github.com/bertpl/counted-float
6
6
  Project-URL: ChangeLog, https://github.com/bertpl/counted-float/blob/develop/RELEASE_NOTES.md
@@ -12,35 +12,32 @@ Requires-Dist: backports-strenum>=1.3.1
12
12
  Requires-Dist: numpy>=1.20
13
13
  Requires-Dist: psutil>=5.0
14
14
  Requires-Dist: pydantic>=2.0.0
15
+ Requires-Dist: rich>=13.0.0
16
+ Provides-Extra: cli
17
+ Requires-Dist: click>=8.0.0; extra == 'cli'
15
18
  Provides-Extra: numba
16
19
  Requires-Dist: numba>=0.50; extra == 'numba'
17
20
  Description-Content-Type: text/markdown
18
21
 
19
22
  <!--START_SECTION:images-->
20
23
  ![shields.io-python-versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)
21
- ![genbadge-test-count](https://bertpl.github.io/counted-float/version_artifacts/v0.9.0/badge-test-count.svg)
22
- ![genbadge-test-coverage](https://bertpl.github.io/counted-float/version_artifacts/v0.9.0/badge-coverage.svg)
23
- ![counted_float logo](https://bertpl.github.io/counted-float/version_artifacts/v0.9.0/splash.webp)
24
+ ![genbadge-test-count](https://bertpl.github.io/counted-float/version_artifacts/v0.9.2/badge-test-count.svg)
25
+ ![genbadge-test-coverage](https://bertpl.github.io/counted-float/version_artifacts/v0.9.2/badge-coverage.svg)
26
+ ![counted_float logo](https://bertpl.github.io/counted-float/version_artifacts/v0.9.2/splash.webp)
24
27
  <!--END_SECTION:images-->
25
28
 
26
29
  # counted-float
27
30
 
28
- This Python package provides functionality for counting the number of floating point operations (FLOPs) of numerical
29
- algorithms implemented in plain Python.
31
+ This Python package provides functionality for...
32
+ - **counting floating point operations** (FLOPs) of numerical algorithms implemented in plain Python, optionally weighted by their relative cost of execution
33
+ - **running benchmarks** to estimate the relative cost of executing various floating-point operations (requires `numba` optional dependency for achieving accurate results)
30
34
 
31
- The target application area are research prototypes of numerical algorithms where (weighted) flop counting can be
35
+ The target application area is evaluation of research prototypes of numerical algorithms where (weighted) flop counting can be
32
36
  useful for estimating total computational cost, in cases where benchmarking a compiled version (C, Rust, ...) is not
33
37
  feasible or desirable.
34
38
 
35
- The package contains two components:
36
- - `counting`: provides a CountedFloat class & flop counting context managers to count flops of code blocks.
37
- - `benchmarking`: provides functionality to micro-benchmark floating point operations to get an empirical
38
- ballpark estimate of the relative cost of different operations on the target hardware. Requires 'numba' optional dependency for accurate results.
39
-
40
39
  # 1. Installation
41
40
 
42
-
43
-
44
41
  Use you favorite package manager such as `uv` or `pip`:
45
42
 
46
43
  ```
@@ -50,6 +47,8 @@ pip install counted-float[numba] # install with numba optional dependency
50
47
  Numba is optional due to its relatively large size (40-50MB, including llvmlite), but without it, benchmarks will
51
48
  not be reliable (but will still run, but not in jit-compiled form).
52
49
 
50
+ NOTE: the `cli` optional dependency is only useful when installing the code as a tool using e.g. `uv` or `pipx` (see below)
51
+
53
52
  # 2. Counting Flops
54
53
 
55
54
  ## 2.1. CountedFloat class
@@ -275,72 +274,105 @@ The 3 built-in *default* flop weights are simply presets for the `key_filter` ar
275
274
 
276
275
  # 3. Benchmarking
277
276
 
278
- ## 3.1. General
279
-
280
- If the package is installed with the optional `numba` dependency, it provides
281
- the ability to micro-benchmark floating point operations as follows:
277
+ If the package is installed with the optional `numba` dependency, it provides the ability to micro-benchmark
278
+ floating point operations as follows:
282
279
 
283
280
  ```
284
281
  >>> from counted_float.benchmarking import run_flops_benchmark
285
282
  >>> results = run_flops_benchmark()
286
283
 
287
- Running FLOPS benchmarks using counted-float 0.9.0 ...
288
-
289
- baseline : wwwwwwwwww.................... 187.97 ns ± 0.52 ns / 1000 flops
290
- FlopType.ABS [abs(x)] : wwwwwwwwww.................... 307.23 ns ± 8.37 ns / 1000 flops
291
- FlopType.CMP_ZERO [x>=0] : wwwwwwwwww.................... 301.36 ns ± 7.22 ns / 1000 flops
292
- FlopType.RND [round(x)] : wwwwwwwwww.................... 302.96 ns ± 8.39 ns / 1000 flops
293
- FlopType.MINUS [-x] : wwwwwwwwww.................... 304.00 ns ± 7.99 ns / 1000 flops
294
- FlopType.EQUALS [x==y] : wwwwwwwwww.................... 319.64 ns ± 6.71 ns / 1000 flops
295
- FlopType.GTE [x>=y] : wwwwwwwwww.................... 325.35 ns ± 9.26 ns / 1000 flops
296
- FlopType.LTE [x<=y] : wwwwwwwwww.................... 323.17 ns ± 11.45 ns / 1000 flops
297
- FlopType.ADD [x+y] : wwwwwwwwww.................... 316.96 ns ± 11.11 ns / 1000 flops
298
- FlopType.SUB [x-y] : wwwwwwwwww.................... 318.59 ns ± 9.36 ns / 1000 flops
299
- FlopType.MUL [x*y] : wwwwwwwwww.................... 318.11 ns ± 7.16 ns / 1000 flops
300
- FlopType.SQRT [sqrt(x)] : wwwwwwwwww.................... 449.06 ns ± 2.42 ns / 1000 flops
301
- FlopType.DIV [x/y] : wwwwwwwwww.................... 483.70 ns ± 2.00 ns / 1000 flops
302
- FlopType.POW2 [2^x] : wwwwwwwwww.................... 1.77 µs ± 0.00 µs / 1000 flops
303
- FlopType.LOG2 [log2(x)] : wwwwwwwwww.................... 2.13 µs ± 0.01 µs / 1000 flops
304
- FlopType.POW [x^y] : wwwwwwwwww.................... 6.53 µs ± 0.00 µs / 1000 flops
305
-
284
+ Running FLOPS benchmarks using counted-float 0.9.2 ...
285
+
286
+ baseline : wwwwwwwwww.................... ( 187.03 ns = 759 cpu cycles) ± 0.6% / 1000 iterations
287
+ FlopType.ABS [abs(x)] : wwwwwwwwww.................... ( 303.31 ns = 1.23K cpu cycles) ± 1.7% / 1000 iterations
288
+ FlopType.CMP_ZERO [x>=0] : wwwwwwwwww.................... ( 302.19 ns = 1.23K cpu cycles) ± 3.0% / 1000 iterations
289
+ FlopType.RND [round(x)] : wwwwwwwwww.................... ( 305.95 ns = 1.24K cpu cycles) ± 4.8% / 1000 iterations
290
+ FlopType.MINUS [-x] : wwwwwwwwww.................... ( 306.31 ns = 1.24K cpu cycles) ± 2.6% / 1000 iterations
291
+ FlopType.EQUALS [x==y] : wwwwwwwwww.................... ( 320.59 ns = 1.30K cpu cycles) ± 3.9% / 1000 iterations
292
+ FlopType.GTE [x>=y] : wwwwwwwwww.................... ( 331.51 ns = 1.34K cpu cycles) ± 2.9% / 1000 iterations
293
+ FlopType.LTE [x<=y] : wwwwwwwwww.................... ( 333.81 ns = 1.35K cpu cycles) ± 1.0% / 1000 iterations
294
+ FlopType.ADD [x+y] : wwwwwwwwww.................... ( 315.84 ns = 1.28K cpu cycles) ± 3.2% / 1000 iterations
295
+ FlopType.SUB [x-y] : wwwwwwwwww.................... ( 335.49 ns = 1.36K cpu cycles) ± 3.8% / 1000 iterations
296
+ FlopType.MUL [x*y] : wwwwwwwwww.................... ( 325.65 ns = 1.32K cpu cycles) ± 3.0% / 1000 iterations
297
+ FlopType.SQRT [sqrt(x)] : wwwwwwwwww.................... ( 443.30 ns = 1.80K cpu cycles) ± 2.6% / 1000 iterations
298
+ FlopType.DIV [x/y] : wwwwwwwwww.................... ( 491.51 ns = 1.99K cpu cycles) ± 1.1% / 1000 iterations
299
+ FlopType.POW2 [2^x] : wwwwwwwwww.................... ( 1.79 µs = 7.28K cpu cycles) ± 0.3% / 1000 iterations
300
+ FlopType.LOG2 [log2(x)] : wwwwwwwwww.................... ( 2.17 µs = 8.80K cpu cycles) ± 0.8% / 1000 iterations
301
+ FlopType.POW [x^y] : wwwwwwwwww.................... ( 6.32 µs = 25.6K cpu cycles) ± 0.7% / 1000 iterations
306
302
 
307
303
  >>> results.flop_weights.show()
308
304
 
309
305
  {
310
- FlopType.ABS [abs(x)] : 0.83953
311
- FlopType.MINUS [-x] : 0.85441
312
- FlopType.EQUALS [x==y] : 1.04173
313
- FlopType.GTE [x>=y] : 1.02677
314
- FlopType.LTE [x<=y] : 0.99542
315
- FlopType.CMP_ZERO [x>=0] : 0.89041
316
- FlopType.RND [round(x)] : 0.88915
317
- FlopType.ADD [x+y] : 0.96007
318
- FlopType.SUB [x-y] : 0.98034
319
- FlopType.MUL [x*y] : 1.01992
320
- FlopType.DIV [x/y] : 2.17358
321
- FlopType.SQRT [sqrt(x)] : 1.95006
322
- FlopType.POW2 [2^x] : 11.65331
323
- FlopType.LOG2 [log2(x)] : 14.38278
324
- FlopType.POW [x^y] : 46.72479
306
+ FlopType.ABS [abs(x)] : 0.84769
307
+ FlopType.MINUS [-x] : 0.86954
308
+ FlopType.EQUALS [x==y] : 0.97369
309
+ FlopType.GTE [x>=y] : 1.05327
310
+ FlopType.LTE [x<=y] : 1.07007
311
+ FlopType.CMP_ZERO [x>=0] : 0.83957
312
+ FlopType.RND [round(x)] : 0.86695
313
+ FlopType.ADD [x+y] : 0.93905
314
+ FlopType.SUB [x-y] : 1.08227
315
+ FlopType.MUL [x*y] : 1.01055
316
+ FlopType.DIV [x/y] : 2.21970
317
+ FlopType.SQRT [sqrt(x)] : 1.86822
318
+ FlopType.POW2 [2^x] : 11.72183
319
+ FlopType.LOG2 [log2(x)] : 14.45542
320
+ FlopType.POW [x^y] : 44.68266
325
321
  }
326
322
  ```
327
323
 
328
- ## 3.2. Using `uv`
324
+ ## 4. Installing the package as a command-line tool
329
325
 
330
- There's a lower-threshold way of running benchmarks if you have `uv` installed. Simply install the package including `numba`.
326
+ An alternative way of using (parts) of the functionality is installing the package as a stand-alone command-line tool
327
+ using `uv` or `pipx`:
331
328
 
332
329
  ```
333
- uv tool install git+https://github.com/bertpl/counted-float@main[numba] # latest official release
334
- uv tool install git+https://github.com/bertpl/counted-float@develop[numba] # or latest develop version
330
+ uv tool install git+https://github.com/bertpl/counted-float@main[numba,cli] # latest official release
331
+ uv tool install git+https://github.com/bertpl/counted-float@develop[numba,cli] # or latest develop version
335
332
  ```
336
- After which you can run the `run_flops_benchmarks` command from the command line:
333
+ This installs the `counted_float` command-line tool, which can be used to e.g. run flops benchmarks.
334
+
335
+ ## 4.1 Running benchmarks
336
+
337
337
  ```
338
- run_flops_benchmark
338
+ counted_float benchmark
339
339
  ```
340
- Final results will be shown as json.
340
+ after which the results will be shown as .json.
341
+
342
+ ## 4.2. Show built-in data
341
343
 
344
+ ```
345
+ [~] counted_float show-data
346
+ MINUS ABS CMP_ZERO LTE EQUALS GTE ADD SUB MUL RND SQRT DIV POW2 LOG2 POW
347
+ ALL 0.59 0.63 0.74 0.90 0.90 0.90 0.92 1.05 1.15 1.25 3.55 3.57 12.33 14.68 34.01
348
+ ├─benchmarks 0.80 0.91 0.82 0.93 0.94 0.95 0.89 1.14 1.05 0.97 2.57 3.11 10.80 16.33 40.50
349
+ │ ├─arm 0.99 0.79 0.88 1.00 1.01 1.04 0.99 1.00 1.00 0.88 1.83 2.17 11.46 14.24 45.98
350
+ │ │ └─apple 0.99 0.79 0.88 1.00 1.01 1.04 0.99 1.00 1.00 0.88 1.83 2.17 11.46 14.24 45.98
351
+ │ │ └─m3_max_macbook_pro_16 0.99 0.79 0.88 1.00 1.01 1.04 0.99 1.00 1.00 0.88 1.83 2.17 11.46 14.24 45.98
352
+ │ └─x86 0.65 1.04 0.77 0.87 0.87 0.87 0.81 1.31 1.09 1.07 3.59 4.46 10.18 18.72 35.68
353
+ │ └─intel 0.65 1.04 0.77 0.87 0.87 0.87 0.81 1.31 1.09 1.07 3.59 4.46 10.18 18.72 35.68
354
+ │ ├─gen12_i7_1265u 1.06 1.08 1.26 1.24 1.24 1.24 0.85 1.02 0.93 3.94 6.38 8.69 20.67 40.99 87.44
355
+ │ └─gen7_i5_7200u 0.40 0.99 0.47 0.60 0.60 0.60 0.77 1.68 1.29 0.29 2.03 2.29 5.01 8.55 14.56
356
+ └─specs 0.43 0.43 0.67 0.86 0.86 0.86 0.96 0.96 1.27 1.61 4.92 4.09 14.08 13.20 28.56
357
+ ├─arm 0.82 0.82 0.65 0.65 0.65 0.65 1.03 1.03 1.45 1.35 5.92 5.53 / / /
358
+ │ ├─arm_v7a_cortex_a9 0.32 0.32 0.32 0.32 0.32 0.32 1.28 1.28 1.92 1.28 10.22 7.99 / / /
359
+ │ ├─arm_v8_cortex_a55 1.41 1.41 0.35 0.35 0.35 0.35 1.41 1.41 1.41 1.41 7.78 7.78 / / /
360
+ │ ├─arm_v8_cortex_a76 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.93 4.63 / / /
361
+ │ ├─arm_v9_cortex_x1 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.78 4.63 / / /
362
+ │ ├─arm_v9_cortex_x2 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.78 4.63 / / /
363
+ │ └─arm_v9_cortex_x3 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.78 4.63 / / /
364
+ └─x86 0.23 0.23 0.70 1.14 1.14 1.14 0.89 0.89 1.11 1.92 4.09 3.02 12.96 12.15 26.29
365
+ ├─amd 0.17 0.17 / 1.45 1.45 1.45 0.88 0.88 0.88 0.59 3.26 2.04 7.89 6.93 15.71
366
+ │ ├─zen3_r7_5800x 0.14 0.14 / 1.49 1.49 1.49 0.88 0.88 0.88 0.54 3.38 2.03 7.40 6.62 14.90
367
+ │ ├─zen4_r9_7900x 0.13 0.13 / 1.40 1.40 1.40 0.89 0.89 0.89 0.64 3.19 1.91 6.99 6.25 14.13
368
+ │ └─zen5_r7_9800x3d 0.29 0.29 / 1.47 1.47 1.47 0.88 0.88 0.88 0.59 3.23 2.20 9.51 8.03 18.42
369
+ └─intel 0.30 0.30 0.90 0.90 0.90 0.90 0.90 0.90 1.39 6.28 5.12 4.47 21.27 21.31 43.97
370
+ ├─gen09_coffee_lake 0.29 0.29 0.88 0.88 0.88 0.88 0.88 0.88 1.47 6.16 5.03 4.39 21.16 20.74 43.37
371
+ ├─gen10_cannon_lake 0.29 0.29 0.88 0.88 0.88 0.88 0.88 0.88 1.47 6.16 5.03 4.39 21.16 20.74 43.37
372
+ └─gen11_tiger_lake 0.31 0.31 0.93 0.93 0.93 0.93 0.93 0.93 1.24 6.51 5.32 4.64 21.49 22.48 45.21
373
+ ```
342
374
 
343
- # 4. Known limitations
375
+ # 5. Known limitations
344
376
 
345
377
  - currently any non-Python-built-in math operations are not counted (e.g. `numpy`)
346
378
  - not all Python built-in math operations are counted (e.g. `log`, `log10`, `exp`, `exp10`)
@@ -1,28 +1,22 @@
1
1
  <!--START_SECTION:images-->
2
2
  ![shields.io-python-versions](https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue)
3
- ![genbadge-test-count](https://bertpl.github.io/counted-float/version_artifacts/v0.9.0/badge-test-count.svg)
4
- ![genbadge-test-coverage](https://bertpl.github.io/counted-float/version_artifacts/v0.9.0/badge-coverage.svg)
5
- ![counted_float logo](https://bertpl.github.io/counted-float/version_artifacts/v0.9.0/splash.webp)
3
+ ![genbadge-test-count](https://bertpl.github.io/counted-float/version_artifacts/v0.9.2/badge-test-count.svg)
4
+ ![genbadge-test-coverage](https://bertpl.github.io/counted-float/version_artifacts/v0.9.2/badge-coverage.svg)
5
+ ![counted_float logo](https://bertpl.github.io/counted-float/version_artifacts/v0.9.2/splash.webp)
6
6
  <!--END_SECTION:images-->
7
7
 
8
8
  # counted-float
9
9
 
10
- This Python package provides functionality for counting the number of floating point operations (FLOPs) of numerical
11
- algorithms implemented in plain Python.
10
+ This Python package provides functionality for...
11
+ - **counting floating point operations** (FLOPs) of numerical algorithms implemented in plain Python, optionally weighted by their relative cost of execution
12
+ - **running benchmarks** to estimate the relative cost of executing various floating-point operations (requires `numba` optional dependency for achieving accurate results)
12
13
 
13
- The target application area are research prototypes of numerical algorithms where (weighted) flop counting can be
14
+ The target application area is evaluation of research prototypes of numerical algorithms where (weighted) flop counting can be
14
15
  useful for estimating total computational cost, in cases where benchmarking a compiled version (C, Rust, ...) is not
15
16
  feasible or desirable.
16
17
 
17
- The package contains two components:
18
- - `counting`: provides a CountedFloat class & flop counting context managers to count flops of code blocks.
19
- - `benchmarking`: provides functionality to micro-benchmark floating point operations to get an empirical
20
- ballpark estimate of the relative cost of different operations on the target hardware. Requires 'numba' optional dependency for accurate results.
21
-
22
18
  # 1. Installation
23
19
 
24
-
25
-
26
20
  Use you favorite package manager such as `uv` or `pip`:
27
21
 
28
22
  ```
@@ -32,6 +26,8 @@ pip install counted-float[numba] # install with numba optional dependency
32
26
  Numba is optional due to its relatively large size (40-50MB, including llvmlite), but without it, benchmarks will
33
27
  not be reliable (but will still run, but not in jit-compiled form).
34
28
 
29
+ NOTE: the `cli` optional dependency is only useful when installing the code as a tool using e.g. `uv` or `pipx` (see below)
30
+
35
31
  # 2. Counting Flops
36
32
 
37
33
  ## 2.1. CountedFloat class
@@ -257,72 +253,105 @@ The 3 built-in *default* flop weights are simply presets for the `key_filter` ar
257
253
 
258
254
  # 3. Benchmarking
259
255
 
260
- ## 3.1. General
261
-
262
- If the package is installed with the optional `numba` dependency, it provides
263
- the ability to micro-benchmark floating point operations as follows:
256
+ If the package is installed with the optional `numba` dependency, it provides the ability to micro-benchmark
257
+ floating point operations as follows:
264
258
 
265
259
  ```
266
260
  >>> from counted_float.benchmarking import run_flops_benchmark
267
261
  >>> results = run_flops_benchmark()
268
262
 
269
- Running FLOPS benchmarks using counted-float 0.9.0 ...
270
-
271
- baseline : wwwwwwwwww.................... 187.97 ns ± 0.52 ns / 1000 flops
272
- FlopType.ABS [abs(x)] : wwwwwwwwww.................... 307.23 ns ± 8.37 ns / 1000 flops
273
- FlopType.CMP_ZERO [x>=0] : wwwwwwwwww.................... 301.36 ns ± 7.22 ns / 1000 flops
274
- FlopType.RND [round(x)] : wwwwwwwwww.................... 302.96 ns ± 8.39 ns / 1000 flops
275
- FlopType.MINUS [-x] : wwwwwwwwww.................... 304.00 ns ± 7.99 ns / 1000 flops
276
- FlopType.EQUALS [x==y] : wwwwwwwwww.................... 319.64 ns ± 6.71 ns / 1000 flops
277
- FlopType.GTE [x>=y] : wwwwwwwwww.................... 325.35 ns ± 9.26 ns / 1000 flops
278
- FlopType.LTE [x<=y] : wwwwwwwwww.................... 323.17 ns ± 11.45 ns / 1000 flops
279
- FlopType.ADD [x+y] : wwwwwwwwww.................... 316.96 ns ± 11.11 ns / 1000 flops
280
- FlopType.SUB [x-y] : wwwwwwwwww.................... 318.59 ns ± 9.36 ns / 1000 flops
281
- FlopType.MUL [x*y] : wwwwwwwwww.................... 318.11 ns ± 7.16 ns / 1000 flops
282
- FlopType.SQRT [sqrt(x)] : wwwwwwwwww.................... 449.06 ns ± 2.42 ns / 1000 flops
283
- FlopType.DIV [x/y] : wwwwwwwwww.................... 483.70 ns ± 2.00 ns / 1000 flops
284
- FlopType.POW2 [2^x] : wwwwwwwwww.................... 1.77 µs ± 0.00 µs / 1000 flops
285
- FlopType.LOG2 [log2(x)] : wwwwwwwwww.................... 2.13 µs ± 0.01 µs / 1000 flops
286
- FlopType.POW [x^y] : wwwwwwwwww.................... 6.53 µs ± 0.00 µs / 1000 flops
287
-
263
+ Running FLOPS benchmarks using counted-float 0.9.2 ...
264
+
265
+ baseline : wwwwwwwwww.................... ( 187.03 ns = 759 cpu cycles) ± 0.6% / 1000 iterations
266
+ FlopType.ABS [abs(x)] : wwwwwwwwww.................... ( 303.31 ns = 1.23K cpu cycles) ± 1.7% / 1000 iterations
267
+ FlopType.CMP_ZERO [x>=0] : wwwwwwwwww.................... ( 302.19 ns = 1.23K cpu cycles) ± 3.0% / 1000 iterations
268
+ FlopType.RND [round(x)] : wwwwwwwwww.................... ( 305.95 ns = 1.24K cpu cycles) ± 4.8% / 1000 iterations
269
+ FlopType.MINUS [-x] : wwwwwwwwww.................... ( 306.31 ns = 1.24K cpu cycles) ± 2.6% / 1000 iterations
270
+ FlopType.EQUALS [x==y] : wwwwwwwwww.................... ( 320.59 ns = 1.30K cpu cycles) ± 3.9% / 1000 iterations
271
+ FlopType.GTE [x>=y] : wwwwwwwwww.................... ( 331.51 ns = 1.34K cpu cycles) ± 2.9% / 1000 iterations
272
+ FlopType.LTE [x<=y] : wwwwwwwwww.................... ( 333.81 ns = 1.35K cpu cycles) ± 1.0% / 1000 iterations
273
+ FlopType.ADD [x+y] : wwwwwwwwww.................... ( 315.84 ns = 1.28K cpu cycles) ± 3.2% / 1000 iterations
274
+ FlopType.SUB [x-y] : wwwwwwwwww.................... ( 335.49 ns = 1.36K cpu cycles) ± 3.8% / 1000 iterations
275
+ FlopType.MUL [x*y] : wwwwwwwwww.................... ( 325.65 ns = 1.32K cpu cycles) ± 3.0% / 1000 iterations
276
+ FlopType.SQRT [sqrt(x)] : wwwwwwwwww.................... ( 443.30 ns = 1.80K cpu cycles) ± 2.6% / 1000 iterations
277
+ FlopType.DIV [x/y] : wwwwwwwwww.................... ( 491.51 ns = 1.99K cpu cycles) ± 1.1% / 1000 iterations
278
+ FlopType.POW2 [2^x] : wwwwwwwwww.................... ( 1.79 µs = 7.28K cpu cycles) ± 0.3% / 1000 iterations
279
+ FlopType.LOG2 [log2(x)] : wwwwwwwwww.................... ( 2.17 µs = 8.80K cpu cycles) ± 0.8% / 1000 iterations
280
+ FlopType.POW [x^y] : wwwwwwwwww.................... ( 6.32 µs = 25.6K cpu cycles) ± 0.7% / 1000 iterations
288
281
 
289
282
  >>> results.flop_weights.show()
290
283
 
291
284
  {
292
- FlopType.ABS [abs(x)] : 0.83953
293
- FlopType.MINUS [-x] : 0.85441
294
- FlopType.EQUALS [x==y] : 1.04173
295
- FlopType.GTE [x>=y] : 1.02677
296
- FlopType.LTE [x<=y] : 0.99542
297
- FlopType.CMP_ZERO [x>=0] : 0.89041
298
- FlopType.RND [round(x)] : 0.88915
299
- FlopType.ADD [x+y] : 0.96007
300
- FlopType.SUB [x-y] : 0.98034
301
- FlopType.MUL [x*y] : 1.01992
302
- FlopType.DIV [x/y] : 2.17358
303
- FlopType.SQRT [sqrt(x)] : 1.95006
304
- FlopType.POW2 [2^x] : 11.65331
305
- FlopType.LOG2 [log2(x)] : 14.38278
306
- FlopType.POW [x^y] : 46.72479
285
+ FlopType.ABS [abs(x)] : 0.84769
286
+ FlopType.MINUS [-x] : 0.86954
287
+ FlopType.EQUALS [x==y] : 0.97369
288
+ FlopType.GTE [x>=y] : 1.05327
289
+ FlopType.LTE [x<=y] : 1.07007
290
+ FlopType.CMP_ZERO [x>=0] : 0.83957
291
+ FlopType.RND [round(x)] : 0.86695
292
+ FlopType.ADD [x+y] : 0.93905
293
+ FlopType.SUB [x-y] : 1.08227
294
+ FlopType.MUL [x*y] : 1.01055
295
+ FlopType.DIV [x/y] : 2.21970
296
+ FlopType.SQRT [sqrt(x)] : 1.86822
297
+ FlopType.POW2 [2^x] : 11.72183
298
+ FlopType.LOG2 [log2(x)] : 14.45542
299
+ FlopType.POW [x^y] : 44.68266
307
300
  }
308
301
  ```
309
302
 
310
- ## 3.2. Using `uv`
303
+ ## 4. Installing the package as a command-line tool
311
304
 
312
- There's a lower-threshold way of running benchmarks if you have `uv` installed. Simply install the package including `numba`.
305
+ An alternative way of using (parts) of the functionality is installing the package as a stand-alone command-line tool
306
+ using `uv` or `pipx`:
313
307
 
314
308
  ```
315
- uv tool install git+https://github.com/bertpl/counted-float@main[numba] # latest official release
316
- uv tool install git+https://github.com/bertpl/counted-float@develop[numba] # or latest develop version
309
+ uv tool install git+https://github.com/bertpl/counted-float@main[numba,cli] # latest official release
310
+ uv tool install git+https://github.com/bertpl/counted-float@develop[numba,cli] # or latest develop version
317
311
  ```
318
- After which you can run the `run_flops_benchmarks` command from the command line:
312
+ This installs the `counted_float` command-line tool, which can be used to e.g. run flops benchmarks.
313
+
314
+ ## 4.1 Running benchmarks
315
+
319
316
  ```
320
- run_flops_benchmark
317
+ counted_float benchmark
321
318
  ```
322
- Final results will be shown as json.
319
+ after which the results will be shown as .json.
320
+
321
+ ## 4.2. Show built-in data
323
322
 
323
+ ```
324
+ [~] counted_float show-data
325
+ MINUS ABS CMP_ZERO LTE EQUALS GTE ADD SUB MUL RND SQRT DIV POW2 LOG2 POW
326
+ ALL 0.59 0.63 0.74 0.90 0.90 0.90 0.92 1.05 1.15 1.25 3.55 3.57 12.33 14.68 34.01
327
+ ├─benchmarks 0.80 0.91 0.82 0.93 0.94 0.95 0.89 1.14 1.05 0.97 2.57 3.11 10.80 16.33 40.50
328
+ │ ├─arm 0.99 0.79 0.88 1.00 1.01 1.04 0.99 1.00 1.00 0.88 1.83 2.17 11.46 14.24 45.98
329
+ │ │ └─apple 0.99 0.79 0.88 1.00 1.01 1.04 0.99 1.00 1.00 0.88 1.83 2.17 11.46 14.24 45.98
330
+ │ │ └─m3_max_macbook_pro_16 0.99 0.79 0.88 1.00 1.01 1.04 0.99 1.00 1.00 0.88 1.83 2.17 11.46 14.24 45.98
331
+ │ └─x86 0.65 1.04 0.77 0.87 0.87 0.87 0.81 1.31 1.09 1.07 3.59 4.46 10.18 18.72 35.68
332
+ │ └─intel 0.65 1.04 0.77 0.87 0.87 0.87 0.81 1.31 1.09 1.07 3.59 4.46 10.18 18.72 35.68
333
+ │ ├─gen12_i7_1265u 1.06 1.08 1.26 1.24 1.24 1.24 0.85 1.02 0.93 3.94 6.38 8.69 20.67 40.99 87.44
334
+ │ └─gen7_i5_7200u 0.40 0.99 0.47 0.60 0.60 0.60 0.77 1.68 1.29 0.29 2.03 2.29 5.01 8.55 14.56
335
+ └─specs 0.43 0.43 0.67 0.86 0.86 0.86 0.96 0.96 1.27 1.61 4.92 4.09 14.08 13.20 28.56
336
+ ├─arm 0.82 0.82 0.65 0.65 0.65 0.65 1.03 1.03 1.45 1.35 5.92 5.53 / / /
337
+ │ ├─arm_v7a_cortex_a9 0.32 0.32 0.32 0.32 0.32 0.32 1.28 1.28 1.92 1.28 10.22 7.99 / / /
338
+ │ ├─arm_v8_cortex_a55 1.41 1.41 0.35 0.35 0.35 0.35 1.41 1.41 1.41 1.41 7.78 7.78 / / /
339
+ │ ├─arm_v8_cortex_a76 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.93 4.63 / / /
340
+ │ ├─arm_v9_cortex_x1 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.78 4.63 / / /
341
+ │ ├─arm_v9_cortex_x2 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.78 4.63 / / /
342
+ │ └─arm_v9_cortex_x3 0.90 0.90 0.90 0.90 0.90 0.90 0.90 0.90 1.36 1.36 4.78 4.63 / / /
343
+ └─x86 0.23 0.23 0.70 1.14 1.14 1.14 0.89 0.89 1.11 1.92 4.09 3.02 12.96 12.15 26.29
344
+ ├─amd 0.17 0.17 / 1.45 1.45 1.45 0.88 0.88 0.88 0.59 3.26 2.04 7.89 6.93 15.71
345
+ │ ├─zen3_r7_5800x 0.14 0.14 / 1.49 1.49 1.49 0.88 0.88 0.88 0.54 3.38 2.03 7.40 6.62 14.90
346
+ │ ├─zen4_r9_7900x 0.13 0.13 / 1.40 1.40 1.40 0.89 0.89 0.89 0.64 3.19 1.91 6.99 6.25 14.13
347
+ │ └─zen5_r7_9800x3d 0.29 0.29 / 1.47 1.47 1.47 0.88 0.88 0.88 0.59 3.23 2.20 9.51 8.03 18.42
348
+ └─intel 0.30 0.30 0.90 0.90 0.90 0.90 0.90 0.90 1.39 6.28 5.12 4.47 21.27 21.31 43.97
349
+ ├─gen09_coffee_lake 0.29 0.29 0.88 0.88 0.88 0.88 0.88 0.88 1.47 6.16 5.03 4.39 21.16 20.74 43.37
350
+ ├─gen10_cannon_lake 0.29 0.29 0.88 0.88 0.88 0.88 0.88 0.88 1.47 6.16 5.03 4.39 21.16 20.74 43.37
351
+ └─gen11_tiger_lake 0.31 0.31 0.93 0.93 0.93 0.93 0.93 0.93 1.24 6.51 5.32 4.64 21.49 22.48 45.21
352
+ ```
324
353
 
325
- # 4. Known limitations
354
+ # 5. Known limitations
326
355
 
327
356
  - currently any non-Python-built-in math operations are not counted (e.g. `numpy`)
328
357
  - not all Python built-in math operations are counted (e.g. `log`, `log10`, `exp`, `exp10`)
@@ -2,13 +2,14 @@ import counted_float.benchmarking as benchmarking
2
2
  import counted_float.config as config
3
3
 
4
4
  from ._core.counting import BuiltInData, CountedFloat, FlopCountingContext, PauseFlopCounting
5
- from ._core.counting.models import (
5
+ from ._core.models import (
6
6
  FlopCounts,
7
7
  FlopsBenchmarkDurations,
8
8
  FlopsBenchmarkResults,
9
9
  FlopType,
10
10
  FlopWeights,
11
11
  FPUInstruction,
12
+ Quantiles,
12
13
  SystemInfo,
13
14
  )
14
15
 
@@ -24,5 +25,6 @@ __all__ = [
24
25
  "FlopWeights",
25
26
  "FPUInstruction",
26
27
  "PauseFlopCounting",
28
+ "Quantiles",
27
29
  "SystemInfo",
28
30
  ]
@@ -0,0 +1,23 @@
1
+ import click
2
+
3
+ from counted_float import BuiltInData
4
+ from counted_float.benchmarking import run_flops_benchmark
5
+
6
+
7
+ # -------------------------------------------------------------------------
8
+ # Commands
9
+ # -------------------------------------------------------------------------
10
+ @click.group()
11
+ def cli():
12
+ pass
13
+
14
+
15
+ @cli.command(short_help="run flop benchmarks")
16
+ def benchmark():
17
+ result = run_flops_benchmark()
18
+ result.show()
19
+
20
+
21
+ @cli.command(short_help="show all built-in data")
22
+ def show_data():
23
+ BuiltInData.show()
@@ -1,6 +1,6 @@
1
1
  from importlib.metadata import version
2
2
 
3
- from counted_float._core.counting.models import FlopsBenchmarkResults
3
+ from counted_float._core.models import FlopsBenchmarkResults
4
4
 
5
5
  from ._flops_benchmark_suite import FlopsBenchmarkSuite
6
6
 
@@ -4,7 +4,7 @@ import numpy as np
4
4
  import psutil
5
5
 
6
6
  from counted_float._core.compatibility import is_numba_installed, numba
7
- from counted_float._core.counting.models import (
7
+ from counted_float._core.models import (
8
8
  BenchmarkSettings,
9
9
  FlopsBenchmarkDurations,
10
10
  FlopsBenchmarkResults,
@@ -25,7 +25,7 @@ class FlopsBenchmarkSuite:
25
25
  array_size: int = 1000,
26
26
  n_runs_total: int = 30,
27
27
  n_runs_warmup: int = 10,
28
- n_seconds_per_run_target: float = 0.5,
28
+ n_seconds_per_run_target: float = 0.01,
29
29
  ) -> FlopsBenchmarkResults:
30
30
  """
31
31
  Run entire flops benchmarking suite and return the results as a FlopsBenchmarkResults object.
@@ -49,7 +49,7 @@ class FlopsBenchmarkSuite:
49
49
  for flop_type, benchmark in benchmarks.items()
50
50
  }
51
51
 
52
- # put results in appropriate format & return
52
+ # put results in appropriate format
53
53
  return FlopsBenchmarkResults(
54
54
  system_info=SystemInfo(
55
55
  platform_processor=platform.processor(),
@@ -61,6 +61,7 @@ class FlopsBenchmarkSuite:
61
61
  platform_python_compiler=platform.python_compiler(),
62
62
  psutil_cpu_count_logical=psutil.cpu_count(logical=True),
63
63
  psutil_cpu_count_physical=psutil.cpu_count(logical=False),
64
+ psutil_cpu_freq_mhz=int(psutil.cpu_freq().current),
64
65
  ),
65
66
  benchmark_settings=BenchmarkSettings(
66
67
  array_size=array_size,
@@ -33,7 +33,7 @@ class FlopsMicroBenchmark(MicroBenchmark):
33
33
  """
34
34
 
35
35
  def __init__(self, name: str, f: Callable, size: int):
36
- super().__init__(name=name, single_operation=f"{size} flops")
36
+ super().__init__(name=name, single_operation=f"{size} iterations")
37
37
  self.size = size
38
38
  self.f = f
39
39
  self.n_operations = 0
@@ -1,7 +1,9 @@
1
1
  from abc import ABC, abstractmethod
2
2
 
3
- from ._models import MicroBenchmarkResult, SingleRunResult
4
- from ._time_utils import Timer, format_time_durations
3
+ import psutil
4
+
5
+ from counted_float._core.models import MicroBenchmarkResult, SingleRunResult
6
+ from counted_float._core.utils import Timer, compute_latency, format_latency, format_time_duration
5
7
 
6
8
 
7
9
  # =================================================================================================
@@ -74,11 +76,21 @@ class MicroBenchmark(ABC):
74
76
  warmup_runs=warmup_runs,
75
77
  benchmark_runs=benchmark_runs,
76
78
  )
77
- stats = benchmark_result.summary_stats()
78
- s_time_duration = format_time_durations(nsec_q25=stats.q25, nsec_q50=stats.q50, nsec_q75=stats.q75)
79
- print(f" {s_time_duration} / {self.single_operation}")
80
79
 
81
- # return quantiles
80
+ # display duration estimates
81
+ stats = benchmark_result.summary_stats()
82
+ s_time_duration = format_time_duration(nsec=stats.q50)
83
+ s_latency = format_latency(n_cycles=compute_latency(nsec=stats.q50, cpu_freq_mhz=psutil.cpu_freq().current))
84
+ s_uncertainty = f"{50 * (stats.q75 - stats.q25) / stats.q50:4.1f}%"
85
+ print(f" ({s_time_duration} = {s_latency}) ± {s_uncertainty} / {self.single_operation}")
86
+ #
87
+ # s_extra_info = self._compute_extra_result_info(benchmark_result)
88
+ # if s_extra_info:
89
+ # print(f" {s_time_duration} / {self.single_operation} [{s_extra_info}]")
90
+ # else:
91
+ # print(f" {s_time_duration} / {self.single_operation}")
92
+
93
+ # return final result
82
94
  return benchmark_result
83
95
 
84
96
  def run_once(self, n_operations: int) -> SingleRunResult: