flopscope 0.2.0__py3-none-any.whl

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 (115) hide show
  1. benchmarks/__init__.py +1 -0
  2. benchmarks/__main__.py +6 -0
  3. benchmarks/_baseline.py +171 -0
  4. benchmarks/_bitwise.py +231 -0
  5. benchmarks/_complex.py +176 -0
  6. benchmarks/_contractions.py +291 -0
  7. benchmarks/_fft.py +198 -0
  8. benchmarks/_impl_urls.py +139 -0
  9. benchmarks/_linalg.py +197 -0
  10. benchmarks/_linalg_delegates.py +407 -0
  11. benchmarks/_metadata.py +141 -0
  12. benchmarks/_misc.py +653 -0
  13. benchmarks/_perf.py +321 -0
  14. benchmarks/_perm_group_calibration.py +175 -0
  15. benchmarks/_pointwise.py +372 -0
  16. benchmarks/_polynomial.py +193 -0
  17. benchmarks/_random.py +209 -0
  18. benchmarks/_reductions.py +136 -0
  19. benchmarks/_sorting.py +289 -0
  20. benchmarks/_stats.py +137 -0
  21. benchmarks/_window.py +92 -0
  22. benchmarks/accumulation/__init__.py +0 -0
  23. benchmarks/accumulation/bench_cost_compute.py +138 -0
  24. benchmarks/dashboard.py +312 -0
  25. benchmarks/runner.py +636 -0
  26. flopscope/__init__.py +273 -0
  27. flopscope/_accumulation/__init__.py +13 -0
  28. flopscope/_accumulation/_bipartite.py +121 -0
  29. flopscope/_accumulation/_burnside.py +51 -0
  30. flopscope/_accumulation/_cache.py +146 -0
  31. flopscope/_accumulation/_components.py +153 -0
  32. flopscope/_accumulation/_cost.py +1414 -0
  33. flopscope/_accumulation/_cost_descriptions.py +63 -0
  34. flopscope/_accumulation/_detection.py +318 -0
  35. flopscope/_accumulation/_ladder.py +191 -0
  36. flopscope/_accumulation/_output_orbit.py +104 -0
  37. flopscope/_accumulation/_partition.py +290 -0
  38. flopscope/_accumulation/_path_info.py +211 -0
  39. flopscope/_accumulation/_public.py +169 -0
  40. flopscope/_accumulation/_reduction.py +310 -0
  41. flopscope/_accumulation/_regimes.py +303 -0
  42. flopscope/_accumulation/_shape.py +33 -0
  43. flopscope/_accumulation/_wreath.py +209 -0
  44. flopscope/_budget.py +1027 -0
  45. flopscope/_config.py +118 -0
  46. flopscope/_counting_ops.py +451 -0
  47. flopscope/_display.py +478 -0
  48. flopscope/_docstrings.py +59 -0
  49. flopscope/_dtypes.py +20 -0
  50. flopscope/_einsum.py +717 -0
  51. flopscope/_errstate.py +25 -0
  52. flopscope/_flops.py +282 -0
  53. flopscope/_free_ops.py +2654 -0
  54. flopscope/_ndarray.py +1126 -0
  55. flopscope/_opt_einsum/LICENSE +21 -0
  56. flopscope/_opt_einsum/NOTICE +59 -0
  57. flopscope/_opt_einsum/__init__.py +209 -0
  58. flopscope/_opt_einsum/_contract.py +1478 -0
  59. flopscope/_opt_einsum/_helpers.py +164 -0
  60. flopscope/_opt_einsum/_hsluv.py +273 -0
  61. flopscope/_opt_einsum/_path_random.py +462 -0
  62. flopscope/_opt_einsum/_paths.py +1653 -0
  63. flopscope/_opt_einsum/_subgraph_symmetry.py +544 -0
  64. flopscope/_opt_einsum/_symmetry.py +140 -0
  65. flopscope/_opt_einsum/_typing.py +37 -0
  66. flopscope/_perm_group.py +717 -0
  67. flopscope/_pointwise.py +2522 -0
  68. flopscope/_polynomial.py +278 -0
  69. flopscope/_registry.py +3216 -0
  70. flopscope/_sorting_ops.py +571 -0
  71. flopscope/_symmetric.py +812 -0
  72. flopscope/_symmetry_transport.py +510 -0
  73. flopscope/_symmetry_utils.py +669 -0
  74. flopscope/_type_info.py +12 -0
  75. flopscope/_unwrap.py +70 -0
  76. flopscope/_validation.py +83 -0
  77. flopscope/_version_check.py +46 -0
  78. flopscope/_weights.py +195 -0
  79. flopscope/_window.py +177 -0
  80. flopscope/accounting.py +565 -0
  81. flopscope/data/default_weights.json +462 -0
  82. flopscope/data/weights.csv +509 -0
  83. flopscope/errors.py +197 -0
  84. flopscope/numpy/__init__.py +878 -0
  85. flopscope/numpy/fft/__init__.py +55 -0
  86. flopscope/numpy/fft/_free.py +51 -0
  87. flopscope/numpy/fft/_transforms.py +695 -0
  88. flopscope/numpy/linalg/__init__.py +105 -0
  89. flopscope/numpy/linalg/_aliases.py +126 -0
  90. flopscope/numpy/linalg/_compound.py +161 -0
  91. flopscope/numpy/linalg/_decompositions.py +353 -0
  92. flopscope/numpy/linalg/_properties.py +533 -0
  93. flopscope/numpy/linalg/_solvers.py +444 -0
  94. flopscope/numpy/linalg/_svd.py +122 -0
  95. flopscope/numpy/random/__init__.py +684 -0
  96. flopscope/numpy/random/_cost_formulas.py +115 -0
  97. flopscope/numpy/random/_counted_classes.py +241 -0
  98. flopscope/numpy/testing/__init__.py +13 -0
  99. flopscope/numpy/typing/__init__.py +30 -0
  100. flopscope/py.typed +0 -0
  101. flopscope/stats/__init__.py +84 -0
  102. flopscope/stats/_base.py +77 -0
  103. flopscope/stats/_cauchy.py +146 -0
  104. flopscope/stats/_erf.py +190 -0
  105. flopscope/stats/_expon.py +146 -0
  106. flopscope/stats/_laplace.py +150 -0
  107. flopscope/stats/_logistic.py +148 -0
  108. flopscope/stats/_lognorm.py +160 -0
  109. flopscope/stats/_ndtri.py +133 -0
  110. flopscope/stats/_norm.py +149 -0
  111. flopscope/stats/_truncnorm.py +186 -0
  112. flopscope/stats/_uniform.py +141 -0
  113. flopscope-0.2.0.dist-info/METADATA +23 -0
  114. flopscope-0.2.0.dist-info/RECORD +115 -0
  115. flopscope-0.2.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,141 @@
1
+ """Hardware & software metadata collection for benchmark reproducibility."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import datetime
6
+ import os
7
+ import platform
8
+ import sys
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ import numpy as np
13
+
14
+
15
+ def _read_cpu_model() -> str:
16
+ """Read CPU model from /proc/cpuinfo (Linux) or fall back to platform."""
17
+ cpuinfo = Path("/proc/cpuinfo")
18
+ if cpuinfo.exists():
19
+ for line in cpuinfo.read_text().splitlines():
20
+ if line.startswith("model name"):
21
+ return line.split(":", 1)[1].strip()
22
+ return platform.processor() or "unknown"
23
+
24
+
25
+ def _read_cache_info() -> dict[str, int | None]:
26
+ """Read CPU cache sizes from sysfs (Linux only)."""
27
+ cache_dir = Path("/sys/devices/system/cpu/cpu0/cache")
28
+ info: dict[str, int | None] = {"L1d": None, "L1i": None, "L2": None, "L3": None}
29
+ if not cache_dir.exists():
30
+ return info
31
+ for idx in cache_dir.iterdir():
32
+ if not idx.is_dir():
33
+ continue
34
+ try:
35
+ level = (idx / "level").read_text().strip()
36
+ ctype = (idx / "type").read_text().strip()
37
+ size_str = (idx / "size").read_text().strip()
38
+ # size_str is like "32K", "256K", "8192K"
39
+ size_kb = int(size_str.rstrip("K"))
40
+ if level == "1" and ctype == "Data":
41
+ info["L1d"] = size_kb
42
+ elif level == "1" and ctype == "Instruction":
43
+ info["L1i"] = size_kb
44
+ elif level == "2":
45
+ info["L2"] = size_kb
46
+ elif level == "3":
47
+ info["L3"] = size_kb
48
+ except (OSError, ValueError):
49
+ continue
50
+ return info
51
+
52
+
53
+ def _cpu_cores_threads() -> tuple[int, int]:
54
+ """Return (physical cores, logical threads)."""
55
+ try:
56
+ import psutil
57
+
58
+ return psutil.cpu_count(logical=False) or 1, psutil.cpu_count(logical=True) or 1
59
+ except ImportError:
60
+ count = os.cpu_count() or 1
61
+ return count, count
62
+
63
+
64
+ def _ram_gb() -> float:
65
+ """Return total RAM in GB."""
66
+ try:
67
+ import psutil
68
+
69
+ return round(psutil.virtual_memory().total / (1024**3), 1)
70
+ except ImportError:
71
+ return 0.0
72
+
73
+
74
+ def _blas_info() -> str:
75
+ """Extract BLAS library info from NumPy build config."""
76
+ try:
77
+ info = np.show_config(mode="dicts")
78
+ # NumPy >= 2.0 returns a dict with "Build Dependencies" key
79
+ if isinstance(info, dict):
80
+ blas = info.get("Build Dependencies", {}).get("blas", {})
81
+ if isinstance(blas, dict):
82
+ name = blas.get("name", "unknown")
83
+ version = blas.get("version", "unknown")
84
+ return f"{name} {version}"
85
+ return "unknown"
86
+ except Exception:
87
+ return "unknown"
88
+
89
+
90
+ PERF_EVENTS = [
91
+ "fp_arith_inst_retired.scalar_single",
92
+ "fp_arith_inst_retired.scalar_double",
93
+ "fp_arith_inst_retired.128b_packed_single",
94
+ "fp_arith_inst_retired.128b_packed_double",
95
+ ]
96
+
97
+
98
+ def collect_metadata(dtype: str, repeats: int, distributions: int) -> dict[str, Any]:
99
+ """Collect hardware/software metadata for a benchmark run.
100
+
101
+ Parameters
102
+ ----------
103
+ dtype : str
104
+ NumPy dtype string (e.g. "float64").
105
+ repeats : int
106
+ Number of timing repetitions per operation.
107
+ distributions : int
108
+ Number of input distributions to sample.
109
+
110
+ Returns
111
+ -------
112
+ dict
113
+ Metadata dictionary with timestamp, hardware, software, and
114
+ benchmark_config sections.
115
+ """
116
+ cores, threads = _cpu_cores_threads()
117
+ cache = _read_cache_info()
118
+
119
+ return {
120
+ "timestamp": datetime.datetime.now(datetime.timezone.utc).isoformat(),
121
+ "hardware": {
122
+ "cpu_model": _read_cpu_model(),
123
+ "cpu_cores": cores,
124
+ "cpu_threads": threads,
125
+ "ram_gb": _ram_gb(),
126
+ "arch": platform.machine(),
127
+ "cache": cache,
128
+ },
129
+ "software": {
130
+ "os": f"{platform.system()} {platform.release()}",
131
+ "python": sys.version,
132
+ "numpy": np.__version__,
133
+ "blas": _blas_info(),
134
+ },
135
+ "benchmark_config": {
136
+ "dtype": dtype,
137
+ "repeats": repeats,
138
+ "distributions": distributions,
139
+ "perf_events": PERF_EVENTS,
140
+ },
141
+ }