ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Rerun Python SDK 日志管道基准测试实战:从吞吐量压测到微基准与火焰图剖析

2026/9/17 11:50:51 拓冰建站 浏览量
Rerun Python SDK 日志管道基准测试实战:从吞吐量压测到微基准与火焰图剖析 Rerun Python SDK 日志管道基准测试实战从吞吐量压测到微基准与火焰图剖析【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun导读本文围绕 Rerun 仓库中 tests/python/log_benchmark/README.md 所定义的 Python SDK 日志logging管道基准测试展开系统讲解如何通过pixi一键运行吞吐量throughput基准与单次调用开销micro-benchmark如何以py-spy生成火焰图定位热点以及如何使用pytest-benchmark保存并对比两次改动前后的性能基线。读完本文你将掌握 Rerun Python SDK 在本地进行性能回归检查与剖析的完整工作流并能读懂测试用例背后的日志管道设计行式rr.log、列式rr.send_columns、内存 sink 与 gRPC 直连等。这套基准测试是手动性能基准不进入 CI专门服务于本地 profiling 与回归检查——理解这一点有助于你将它嵌入自己的开发流程而不是等待 CI 结果。基准测试的整体布局三个文件各司其职基准测试代码集中在tests/python/log_benchmark/目录下由三个文件组成文件职责tests/python/log_benchmark/init.py共享数据类Point3DInput、Transform3DInput负责用固定随机种子生成可复现的输入数据tests/python/log_benchmark/test_log_benchmark.py吞吐量基准throughput benchmarks大数据批、逐点单条日志、图像、时间轴上的变换等tests/python/log_benchmark/test_micro_benchmark.py微基准per-call overhead剖析rr.log()管道中每个环节的固定开销数据类的设计值得先看一眼因为它决定了测试的可复现性Point3DInput.prepare(seed, num_points)使用np.random.default_rng(seed)以固定种子生成positions(num_points, 3)的 float32、colorsuint32和radiifloat32数组并附带默认 labelsome label。Transform3DInput.prepare(seed, num_entities, num_time_steps)生成形状为(num_time_steps, num_entities, 3)的translations取值[0, 10)和形状为(num_time_steps, num_entities, 3, 3)的mat3x3s取值[-1, 1)。也就是说同一套基准在任意机器、任意时间运行输入数据都完全一致性能差异只可能来自代码改动与环境差异——这正是做回归对比的前提。通过 pixi 一键运行全部基准项目使用 pixi 管理任务。在仓库根目录rerun/下直接运行# 运行全部基准 pixi run py-bench # 只运行吞吐量基准排除名称含 micro 的用例 pixi run py-bench -k not micro # 只运行微基准 pixi run py-bench -k micro # 运行某个具体基准例如 Points3D 的微基准 pixi run py-bench -k micro_log-Points3D-k是 pytest 的表达式过滤参数这里py-bench命令会把-k之后的参数原样透传给 pytest。py-bench这个任务定义在 pixi.toml 中其真实命令为py-bench { cmd uvpy -m pytest --benchmark-only --benchmark-group-byfunc --benchmark-sortfullname, depends-on [py-build-release] }从中可以读出三条关键信息依赖py-build-release运行基准前会先以 release 模式构建并安装 Python 绑定maturin develop --release。性能测试必须用 release 构建否则 debug 构建的测量结果毫无意义。--benchmark-only只执行被pytest-benchmark插件识别的基准函数即带benchmarkfixture 的测试跳过普通断言测试。--benchmark-group-byfunc --benchmark-sortfullname结果按函数分组、按完整名称排序便于在终端输出中按用例横向对比。独立运行单个基准配合性能分析器吞吐量基准的test_log_benchmark.py在文件底部提供了if __name__ __main__独立入口用于脱离 pytest 直接运行方便挂接 py-spy、perf 等分析器。先进入 pixi shellpixi shell然后直接运行# 独立运行 transform3d 吞吐量基准 uvpy -m tests.python.log_benchmark.test_log_benchmark transform3d # 带参数运行10 个实体、10000 个时间步、按静态数据记录 uvpy -m tests.python.log_benchmark.test_log_benchmark transform3d --num-entities 10 --num-time-steps 10000 --static # 连接到一个正在运行的 Rerun viewer先启动 rerun uvpy -m tests.python.log_benchmark.test_log_benchmark transform3d --connect这个独立入口支持如下参数定义见 test_log_benchmark.py参数默认值说明benchmark位置参数—目前仅支持transform3d--num-entities10实体数量--num-time-steps1000时间步数量--static关闭以静态数据记录不随时间变化--connect关闭通过 gRPC 连接正在运行的 Rerun viewer而不是写入内存 sink--create-only关闭只构造Transform3D实例、不实际记录用于分离“对象构造”与“日志管道”的开销注意--create-only这个选项的妙用把log_transform3d_translation_mat3x3构造 记录与create_transform3d_translation_mat3x3仅构造分开计时从而精确区分 SDK 对象构造开销与底层日志/编码/传输开销。这也是吞吐量测试test_bench_transform3d_translation_mat3x3与test_bench_create_transform3d_translation_mat3x3成对存在的原因。运行时会打印实测吞吐量例如Logged 100000 transforms in 3.21s (31153 transforms/second)数字仅为示意实际取决于硬件、构建配置与记录目标。用 py-spy 生成火焰图在独立运行模式下可以方便地挂接采样式分析器 py-spy不会像 cProfile 那样显著干扰被测代码# 生成火焰图Linux 上建议加 --native 以包含原生栈帧 sudo PYTHONPATHrerun_py/rerun_sdk:rerun_py py-spy record -o flamegraph.svg -- \ .venv/bin/python -m tests.python.log_benchmark.test_log_benchmark transform3d要点说明PYTHONPATHrerun_py/rerun_sdk:rerun_py让 Python 进程能导入仓库内尚未安装或刚由py-build-release构建的rerun包。--native会采样 Rust 侧的原生栈帧由于 Rerun 的 Python 绑定是基于 PyO3/maturin 的 Rust 实现定位热点通常必须依赖原生栈信息。生成的flamegraph.svg用浏览器打开即可看到调用栈的横向火焰图宽条即热点。Python 层与 Rust 原生层会分别体现方便判断瓶颈在 SDK 封装、Arrow 编码还是底层存储/传输。吞吐量基准详解四种典型的日志形态tests/python/log_benchmark/test_log_benchmark.py 中的吞吐量用例覆盖了四种典型的日志使用形态1. 单次调用写入超大批次Points3Dtest_bench_points3d_large_batch固定参数num_points50_000_0005000 万点一次性调用rr.log(large_batch, rr.Points3D(...))测量单次调用承载超大数据量的能力反映 Arrow 数组构建与传输的吞吐上限。2. 海量小调用逐点单条日志test_bench_points3d_many_individual固定num_points100_000在循环中逐点调用rr.log(single_point, rr.Points3D(...))每次只带 1 个点。这是典型的“每帧逐实体记录”模式测的是小消息场景下日志管道的消息处理速率。3. 图像/Tensor 数据test_bench_image固定参数为1024^2px-4channels-20000calls1024×1024、4 通道、20000 次调用循环记录同一张rr.Tensor(image)。注意它用np.zeros(...)构造全零图像测量的是重复记录同尺寸张量的稳定吞吐。4. 时间序列上的 Transform3D行式 vs 列式test_bench_transforms_over_time对同一批 10000 个变换以num_transforms_per_batch为参数做了三档对比1纯行式、100、1000列式批大小。行式batch1每个时间步调用rr.set_time(frame, sequencei)再rr.log(...)模拟逐帧逐实体记录列式batch1使用rr.send_columns一次性提交一个时间列和多个组件列例如rr.send_columns( test_transform, indexes[rr.TimeColumn(frame, sequencetimes)], columnsrr.Transform3D.columns( translationrand_trans[start:end], quaternionrand_quats[start:end], scalerand_scales[start:end], ), )rr.send_columns的语义在 rerun_py/rerun_sdk/rerun/_send_columns.py 中有明确说明它与行式rr.log相对接受多个等长列每个索引处各列数据合并为一行逻辑记录且该 API忽略通过rr.set_time设置的状态化时间也不会自动注入log_tick/log_time默认时间轴。rr.TimeColumn要求sequence、duration、timestamp三选一且只能选一个见 TimeColumn 实现sequence对应整数序列如帧号duration对应相对时间timestamp对应 Unix 绝对时间戳。这一组基准直接量化了“列式批量提交相对逐条set_timelog到底能快多少”是选择日志策略的关键依据。5. Transform3D 双时间轴吞吐与构造分离test_bench_transform3d_translation_mat3x3使用Transform3DInput1000 实体 × 10000 时间步对每条记录同时设置两个时间轴frame序列时间与sim_timetime_index * 0.01的仿真时间staticTrue参数变体则把整批数据作为静态数据记录只记录一次不随帧变化。配合--static/--create-only独立入口可以分别评估双时间轴场景下日志与对象构造各自的开销。微基准详解rr.log()管道的五层剖析tests/python/log_benchmark/test_micro_benchmark.py 是理解 Python SDK 日志开销结构的最佳入口。它对四种 archetypeScalars、Points3D、Transform3D、Boxes3D分别测量日志管道中的五个阶段基准函数测量环节说明test_bench_micro_constructarchetype 对象构造rr.Scalars(42.0)、rr.Points3D(...)等对象的纯 Python 构造开销test_bench_micro_as_component_batches组件批次化调用archetype.as_component_batches()把 archetype 拆成组件批次test_bench_micro_log_components组件批量记录调用内部函数_log_components(test_entity, batches)进入日志管道的 Python 侧入口rerun_py/rerun_sdk/rerun/_log.pytest_bench_micro_log_arrow_msgArrow 消息直达原生层手动把组件批次转成 Arrow 数组后直接调用bindings.log_arrow_msg测量绕过 archetype/批次化等 Python 封装后的原生层开销test_bench_micro_log完整rr.log一次完整的rr.log(test_entity, archetype)调用不包含对象构造archetype 在基准外预先创建好test_bench_micro_set_time时间轴设置单独测量rr.set_time(frame, sequence42)的开销把同一 archetype 在这五个阶段的耗时横向对比就能直观看出开销究竟花在 Python 对象构造、组件序列化还是原生 Rust 侧的编码/存储。例如某次测量中若log_arrow_msg与log差距明显说明瓶颈在 Python 侧的封装层若差距很小则说明瓶颈已经下探到原生层优化方向应转向 Rust 侧。基准对比保存基线、改动、再对比性能回归检查的核心流程是“改动前后各跑一次再对比”。pytest-benchmark提供了结果持久化能力# 在当前分支上保存一份基线 pixi run py-bench -k micro --benchmark-savebefore # 修改代码、重新构建py-bench 依赖 py-build-release会自动重编再保存一份 pixi run py-bench -k micro --benchmark-saveafter保存的结果存放在仓库根目录下的.benchmarks/目录中自动按序号命名例如0001_before、0002_after。对比时使用pytest-benchmark自带的 CLIuv run pytest-benchmark compare 0001 0002compare会输出两份结果在均值、中位数、标准差、每轮耗时等维度上的逐用例对比。这里的uv run同样需要先处于 pixi 环境pixi shell中因为pytest-benchmark是 Python 环境依赖。由于测试输入数据由固定随机种子生成见__init__.py的prepare两次运行的数据完全一致因此对比结果可以归因于代码改动本身。记录目标的选择内存 sink 与 gRPC 直连的差异基准代码中反复出现两个关键的 sink 选择理解它们才能正确解读测量结果rr.memory_recording()默认将日志数据全部写入内存缓冲而不是发送给 viewer。其实现见 rerun_py/rerun_sdk/rerun/_memory.py本质是创建一个PyMemorySinkStorage可后续通过MemoryRecording.num_msgs()或drain_as_bytes()读取drain_as_bytes会先冲刷当前 sink。吞吐量基准每个函数开头都调用rr.memory_recording()以重置一个新的空内存 sink——这一步至关重要它确保多次测量互不污染避免把上一轮数据混入本轮。内存 sink 排除了网络传输与 viewer 渲染的干扰测的是“日志进入 SDK 并完成编码存储”这一段的纯性能。--connect/rr.connect_grpc()通过 gRPC 连接一个正在运行的 Rerun viewerrr.connect_grpc的实现见 rerun_py/rerun_sdk/rerun/sinks.py它会立即返回、异步发送数据。这种模式包含了序列化、传输与 viewer 侧接收的完整链路更接近生产环境但由于引入了网络与 viewer 侧负载测量噪声更大更适合做端到端验证而非精确基准。小结一条完整的本地性能工作流把这套基准工具串起来就得到了一条可复用的本地性能检查工作流跑全量或定向基准pixi run py-bench -k not micro吞吐或pixi run py-bench -k micro微基准先看整体是否有明显异常定位热点对疑似慢的用例进入pixi shell后用uvpy -m tests.python.log_benchmark.test_log_benchmark transform3d独立运行配合py-spy record --native生成火焰图区分 Python 层与 Rust 原生层瓶颈隔离环节利用--create-only、微基准的五个阶段、以及行式/列式对比用例把开销精确归因到对象构造、批次化、Arrow 编码、时间轴设置或原生 sink 等具体环节回归对比改动前--benchmark-savebefore改动后--benchmark-saveafter用uv run pytest-benchmark compare 0001 0002出具定量结论。这套基准并非 CI 中的自动门禁而是为开发者准备的一套手动剖析工具箱。仓库内相关的文档入口是 tests/python/log_benchmark/README.md测试数据类与用例代码分别在init.py、test_log_benchmark.py 与 test_micro_benchmark.py建议在修改rr.log相关实现后用上述流程跑一遍前后对比再合入改动。【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考