llg3d 2.0.1__tar.gz → 3.1.0__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.
- {llg3d-2.0.1 → llg3d-3.1.0}/PKG-INFO +5 -2
- {llg3d-2.0.1 → llg3d-3.1.0}/pyproject.toml +23 -6
- llg3d-3.1.0/src/llg3d/__init__.py +4 -0
- llg3d-3.1.0/src/llg3d/benchmarks/__init__.py +1 -0
- llg3d-3.1.0/src/llg3d/benchmarks/compare_commits.py +321 -0
- llg3d-3.1.0/src/llg3d/benchmarks/efficiency.py +451 -0
- llg3d-3.1.0/src/llg3d/benchmarks/utils.py +25 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/src/llg3d/element.py +98 -17
- llg3d-3.1.0/src/llg3d/grid.py +113 -0
- llg3d-3.1.0/src/llg3d/io.py +395 -0
- llg3d-3.1.0/src/llg3d/main.py +64 -0
- llg3d-3.1.0/src/llg3d/parameters.py +185 -0
- llg3d-3.1.0/src/llg3d/post/__init__.py +1 -0
- llg3d-3.1.0/src/llg3d/post/extract.py +112 -0
- llg3d-3.1.0/src/llg3d/post/info.py +192 -0
- llg3d-3.1.0/src/llg3d/post/m1_vs_T.py +107 -0
- llg3d-3.1.0/src/llg3d/post/m1_vs_time.py +81 -0
- llg3d-3.1.0/src/llg3d/post/process.py +112 -0
- llg3d-3.1.0/src/llg3d/post/utils.py +38 -0
- llg3d-3.1.0/src/llg3d/post/x_profiles.py +161 -0
- llg3d-3.1.0/src/llg3d/py.typed +1 -0
- llg3d-3.1.0/src/llg3d/solvers/__init__.py +153 -0
- llg3d-3.1.0/src/llg3d/solvers/base.py +345 -0
- llg3d-3.1.0/src/llg3d/solvers/experimental/__init__.py +9 -0
- {llg3d-2.0.1/src/llg3d/solver → llg3d-3.1.0/src/llg3d/solvers/experimental}/jax.py +117 -143
- llg3d-3.1.0/src/llg3d/solvers/math_utils.py +41 -0
- llg3d-3.1.0/src/llg3d/solvers/mpi.py +370 -0
- llg3d-3.1.0/src/llg3d/solvers/numpy.py +126 -0
- llg3d-3.1.0/src/llg3d/solvers/opencl.py +439 -0
- llg3d-3.1.0/src/llg3d/solvers/profiling.py +38 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/src/llg3d.egg-info/PKG-INFO +5 -2
- llg3d-3.1.0/src/llg3d.egg-info/SOURCES.txt +45 -0
- llg3d-3.1.0/src/llg3d.egg-info/entry_points.txt +9 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/src/llg3d.egg-info/requires.txt +4 -0
- llg3d-3.1.0/tests/test_element.py +159 -0
- llg3d-3.1.0/tests/test_grid.py +79 -0
- llg3d-3.1.0/tests/test_io.py +306 -0
- llg3d-3.1.0/tests/test_main.py +43 -0
- llg3d-3.1.0/tests/test_parameters.py +53 -0
- llg3d-3.1.0/tests/test_profiling.py +92 -0
- llg3d-2.0.1/src/llg3d/__init__.py +0 -6
- llg3d-2.0.1/src/llg3d/grid.py +0 -123
- llg3d-2.0.1/src/llg3d/main.py +0 -67
- llg3d-2.0.1/src/llg3d/output.py +0 -107
- llg3d-2.0.1/src/llg3d/parameters.py +0 -75
- llg3d-2.0.1/src/llg3d/post/__init__.py +0 -1
- llg3d-2.0.1/src/llg3d/post/plot_results.py +0 -61
- llg3d-2.0.1/src/llg3d/post/process.py +0 -110
- llg3d-2.0.1/src/llg3d/post/temperature.py +0 -76
- llg3d-2.0.1/src/llg3d/simulation.py +0 -95
- llg3d-2.0.1/src/llg3d/solver/__init__.py +0 -45
- llg3d-2.0.1/src/llg3d/solver/mpi.py +0 -450
- llg3d-2.0.1/src/llg3d/solver/numpy.py +0 -207
- llg3d-2.0.1/src/llg3d/solver/opencl.py +0 -330
- llg3d-2.0.1/src/llg3d/solver/solver.py +0 -89
- llg3d-2.0.1/src/llg3d.egg-info/SOURCES.txt +0 -32
- llg3d-2.0.1/src/llg3d.egg-info/entry_points.txt +0 -4
- llg3d-2.0.1/tests/test_element.py +0 -51
- llg3d-2.0.1/tests/test_grid.py +0 -65
- llg3d-2.0.1/tests/test_main.py +0 -53
- llg3d-2.0.1/tests/test_parameters.py +0 -39
- {llg3d-2.0.1 → llg3d-3.1.0}/AUTHORS +0 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/LICENSE +0 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/README.md +0 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/setup.cfg +0 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/src/llg3d/__main__.py +0 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/src/llg3d.egg-info/dependency_links.txt +0 -0
- {llg3d-2.0.1 → llg3d-3.1.0}/src/llg3d.egg-info/top_level.txt +0 -0
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: llg3d
|
|
3
|
-
Version:
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: A solver for the stochastic Landau-Lifshitz-Gilbert equation in 3D
|
|
5
5
|
Author-email: Clémentine Courtès <clementine.courtes@math.unistra.fr>, Matthieu Boileau <matthieu.boileau@math.unistra.fr>
|
|
6
6
|
Project-URL: Homepage, https://gitlab.math.unistra.fr/llg3d/llg3d
|
|
7
7
|
Classifier: Programming Language :: Python :: 3
|
|
8
8
|
Classifier: License :: OSI Approved :: MIT License
|
|
9
9
|
Classifier: Operating System :: OS Independent
|
|
10
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
13
|
License-File: AUTHORS
|
|
14
14
|
Requires-Dist: numpy
|
|
15
15
|
Requires-Dist: matplotlib
|
|
16
16
|
Requires-Dist: scipy
|
|
17
|
+
Requires-Dist: tqdm
|
|
17
18
|
Provides-Extra: mpi
|
|
18
19
|
Requires-Dist: mpi4py; extra == "mpi"
|
|
19
20
|
Provides-Extra: opencl
|
|
@@ -22,6 +23,8 @@ Requires-Dist: mako; extra == "opencl"
|
|
|
22
23
|
Provides-Extra: jax
|
|
23
24
|
Requires-Dist: jax[cuda]; sys_platform != "darwin" and extra == "jax"
|
|
24
25
|
Requires-Dist: jax[cpu]; sys_platform == "darwin" and extra == "jax"
|
|
26
|
+
Provides-Extra: git
|
|
27
|
+
Requires-Dist: GitPython; extra == "git"
|
|
25
28
|
Dynamic: license-file
|
|
26
29
|
|
|
27
30
|
# LLG3D: A solver for the stochastic Landau-Lifshitz-Gilbert equation in 3D
|
|
@@ -14,8 +14,8 @@ classifiers = [
|
|
|
14
14
|
"License :: OSI Approved :: MIT License",
|
|
15
15
|
"Operating System :: OS Independent",
|
|
16
16
|
]
|
|
17
|
-
requires-python = ">=3.
|
|
18
|
-
dependencies = ["numpy", "matplotlib", "scipy"]
|
|
17
|
+
requires-python = ">=3.10"
|
|
18
|
+
dependencies = ["numpy", "matplotlib", "scipy", "tqdm"]
|
|
19
19
|
dynamic = ["version"]
|
|
20
20
|
|
|
21
21
|
|
|
@@ -28,8 +28,13 @@ Homepage = "https://gitlab.math.unistra.fr/llg3d/llg3d"
|
|
|
28
28
|
|
|
29
29
|
[project.scripts]
|
|
30
30
|
llg3d = "llg3d.main:main"
|
|
31
|
-
"llg3d.
|
|
32
|
-
"llg3d.
|
|
31
|
+
"llg3d.m1_vs_T" = "llg3d.post.m1_vs_T:main"
|
|
32
|
+
"llg3d.m1_vs_time" = "llg3d.post.m1_vs_time:main"
|
|
33
|
+
"llg3d.x_profiles" = "llg3d.post.x_profiles:main"
|
|
34
|
+
"llg3d.info" = "llg3d.post.info:main"
|
|
35
|
+
"llg3d.extract" = "llg3d.post.extract:main"
|
|
36
|
+
"llg3d.bench.compare_commits" = "llg3d.benchmarks.compare_commits:main"
|
|
37
|
+
"llg3d.bench.efficiency" = "llg3d.benchmarks.efficiency:main"
|
|
33
38
|
|
|
34
39
|
[project.optional-dependencies]
|
|
35
40
|
mpi = ["mpi4py"]
|
|
@@ -38,6 +43,7 @@ jax = [
|
|
|
38
43
|
"jax[cuda] ; sys_platform != 'darwin'",
|
|
39
44
|
"jax[cpu] ; sys_platform == 'darwin'",
|
|
40
45
|
]
|
|
46
|
+
git = ["GitPython"]
|
|
41
47
|
|
|
42
48
|
[tool.setuptools]
|
|
43
49
|
include-package-data = true
|
|
@@ -55,6 +61,7 @@ attr = "llg3d.__version__"
|
|
|
55
61
|
[tool.coverage.run]
|
|
56
62
|
parallel = true
|
|
57
63
|
source = ["src/"]
|
|
64
|
+
omit = ["src/llg3d/benchmarks/*", "src/llg3d/solvers/jax/*"]
|
|
58
65
|
|
|
59
66
|
[dependency-groups]
|
|
60
67
|
dev = [
|
|
@@ -63,13 +70,12 @@ dev = [
|
|
|
63
70
|
{ include-group = "doc" },
|
|
64
71
|
]
|
|
65
72
|
test = ["pytest", "pytest-cov", "pytest-mpi"]
|
|
66
|
-
lint = ["ruff"]
|
|
73
|
+
lint = ["ruff", "mypy", "pydoclint", "scipy-stubs", "types-tqdm"]
|
|
67
74
|
doc = [
|
|
68
75
|
"Sphinx >= 7.2.2",
|
|
69
76
|
"sphinx-design",
|
|
70
77
|
"myst-parser",
|
|
71
78
|
"furo",
|
|
72
|
-
"nbsphinx",
|
|
73
79
|
"sphinx-copybutton",
|
|
74
80
|
"sphinx-autobuild",
|
|
75
81
|
"sphinx-prompt",
|
|
@@ -77,6 +83,9 @@ doc = [
|
|
|
77
83
|
"sphinxcontrib-programoutput",
|
|
78
84
|
"sphinxcontrib-bibtex",
|
|
79
85
|
"ipython",
|
|
86
|
+
"ipykernel",
|
|
87
|
+
"tabulate",
|
|
88
|
+
"types-tabulate",
|
|
80
89
|
]
|
|
81
90
|
|
|
82
91
|
[tool.ruff]
|
|
@@ -111,3 +120,11 @@ indent-style = "space"
|
|
|
111
120
|
skip-magic-trailing-comma = false
|
|
112
121
|
# Line length compatible with Black
|
|
113
122
|
line-ending = "auto"
|
|
123
|
+
|
|
124
|
+
[tool.pydoclint]
|
|
125
|
+
style = "google"
|
|
126
|
+
arg-type-hints-in-docstring = false
|
|
127
|
+
check-return-types = false
|
|
128
|
+
|
|
129
|
+
[tool.coverage.report]
|
|
130
|
+
omit = ["jax.py"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Benchmarks package."""
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Compare simple benchmark timings between commits using GitPython.
|
|
4
|
+
|
|
5
|
+
This script keeps repository objects local to `main()` so it fails fast when
|
|
6
|
+
not run from the llg3d repository.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import argparse
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
import shlex
|
|
13
|
+
import subprocess
|
|
14
|
+
import sys
|
|
15
|
+
import logging
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
from .utils import ChdirTemporaryDirectory
|
|
20
|
+
from git import Repo
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_llg3d_repo() -> Repo:
|
|
24
|
+
"""Return the llg3d GitPython Repo object."""
|
|
25
|
+
repo = Repo(Path(__file__).resolve(), search_parent_directories=True)
|
|
26
|
+
if repo.working_tree_dir is None:
|
|
27
|
+
raise RuntimeError("Could not determine repository working tree")
|
|
28
|
+
root = Path(repo.working_tree_dir)
|
|
29
|
+
|
|
30
|
+
if (root / "src" / "llg3d").exists():
|
|
31
|
+
return repo
|
|
32
|
+
|
|
33
|
+
py = root / "pyproject.toml"
|
|
34
|
+
if py.exists():
|
|
35
|
+
try:
|
|
36
|
+
import tomllib
|
|
37
|
+
|
|
38
|
+
with py.open("rb") as fh:
|
|
39
|
+
data = tomllib.load(fh)
|
|
40
|
+
if data.get("project", {}).get("name") == "llg3d":
|
|
41
|
+
return repo
|
|
42
|
+
except Exception:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
try:
|
|
46
|
+
for remote in repo.remotes:
|
|
47
|
+
try:
|
|
48
|
+
url = remote.url
|
|
49
|
+
except Exception:
|
|
50
|
+
url = repo.git.config(f"--get remote.{remote.name}.url")
|
|
51
|
+
if url and "llg3d" in str(url):
|
|
52
|
+
return repo
|
|
53
|
+
except Exception:
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
logging.error("This script must be run inside the llg3d repository.")
|
|
57
|
+
logging.error(f"Detected repo root: {root}")
|
|
58
|
+
sys.exit(2)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_current_commit(repo: Repo) -> str:
|
|
62
|
+
"""Return the current commit hexsha for `repo`."""
|
|
63
|
+
return repo.head.commit.hexsha
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_current_ref(repo: Repo) -> str:
|
|
67
|
+
"""Return the current branch name, or the commit if HEAD is detached."""
|
|
68
|
+
if repo.head.is_detached:
|
|
69
|
+
return get_current_commit(repo)
|
|
70
|
+
return repo.active_branch.name
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def ensure_clean_worktree(repo: Repo) -> None:
|
|
74
|
+
"""Exit if the worktree contains changes or untracked files."""
|
|
75
|
+
if repo.is_dirty(untracked_files=True):
|
|
76
|
+
logging.error("Working tree is not clean. Stash or commit changes first.")
|
|
77
|
+
logging.error("Hint: git stash -u")
|
|
78
|
+
sys.exit(1)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def checkout_commit(repo: Repo, commit: str) -> None:
|
|
82
|
+
"""Checkout the given `commit` in `repo`."""
|
|
83
|
+
repo.git.checkout(commit)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def run_single_benchmark(
|
|
87
|
+
solver: str,
|
|
88
|
+
Jx: int,
|
|
89
|
+
Jy: int,
|
|
90
|
+
Jz: int,
|
|
91
|
+
n_mean: int,
|
|
92
|
+
N: int,
|
|
93
|
+
launcher: str | None = None,
|
|
94
|
+
np_procs: int = 1,
|
|
95
|
+
precision: str = "single",
|
|
96
|
+
repo_root: Path | None = None,
|
|
97
|
+
) -> dict:
|
|
98
|
+
"""Run a single benchmark and return a dict with timing results."""
|
|
99
|
+
if repo_root is None:
|
|
100
|
+
raise RuntimeError("repo_root must be provided")
|
|
101
|
+
|
|
102
|
+
arg_new = (
|
|
103
|
+
f"--element Cobalt --N {N} --dt 1.0e-14 --Jx {Jx} --Jy {Jy} --Jz {Jz} "
|
|
104
|
+
f"--dx 1.0e-9 --T 1100.0 --H_ext 0.0 --solver {solver} --precision {precision} "
|
|
105
|
+
f"--n_mean {n_mean} --n_profile 0 --seed 42"
|
|
106
|
+
)
|
|
107
|
+
arg_old = (
|
|
108
|
+
f"-element Cobalt -N {N} -dt 1.0e-14 -Jx {Jx} -Jy {Jy} -Jz {Jz} "
|
|
109
|
+
f"-dx 1.0e-9 -T 1100.0 -H_ext 0.0 -n_average {n_mean} -n_profile 0"
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
candidates = [
|
|
113
|
+
["python", "-m", "llg3d"],
|
|
114
|
+
["python", "-m", "llg3d.__main__"],
|
|
115
|
+
["python", "-m", "llg3d.main"],
|
|
116
|
+
["python", "-m", "llg3d.llg3d"],
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
effective_launcher = launcher
|
|
120
|
+
if solver == "mpi" and not effective_launcher:
|
|
121
|
+
effective_launcher = f"mpirun -np {np_procs}"
|
|
122
|
+
|
|
123
|
+
env = os.environ.copy()
|
|
124
|
+
env["PYTHONPATH"] = f"{repo_root / 'src'}" + (":" + env.get("PYTHONPATH", ""))
|
|
125
|
+
|
|
126
|
+
last_err = None
|
|
127
|
+
output = ""
|
|
128
|
+
|
|
129
|
+
with ChdirTemporaryDirectory() as tmpdir:
|
|
130
|
+
for arg_str in (arg_new, arg_old):
|
|
131
|
+
arg_list = shlex.split(arg_str)
|
|
132
|
+
for cli in candidates:
|
|
133
|
+
cmd = cli + arg_list
|
|
134
|
+
if effective_launcher:
|
|
135
|
+
cmd = shlex.split(effective_launcher) + cmd
|
|
136
|
+
proc = subprocess.run(
|
|
137
|
+
cmd,
|
|
138
|
+
cwd=tmpdir,
|
|
139
|
+
capture_output=True,
|
|
140
|
+
text=True,
|
|
141
|
+
env=env,
|
|
142
|
+
check=False,
|
|
143
|
+
)
|
|
144
|
+
if proc.returncode == 0:
|
|
145
|
+
output = proc.stdout
|
|
146
|
+
break
|
|
147
|
+
last_err = (
|
|
148
|
+
"Cmd: "
|
|
149
|
+
+ " ".join(cmd)
|
|
150
|
+
+ "\n"
|
|
151
|
+
+ "Stdout:\n"
|
|
152
|
+
+ proc.stdout
|
|
153
|
+
+ "\n"
|
|
154
|
+
+ "Stderr:\n"
|
|
155
|
+
+ proc.stderr
|
|
156
|
+
)
|
|
157
|
+
# log the last failing command at DEBUG level; it can be
|
|
158
|
+
# unrelated to the solver implementation/version
|
|
159
|
+
logging.debug(last_err)
|
|
160
|
+
if output:
|
|
161
|
+
break
|
|
162
|
+
|
|
163
|
+
if not output:
|
|
164
|
+
raise RuntimeError("Benchmark failed for all CLI variants\n" + (last_err or ""))
|
|
165
|
+
|
|
166
|
+
total_time = None
|
|
167
|
+
for line in output.splitlines():
|
|
168
|
+
if "total_time [s]" in line:
|
|
169
|
+
m = re.search(r"total_time \[s\]\s*=\s*([0-9.]+)", line)
|
|
170
|
+
if m:
|
|
171
|
+
total_time = float(m.group(1))
|
|
172
|
+
break
|
|
173
|
+
|
|
174
|
+
if total_time is None:
|
|
175
|
+
raise RuntimeError("Failed to extract total_time from output.\n" + output)
|
|
176
|
+
|
|
177
|
+
return {"total_time": total_time, "time_per_ite": total_time / N if N else 0.0}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def print_separator(char: str = "=", length: int = 80) -> None:
|
|
181
|
+
"""Print a simple separator line to stdout."""
|
|
182
|
+
logging.info(char * length)
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
def main() -> None:
|
|
186
|
+
"""Command-line entry point: compare benchmark timings between commits."""
|
|
187
|
+
# configure logging for the CLI; keep message format minimal
|
|
188
|
+
logging.basicConfig(level=logging.INFO, format="%(message)s")
|
|
189
|
+
|
|
190
|
+
repo = get_llg3d_repo()
|
|
191
|
+
assert repo.working_tree_dir is not None
|
|
192
|
+
repo_root = Path(repo.working_tree_dir)
|
|
193
|
+
|
|
194
|
+
parser = argparse.ArgumentParser(
|
|
195
|
+
description="Compare simple benchmark timings between two commits",
|
|
196
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
197
|
+
)
|
|
198
|
+
parser.add_argument("--reference-commit", default="HEAD~1")
|
|
199
|
+
parser.add_argument(
|
|
200
|
+
"--solver",
|
|
201
|
+
default="numpy",
|
|
202
|
+
choices=["numpy", "mpi", "opencl"],
|
|
203
|
+
)
|
|
204
|
+
parser.add_argument(
|
|
205
|
+
"--debug",
|
|
206
|
+
action="store_true",
|
|
207
|
+
help="Enable debug logging output",
|
|
208
|
+
)
|
|
209
|
+
parser.add_argument(
|
|
210
|
+
"--np", type=int, default=1, help="Number of processes for MPI solver"
|
|
211
|
+
)
|
|
212
|
+
parser.add_argument(
|
|
213
|
+
"--launcher", default="", help="Launcher command for MPI solver"
|
|
214
|
+
)
|
|
215
|
+
parser.add_argument(
|
|
216
|
+
"--Jx", type=int, default=300, help="Number of grid points in x"
|
|
217
|
+
)
|
|
218
|
+
parser.add_argument("--Jy", type=int, default=21, help="Number of grid points in y")
|
|
219
|
+
parser.add_argument("--Jz", type=int, default=21, help="Number of grid points in z")
|
|
220
|
+
parser.add_argument(
|
|
221
|
+
"--n_mean",
|
|
222
|
+
type=int,
|
|
223
|
+
default=0,
|
|
224
|
+
help="Spatial average frequency (number of iterations)",
|
|
225
|
+
)
|
|
226
|
+
parser.add_argument(
|
|
227
|
+
"--precision",
|
|
228
|
+
choices=["single", "double"],
|
|
229
|
+
default="single",
|
|
230
|
+
help="Precision of the simulation",
|
|
231
|
+
)
|
|
232
|
+
parser.add_argument("--N", type=int, default=100, help="Number of iterations")
|
|
233
|
+
parser.add_argument("--skip-reference", action="store_true")
|
|
234
|
+
|
|
235
|
+
args = parser.parse_args()
|
|
236
|
+
|
|
237
|
+
if args.debug:
|
|
238
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
|
239
|
+
|
|
240
|
+
current_ref = get_current_ref(repo)
|
|
241
|
+
current_commit = get_current_commit(repo)
|
|
242
|
+
reference_commit = args.reference_commit
|
|
243
|
+
|
|
244
|
+
if current_ref == current_commit:
|
|
245
|
+
logging.error("detached HEAD — checkout a branch first")
|
|
246
|
+
sys.exit(1)
|
|
247
|
+
|
|
248
|
+
print_separator()
|
|
249
|
+
logging.info("SIMPLE COMPARISON BENCHMARK")
|
|
250
|
+
print_separator()
|
|
251
|
+
logging.info(f"Current ref : {current_ref}")
|
|
252
|
+
logging.info(f"Current hash : {current_commit[:8]}")
|
|
253
|
+
logging.info(f"Reference : {reference_commit}")
|
|
254
|
+
logging.info(f"Solver : {args.solver}")
|
|
255
|
+
print_separator()
|
|
256
|
+
|
|
257
|
+
reference_result = None
|
|
258
|
+
if not args.skip_reference:
|
|
259
|
+
stash = False
|
|
260
|
+
if repo.is_dirty(untracked_files=True):
|
|
261
|
+
try:
|
|
262
|
+
repo.git.stash("save", "-u")
|
|
263
|
+
stash = True
|
|
264
|
+
except Exception:
|
|
265
|
+
stash = False
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
checkout_commit(repo, reference_commit)
|
|
269
|
+
reference_result = run_single_benchmark(
|
|
270
|
+
args.solver,
|
|
271
|
+
args.Jx,
|
|
272
|
+
args.Jy,
|
|
273
|
+
args.Jz,
|
|
274
|
+
args.n_mean,
|
|
275
|
+
args.N,
|
|
276
|
+
args.launcher or None,
|
|
277
|
+
args.np,
|
|
278
|
+
args.precision,
|
|
279
|
+
repo_root=repo_root,
|
|
280
|
+
)
|
|
281
|
+
finally:
|
|
282
|
+
checkout_commit(repo, current_ref)
|
|
283
|
+
if stash:
|
|
284
|
+
try:
|
|
285
|
+
repo.git.stash("pop")
|
|
286
|
+
except Exception:
|
|
287
|
+
pass
|
|
288
|
+
|
|
289
|
+
current_result = run_single_benchmark(
|
|
290
|
+
args.solver,
|
|
291
|
+
args.Jx,
|
|
292
|
+
args.Jy,
|
|
293
|
+
args.Jz,
|
|
294
|
+
args.n_mean,
|
|
295
|
+
args.N,
|
|
296
|
+
args.launcher or None,
|
|
297
|
+
args.np,
|
|
298
|
+
args.precision,
|
|
299
|
+
repo_root=repo_root,
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
if reference_result:
|
|
303
|
+
speedup = reference_result["total_time"] / current_result["total_time"]
|
|
304
|
+
diff_pct = (
|
|
305
|
+
100
|
|
306
|
+
* (current_result["total_time"] - reference_result["total_time"])
|
|
307
|
+
/ reference_result["total_time"]
|
|
308
|
+
)
|
|
309
|
+
logging.info(f"Reference : {reference_result['total_time']:.3f} s")
|
|
310
|
+
logging.info(f"Current : {current_result['total_time']:.3f} s")
|
|
311
|
+
logging.info(f"Speedup : {speedup:.3f}x")
|
|
312
|
+
logging.info(f"Diff : {diff_pct:+.1f}%")
|
|
313
|
+
else:
|
|
314
|
+
logging.info(f"Current : {current_result['total_time']:.3f} s")
|
|
315
|
+
|
|
316
|
+
print_separator()
|
|
317
|
+
logging.info("✓ Benchmark completed!")
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
if __name__ == "__main__":
|
|
321
|
+
main()
|