Logging¶
PyPTO ships two independent logging subsystems. Knowing which one a message comes from — and which knob controls it — is essential for day-to-day debugging.
| Subsystem | Source | Sink | Threshold knob |
|---|---|---|---|
| PyPTO C++ logger | Compiler core (src/, passes, codegen, diagnostics) |
stderr | pypto.set_log_level() / PYPTO_LOG_LEVEL |
| PyPTO runtime logger | On-device runtime (runtime/, simpler Python + C++) |
stderr via Python logging |
pypto.runtime.configure_log() / PYPTO_RUNTIME_LOG |
They are deliberately separate: the compile-time logger and the run-time
logger have different audiences (kernel author vs. integrator) and run in
different processes (host compiler vs. simpler worker). A change to one
does not silence the other unless you opt in via sync_pypto=True.
1. PyPTO C++ logger (compile-time)¶
Used by every LOG_INFO / LOG_WARN / LOG_ERROR call inside the
compiler, including diagnostics (Warning, PerfHint) — see
passes/92-diagnostics.md for what fires on
each level.
Levels¶
LogLevel is a coarse enum exposed in python/pypto/pypto_core/logging.pyi:18:
| Value | Name | Use |
|---|---|---|
| 0 | DEBUG |
Verbose pass tracing, IR dumps |
| 1 | INFO |
Per-hint perf summaries, pipeline status |
| 2 | WARN |
Likely-mistake diagnostics |
| 3 | ERROR |
Recoverable compile errors |
| 4 | FATAL |
Unrecoverable, abort imminent |
| 5 | EVENT |
Structured timing events |
| 6 | NONE |
Silence everything |
Setting the threshold¶
Programmatic (preferred in tests and library code):
Environment variable (PYPTO_LOG_LEVEL) — case-insensitive, accepts
the names above. Read once at C++ logger init:
Override order: explicit set_log_level() wins over PYPTO_LOG_LEVEL,
which wins over the build-time default (info in release, debug
otherwise).
2. PyPTO runtime logger (run-time)¶
Drives the Python logger named "simpler" and (via a one-shot snapshot
inside Worker.init()) simpler's C++ runtime. Everything emitted while
launching kernels, waiting on tasks, or tearing down the worker flows
through here.
The user-facing entry point lives in python/pypto/runtime/log_config.py:38:
from pypto.runtime import configure_log, log_level
configure_log("v7") # finer than INFO, coarser than DEBUG
print(log_level()) # → 22 (Python logging int)
Levels¶
The runtime logger uses a finer band than PyPTO's C++ enum. The canonical
table lives in
runtime/simpler_setup/log_config.py
and pypto.runtime.configure_log() delegates parsing there:
| Name(s) | Python logging int |
Notes |
|---|---|---|
debug |
10 | full verbosity |
v0 .. v9 |
15..24 | INFO sub-tiers; v5 == info (20) |
info |
20 | runtime default |
warn / warning |
30 | |
error |
40 | |
null |
60 | silence everything |
v0..v9 is what makes the runtime logger different from the PyPTO C++
one: you get ten gradations inside INFO so noisy subsystems can be
turned up without dropping back to full debug.
configure_log(level, *, sync_pypto=False)¶
| Argument | Type | Effect |
|---|---|---|
level |
int or str |
Python logger int (e.g. 20) or any name from the table above. Case-insensitive. |
sync_pypto |
bool (default False) |
When True, also push the closest LogLevel band onto PyPTO's C++ logger — useful when you want a single knob to cover both subsystems. |
The band mapping used by sync_pypto=True
(log_config.py:63-81):
| runtime threshold | PyPTO LogLevel |
|---|---|
| ≤14 | DEBUG |
15..24 (v0..v9) |
INFO |
25..39 (warn) |
WARN |
40..59 (error) |
ERROR |
≥60 (null) |
NONE |
Read back the effective threshold with
pypto.runtime.log_level() (re-exported from current_level()).
Environment variables¶
pypto.runtime runs an idempotent bootstrap (_ensure_configured) once
at import time, so you can drive logging from the shell without touching
Python:
| Env var | Effect |
|---|---|
PYPTO_RUNTIME_LOG |
Same string accepted by configure_log(level=...). Unset = keep the runtime logger at its V5 default. |
PYPTO_RUNTIME_LOG_SYNC |
When =1, flips the default of sync_pypto to True for the env-var bootstrap. Ignored when PYPTO_RUNTIME_LOG is unset. |
# Verbose runtime logs, leave PyPTO C++ untouched
PYPTO_RUNTIME_LOG=v7 python -m my_test
# One knob for both subsystems
PYPTO_RUNTIME_LOG=debug PYPTO_RUNTIME_LOG_SYNC=1 python -m my_test
An explicit configure_log(...) call after import overrides whatever the
env bootstrap chose.
3. pytest options (tests/st/)¶
The integration-test harness exposes both subsystems as CLI options
(tests/st/conftest.py:157-170).
They are applied in pytest_configure so collection-time logs already
respect them.
| Option | Default | Drives |
|---|---|---|
--pypto-log-level |
ERROR |
PyPTO C++ logger via set_log_level(LogLevel[name]) |
--runtime-log-level |
unset (keeps v5) |
PyPTO runtime logger via configure_log(level) — note this does not pass sync_pypto=True |
# Quiet PyPTO compile chatter, verbose runtime logs
pytest tests/st/ --pypto-log-level=ERROR --runtime-log-level=v8
# Debug both
pytest tests/st/ --pypto-log-level=DEBUG --runtime-log-level=debug
4. Decision guide¶
| You want to … | Use |
|---|---|
| Mute compiler warnings during a long compile | set_log_level(LogLevel.ERROR) or PYPTO_LOG_LEVEL=error |
| See pass-by-pass tracing | set_log_level(LogLevel.DEBUG) |
| Read perf hints on stderr | leave PyPTO at default INFO (or PYPTO_LOG_LEVEL=info) — see passes/92-diagnostics.md |
| Trace a hang at execute time | configure_log("debug") or PYPTO_RUNTIME_LOG=debug |
| Bump only one noisy runtime subsystem | configure_log("v7") (V0..V9 is finer than info/debug) |
| One env var to silence everything | PYPTO_RUNTIME_LOG=null PYPTO_RUNTIME_LOG_SYNC=1 PYPTO_LOG_LEVEL=none |
5. Common pitfalls¶
PYPTO_LOG_LEVELdoes not affect runtime logs, andPYPTO_RUNTIME_LOGdoes not affect compiler logs. Usesync_pypto=True(or set both env vars) if you want one knob.configure_log()re-imports simpler lazily. In environments where simpler is not installed (codegen-only flows), avoid calling it — thepypto.runtimeimport itself is safe because the env-var bootstrap short-circuits whenPYPTO_RUNTIME_LOGis unset.--runtime-log-levelintests/st/does not sync PyPTO. Pair it with--pypto-log-levelif you want both subsystems aligned.- The runtime C++ side reads its threshold once at
Worker.init(). Callingconfigure_log()after the worker is up changes only the Python side until the next worker init.
See also¶
- passes/92-diagnostics.md — what each diagnostic phase emits at INFO / WARN, and the perf-hint file output
- python/pypto/runtime/log_config.py — the canonical implementation
- runtime/simpler_setup/log_config.py — simpler's level table