mjolnir-cli 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.
- mjolnir_cli/__init__.py +8 -0
- mjolnir_cli/__main__.py +4 -0
- mjolnir_cli/accuracy.py +333 -0
- mjolnir_cli/autoresearch.py +539 -0
- mjolnir_cli/benchy.py +475 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4/config.yaml +78 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_DFLASH2/config.yaml +103 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_DSPARK/config.yaml +102 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_FA2/config.yaml +84 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_FA4hd256/config.yaml +104 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR/config.yaml +86 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3/config.yaml +93 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_DFLASH2/config.yaml +123 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_DSPARK/config.yaml +124 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8/.env +2 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8/config.yaml +98 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT32K/.env +4 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT32K/config.yaml +98 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT64K/.env +4 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_LMH8_VT64K/config.yaml +102 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_VT32K/.env +3 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/NVFP4_MJOLNIR_E2M3_VT32K/config.yaml +98 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/draft_vocab.json +1 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8-27B/kv_scales.json +35197 -0
- mjolnir_cli/bundled/configs/Qwen/Qwen3.8_chat_template.jinja +456 -0
- mjolnir_cli/bundled/docker/litellm/docker-compose.yaml +113 -0
- mjolnir_cli/bundled/docker/litellm/litellm.env.example +51 -0
- mjolnir_cli/bundled/docker/litellm/litellm_config.template.example.yaml +192 -0
- mjolnir_cli/bundled/docker/perses/README.md +89 -0
- mjolnir_cli/bundled/docker/perses/dashboards/global-datasource.yaml +17 -0
- mjolnir_cli/bundled/docker/perses/dashboards/performance_statistics.yaml +771 -0
- mjolnir_cli/bundled/docker/perses/dashboards/project.yaml +13 -0
- mjolnir_cli/bundled/docker/perses/dashboards/query_statistics.yaml +399 -0
- mjolnir_cli/bundled/docker/perses/docker-compose.yaml +51 -0
- mjolnir_cli/bundled/docker/perses/perses.yml +16 -0
- mjolnir_cli/bundled/docker/perses/prometheus.template.yaml +20 -0
- mjolnir_cli/bundled/scripts/hw/setup-thor.sh +1287 -0
- mjolnir_cli/cachectl.py +146 -0
- mjolnir_cli/charts.py +1687 -0
- mjolnir_cli/cli.py +1480 -0
- mjolnir_cli/clidoc.py +170 -0
- mjolnir_cli/config.py +346 -0
- mjolnir_cli/dockerctl.py +533 -0
- mjolnir_cli/drivers/fa2_driver.py +89 -0
- mjolnir_cli/drivers/fi_driver.py +134 -0
- mjolnir_cli/e2e.py +302 -0
- mjolnir_cli/fonts/InterDisplay-Bold.ttf +0 -0
- mjolnir_cli/fonts/InterDisplay-Medium.ttf +0 -0
- mjolnir_cli/fonts/InterDisplay-Regular.ttf +0 -0
- mjolnir_cli/fonts/InterDisplay-SemiBold.ttf +0 -0
- mjolnir_cli/fonts/OFL.txt +92 -0
- mjolnir_cli/gate.py +233 -0
- mjolnir_cli/history.py +159 -0
- mjolnir_cli/interactive.py +383 -0
- mjolnir_cli/legs.py +109 -0
- mjolnir_cli/litellm.py +254 -0
- mjolnir_cli/perses.py +214 -0
- mjolnir_cli/picker.py +70 -0
- mjolnir_cli/readme.py +1020 -0
- mjolnir_cli/stack.py +340 -0
- mjolnir_cli/tasks.py +122 -0
- mjolnir_cli/theme.py +281 -0
- mjolnir_cli/thor.py +108 -0
- mjolnir_cli/verify/__init__.py +2 -0
- mjolnir_cli/verify/cli.py +816 -0
- mjolnir_cli/verify/docker.py +334 -0
- mjolnir_cli/verify/kvcache.py +180 -0
- mjolnir_cli/verify/legs.py +134 -0
- mjolnir_cli/verify/ncu.py +141 -0
- mjolnir_cli/verify/profile.py +312 -0
- mjolnir_cli/verify/report.py +177 -0
- mjolnir_cli/verify/results.py +157 -0
- mjolnir_cli/verify/spec.py +279 -0
- mjolnir_cli/verify/stages.py +817 -0
- mjolnir_cli-0.2.0.dist-info/METADATA +87 -0
- mjolnir_cli-0.2.0.dist-info/RECORD +80 -0
- mjolnir_cli-0.2.0.dist-info/WHEEL +4 -0
- mjolnir_cli-0.2.0.dist-info/entry_points.txt +2 -0
- mjolnir_cli-0.2.0.dist-info/licenses/LICENSE +202 -0
- mjolnir_cli-0.2.0.dist-info/licenses/NOTICE +64 -0
mjolnir_cli/cachectl.py
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"""Host page-cache management + the one-time, targeted NOPASSWD sudo grant
|
|
2
|
+
that lets the kernel benches clear it without a password prompt.
|
|
3
|
+
|
|
4
|
+
The kernel compile / verify / bench path clears the host page cache
|
|
5
|
+
(``sysctl -w vm.drop_caches=3``) right before the measurement so a warm file
|
|
6
|
+
cache can't skew the numbers. That call needs root, so
|
|
7
|
+
``mjolnir grant-permissions`` installs a *targeted* NOPASSWD grant —
|
|
8
|
+
drop-caches only, **never full sudo** — as a single sudoers drop-in
|
|
9
|
+
(``/etc/sudoers.d/mjolnir-drop-caches``). After that one install (one sudo
|
|
10
|
+
password prompt) the cache clear runs passwordless on every run.
|
|
11
|
+
|
|
12
|
+
``prepare_bench()`` is the "always-before" hook the compile/test/bench entry
|
|
13
|
+
points call: it clears when the grant is present and silently skips (with a
|
|
14
|
+
hint) when it isn't — it never prompts and never fails a run.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import getpass
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
import subprocess
|
|
23
|
+
import sys
|
|
24
|
+
import tempfile
|
|
25
|
+
|
|
26
|
+
# The command the grant covers. sudoers requires the absolute path; the
|
|
27
|
+
# property is the kernel page/dentry/inode cache clear.
|
|
28
|
+
SYSCTL = "/usr/sbin/sysctl"
|
|
29
|
+
DROP_CACHES = "vm.drop_caches=3"
|
|
30
|
+
DROP_CACHES_CMD = f"{SYSCTL} -w {DROP_CACHES}"
|
|
31
|
+
|
|
32
|
+
# The sudoers drop-in the grant installs (one file, one rule).
|
|
33
|
+
SUDOERS_DROPIN = "/etc/sudoers.d/mjolnir-drop-caches"
|
|
34
|
+
|
|
35
|
+
# The rule is recognized in a `sudo -l` listing by the sysctl command + the
|
|
36
|
+
# property name. `=` is escaped to `\=` in the listing, but `vm.drop_caches`
|
|
37
|
+
# (a literal dot) survives verbatim — and the literal dot keeps it distinct
|
|
38
|
+
# from an unrelated `tee /proc/sys/vm/drop_caches` grant (a slash, not a dot).
|
|
39
|
+
_GRANTED_RE = re.compile(r"sysctl.*vm\.drop_caches")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _user() -> str:
|
|
43
|
+
"""The invoking user (honors SUDO_USER when already running under sudo)."""
|
|
44
|
+
return os.environ.get("SUDO_USER") or getpass.getuser()
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _rule() -> str:
|
|
48
|
+
"""The single sudoers rule: this user runs the cache clear passwordless —
|
|
49
|
+
nothing else (explicitly *not* full sudo)."""
|
|
50
|
+
return f"{_user()} ALL=(ALL) NOPASSWD: {DROP_CACHES_CMD}\n"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def drop_caches_granted() -> bool:
|
|
54
|
+
"""True if the current user can run the cache clear passwordless.
|
|
55
|
+
|
|
56
|
+
Checked via the non-interactive ``sudo -n -l`` listing (read-only, no
|
|
57
|
+
password prompt). A missing/locked sudo → False (callers skip the clear
|
|
58
|
+
rather than fail)."""
|
|
59
|
+
try:
|
|
60
|
+
p = subprocess.run(["sudo", "-n", "-l"], capture_output=True, text=True, timeout=15)
|
|
61
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
62
|
+
return False
|
|
63
|
+
return p.returncode == 0 and _GRANTED_RE.search(p.stdout) is not None
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def drop_caches() -> int:
|
|
67
|
+
"""Clear the page cache passwordless (``sudo -n sysctl -w
|
|
68
|
+
vm.drop_caches=3``). Returns the sysctl exit code (0 = cleared).
|
|
69
|
+
|
|
70
|
+
The command is passed as separate argv elements (NOT one joined string)
|
|
71
|
+
so ``sudo`` matches it against the ``/usr/sbin/sysctl -w vm.drop_caches=3``
|
|
72
|
+
NOPASSWD rule — a single token would not match and would fall through to
|
|
73
|
+
the password-requiring rule. ``-n`` makes a missing grant fail fast
|
|
74
|
+
instead of prompting — callers that may run without the grant check
|
|
75
|
+
:func:`drop_caches_granted` first or use :func:`prepare_bench`."""
|
|
76
|
+
return subprocess.call(["sudo", "-n", SYSCTL, "-w", DROP_CACHES])
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def grant_drop_caches(assume_yes: bool = False) -> int:
|
|
80
|
+
"""Install the targeted drop-caches NOPASSWD grant (idempotent; exit code).
|
|
81
|
+
|
|
82
|
+
Already granted → no-op (0). Otherwise the single rule is written to a
|
|
83
|
+
temp file, validated with ``visudo -cf`` (a bad rule can never reach
|
|
84
|
+
sudoers), then installed as a 0440 root-owned drop-in via one ``sudo
|
|
85
|
+
install`` — the single password prompt. Adds only the cache-clear
|
|
86
|
+
command, never full sudo."""
|
|
87
|
+
if drop_caches_granted():
|
|
88
|
+
print("[mjolnir] drop-caches grant already present — nothing to do", file=sys.stderr)
|
|
89
|
+
return 0
|
|
90
|
+
if not assume_yes:
|
|
91
|
+
try:
|
|
92
|
+
ans = (
|
|
93
|
+
input(
|
|
94
|
+
f"Install a NOPASSWD sudo grant for '{DROP_CACHES_CMD}' (cache clear only — not full sudo)? [y/N] "
|
|
95
|
+
)
|
|
96
|
+
.strip()
|
|
97
|
+
.lower()
|
|
98
|
+
)
|
|
99
|
+
except EOFError:
|
|
100
|
+
ans = ""
|
|
101
|
+
if ans not in ("y", "yes"):
|
|
102
|
+
print("[mjolnir] aborted — no change", file=sys.stderr)
|
|
103
|
+
return 1
|
|
104
|
+
|
|
105
|
+
rule = _rule()
|
|
106
|
+
fd, tmp = tempfile.mkstemp(prefix="mjolnir-sudoers-")
|
|
107
|
+
try:
|
|
108
|
+
with os.fdopen(fd, "w") as fh:
|
|
109
|
+
fh.write(rule)
|
|
110
|
+
chk = subprocess.run(["visudo", "-cf", tmp], capture_output=True, text=True)
|
|
111
|
+
if chk.returncode != 0:
|
|
112
|
+
print(f"[mjolnir] visudo rejected the rule:\n{chk.stdout}{chk.stderr}", file=sys.stderr)
|
|
113
|
+
return 1
|
|
114
|
+
# One privileged step: install as a 0440 root-owned drop-in.
|
|
115
|
+
rc = subprocess.call(["sudo", "install", "-m", "0440", "-o", "root", "-g", "root", tmp, SUDOERS_DROPIN])
|
|
116
|
+
if rc != 0:
|
|
117
|
+
print(f"[mjolnir] failed to install the drop-in (exit {rc})", file=sys.stderr)
|
|
118
|
+
return rc
|
|
119
|
+
print(f"[mjolnir] installed {SUDOERS_DROPIN}", file=sys.stderr)
|
|
120
|
+
return 0
|
|
121
|
+
finally:
|
|
122
|
+
try:
|
|
123
|
+
os.unlink(tmp)
|
|
124
|
+
except OSError:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def prepare_bench() -> None:
|
|
129
|
+
"""The "always-before" clean-cache hook. Called right before a kernel
|
|
130
|
+
compile/test/bench (``mjolnir verify``, ``image gates``) and around the server
|
|
131
|
+
(before ``serve up``, after ``serve down``) so a warm file cache can't skew
|
|
132
|
+
a measurement and freed cache is released after serving. Never raises and
|
|
133
|
+
never prompts — if the grant is missing it prints a hint and proceeds
|
|
134
|
+
(the work still happens, just on a warm cache).
|
|
135
|
+
"""
|
|
136
|
+
if not drop_caches_granted():
|
|
137
|
+
print(
|
|
138
|
+
"[mjolnir] page-cache clear skipped (grant missing) — run 'mjolnir grant-permissions' to enable it",
|
|
139
|
+
file=sys.stderr,
|
|
140
|
+
)
|
|
141
|
+
return
|
|
142
|
+
rc = drop_caches()
|
|
143
|
+
if rc == 0:
|
|
144
|
+
print("[mjolnir] page cache cleared (vm.drop_caches=3)", file=sys.stderr)
|
|
145
|
+
else:
|
|
146
|
+
print(f"[mjolnir] page-cache clear failed (exit {rc}) — proceeding", file=sys.stderr)
|