跳转至

日志(Logging)

PyPTO 内部存在 两套相互独立的日志子系统,调试时务必先分清当前看到的 日志来自哪一套、由哪个开关控制。

子系统 来源 输出 阈值开关
PyPTO C++ 日志 编译器核心(src/、Pass、Codegen、Diagnostics) stderr pypto.set_log_level() / pypto.get_log_level() / PYPTO_LOG_LEVEL
PyPTO runtime 日志 运行时(runtime/、simpler 的 Python 与 C++) 经 Python logging 输出到 stderr pypto.runtime.configure_log() / PYPTO_RUNTIME_LOG

两者刻意保持独立:编译期日志的读者是 kernel 作者,运行期日志的读者是 集成方,且分别属于不同进程(host 编译器 vs. simpler worker)。除非显式 传入 sync_pypto=True,对其中一个的修改 不会 影响另一个。

1. PyPTO C++ 日志(编译期)

编译器内部所有 LOG_INFO / LOG_WARN / LOG_ERROR 都走它,包括 Diagnostics(WarningPerfHint);各级别在何处触发请参考 passes/92-diagnostics.md

级别

LogLevel 是一组较粗的枚举,定义见 python/pypto/pypto_core/logging.pyi

名称 用途
0 DEBUG 详细 Pass 跟踪、IR dump
1 INFO 性能提示汇总、流水线状态
2 WARN 疑似错误的诊断
3 ERROR 可恢复的编译错误
4 FATAL 不可恢复,即将 abort
5 EVENT 结构化时间点事件
6 NONE 全部静音

设置阈值

编程方式(推荐用于测试与库代码):

from pypto import LogLevel, get_log_level, set_log_level

set_log_level(LogLevel.WARN)   # 屏蔽 INFO / DEBUG

该阈值是 进程全局 的,因此临时调低它的库代码或测试必须负责还原。 get_log_level() 正是为这种 save-restore 配对而提供的读取接口:

saved = get_log_level()
set_log_level(LogLevel.ERROR)
try:
    compile_something_noisy()
finally:
    set_log_level(saved)

不还原的后果不只是"少了些啰嗦输出":同进程内后续所有代码的 WarningPerfHint 诊断都会被一并静音,下游看到的现象是"编译器什么都没说"。 单元测试无需自行处理:tests/ut/conftest.py::_reset_log_level 会在每个 测试前后固定该级别。

环境变量 PYPTO_LOG_LEVEL(大小写不敏感,取值同上表)。在 C++ 日志器初始化时一次性读取:

export PYPTO_LOG_LEVEL=warn      # release 默认值是 info
python my_program.py

优先级:显式 set_log_level() > PYPTO_LOG_LEVEL > 编译期默认 (release 为 info,否则为 debug)。

2. PyPTO runtime 日志(运行期)

驱动名为 "simpler" 的 Python logger,并在 Worker.init() 中以一次性 快照的方式同步到 simpler 的 C++ 运行时。启动 kernel、等待 task、销毁 worker 阶段的所有日志都经此输出。

用户入口位于 python/pypto/runtime/log_config.py

from pypto.runtime import configure_log, log_level

configure_log("timing")            # 保留稳定性能标记,不打开普通 INFO 日志
print(log_level())                 # → 25  (Python logging 整数)

级别

runtime 日志提供了 PyPTO C++ 枚举中没有的独立 timing 档位,定义在 runtime/simpler_setup/log_config.pypypto.runtime.configure_log() 直接复用其 parse_level

名称 Python logging 整数 说明
debug 10 全量详细
info 20 生命周期与汇总信息
timing 25 runtime 默认;[STRACE] 等稳定性能标记
warn / warning 30
error 40
null 60 全部静音

默认 timing 阈值会显示 timing 标记、warning 和 error,同时屏蔽普通 INFO 与 DEBUG 日志。

configure_log(level, *, sync_pypto=False)

参数 类型 作用
level intstr Python logger 整数(如 20)或上表名称,大小写不敏感
sync_pypto bool,默认 False True 时同步把对应 band 的 LogLevel 推送给 PyPTO C++ 日志器,便于一个开关同时控制两套子系统

sync_pypto=True 使用的 band 映射见 log_config.py

runtime 阈值 PyPTO LogLevel
≤10 (debug) DEBUG
11..20 (info) INFO
21..30 (timing / warn) WARN
31..40 (error) ERROR
≥41 (null) NONE

timing 映射为 WARN,因为 PyPTO 没有只显示 timing 的档位;如果映射为 INFO,普通编译器信息也会被一并打开。

可用 pypto.runtime.log_level()(即 current_level() 的别名)回读 当前生效阈值。

环境变量

pypto.runtime 在导入时会执行一次幂等的 _ensure_configured bootstrap,因此可以不写 Python,仅靠 shell 环境变量驱动:

环境变量 作用
PYPTO_RUNTIME_LOG 接受与 configure_log(level=...) 相同的字符串;未设置则保持 runtime 日志的 timing 默认
PYPTO_RUNTIME_LOG_SYNC 设为 =1 时把 bootstrap 阶段 sync_pypto 的默认值翻成 True;当 PYPTO_RUNTIME_LOG 未设置时被忽略
# runtime 生命周期日志,不影响 PyPTO C++ 日志
PYPTO_RUNTIME_LOG=info python -m my_test

# 一个开关同时管两套
PYPTO_RUNTIME_LOG=debug PYPTO_RUNTIME_LOG_SYNC=1 python -m my_test

导入后再显式调用 configure_log(...) 会覆盖 bootstrap 的选择。

3. pytest 选项(tests/st/

集成测试 harness 把两套子系统都暴露成命令行参数,定义见 tests/st/conftest.py

选项 默认值 作用
--pypto-log-level ERROR 线程局部 覆盖的形式,逐个 ST 用例控制 PyPTO C++ 日志
--runtime-log-level 未设置(保留 timing 通过 configure_log(level) 控制 PyPTO runtime 日志;不会 同时传 sync_pypto=True

--pypto-log-level 刻意 调用 set_log_level():该阈值是进程全局的, 而 tests/st/conftest.py 在 ST/UT 混合会话中同样会被加载,因此在 pytest_configure 里设置它会把后续单元测试所断言的诊断输出一并静音。 现在改为在 pytest_runtest_protocol 包装器中用 _set_thread_log_level 对每个 ST 用例生效,并在 finally 中清除——fork 出的 runtime worker 仍 能继承该级别,而任何状态都不会越过该用例。编译线程池通过 ThreadPoolExecutor(initializer=...) 取得同一级别。

# 抑制编译噪声,放大 runtime 日志
pytest tests/st/ --pypto-log-level=ERROR --runtime-log-level=info

# 两侧都开 debug
pytest tests/st/ --pypto-log-level=DEBUG --runtime-log-level=debug

4. 决策表

场景 用法
长编译过程屏蔽 warning set_log_level(LogLevel.ERROR)PYPTO_LOG_LEVEL=error
查看 Pass 级跟踪 set_log_level(LogLevel.DEBUG)
在 stderr 看到性能提示 保持 PyPTO 默认 INFO(或 PYPTO_LOG_LEVEL=info),详见 passes/92-diagnostics.md
排查执行期 hang configure_log("debug")PYPTO_RUNTIME_LOG=debug
不打开 DEBUG、只显示 runtime 生命周期信息 configure_log("info")PYPTO_RUNTIME_LOG=info
一条环境变量全部静音 PYPTO_RUNTIME_LOG=null PYPTO_RUNTIME_LOG_SYNC=1 PYPTO_LOG_LEVEL=none

5. 常见坑

  • PYPTO_LOG_LEVEL 不会影响 runtime 日志,反之 PYPTO_RUNTIME_LOG 也不会影响编译器日志。需要一个开关同时管两侧时, 请使用 sync_pypto=True 或两个环境变量都设。
  • configure_log() 内部惰性导入 simpler。 在没有安装 simpler 的 纯 codegen 环境里不要调用它;import pypto.runtime 本身仍然安全,因为 当 PYPTO_RUNTIME_LOG 未设置时 bootstrap 会直接短路。
  • tests/st/ 里的 --runtime-log-level 不会自动同步 PyPTO。 想让 两套子系统对齐,请显式同时设 --pypto-log-level
  • runtime C++ 端只在 Worker.init() 时读一次阈值。 在 worker 起来 之后再调 configure_log() 仅改 Python 侧,下一次 worker init 才会 把新阈值带到 C++。

参考