ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Fuel Core VM Gas 计量基准实测:从 cargo criterion 到 collect 生成 gas-costs 全流程解析

Fuel Core VM Gas 计量基准实测:从 cargo criterion 到 collect 生成 gas-costs 全流程解析 Fuel Core VM Gas 计量基准实测从 cargo criterion 到 collect 生成 gas-costs 全流程解析【免费下载链接】fuel-coreRust full node implementation of the Fuel v2 protocol.项目地址: https://gitcode.com/GitHub_Trending/fu/fuel-core本文围绕benches/README.md及其配套的 fuel-core-benches 基准代码 展开讲解 Fuel Core 节点如何为 Fuel v2 协议中的 VM 指令计算 gas 计量成本如何运行基准套件、如何用 flamegraph 验证测量对象、以及如何用仓库自带的collect工具把 criterion 的 JSON 输出转化为gas-costs.yaml或可直接替换进GasCostsValuesV7的default-gas-costs.rs。读完后你可以独立完成一次跑基准 → 采集数据 → 生成 gas 成本文件的完整流程。基准目录的定位与结构benches/README.md开篇即说明了这套基准的核心用途为 Fuel Core VM 计算 gas 计量成本gas metering costs。换句话说链上每条 VM 指令消耗多少 gas并不是拍脑袋定的而是由这组基准实测得出。从源码结构看benches/目录同时承担两个角色基准测试入口benches/benches/ 下是 criterion 基准按功能域拆分为vm_set/alu、blockchain、crypto、flow、mem 五大指令族、contract.rscontract_root / state_root、vm_initialization.rsVM 初始化成本等模块可复用的基准工具库benches/src/lib.rs 以库形式导出VmBench、default_gas_costs、import等模块供各基准二进制共享。benches/Cargo.toml 中注册了 6 个[[bench]]目标全部harness false即由 criterion 自己驱动而非 libtest基准二进制测量对象从源码结构看vmVM 指令级成本即 gas 成本的数据来源block_target_gas区块目标 gas 相关场景block_target_gas_set/import区块导入性能benches/src/import.rsstate状态存储性能transaction_throughput交易吞吐db_lookup_times数据库查询耗时配套 db_lookup_times_utils/其中defaultfeature 启用了fuel-core/rocksdb与rocksdb-production说明基准默认在 RocksDB 存储后端下运行贴近生产节点的存储路径。运行基准cargo bench 与 cargo criterionbenches/README.md给出的运行方式非常直接两种等价选择# 方式一直接用 cargo cargo bench -p fuel-core-benches # 方式二使用 criterion 命令行工具需单独安装 cargo criterion -p fuel-core-benches两者的差异在于cargo bench会编译并运行上面列出的全部 6 个基准二进制适合完整回归cargo criterion则更灵活支持--bench过滤单个基准、--filter过滤组内单个 benchmark、以及 JSON 消息输出后文生成 gas 数据时会用到。一个值得注意的实现细节在 benches/benches/vm.rs 中基准通过#[global_allocator]把全局分配器切换为tikv_jemallocator::Jemalloc以保证计时不受系统分配器抖动影响。更关键的是run_group_ref中对测量循环的设计每次迭代前为 VM 构造三层嵌套的存储事务block → relayer → tx并注释明确说明这是为了模拟区块生产/验证时的真实嵌套层级保持相同性能特征用quanta::Clock精确计时并对指令执行前后调用black_box防止编译器优化掉被测代码每轮迭代结束后通过vm.reset_vm_state(diff)与数据库reset_changes()把 VM 和存储回滚到初始状态保证每次迭代都从完全相同的前置状态执行同一条指令——这正是单指令成本能独立于业务状态被准确测量的原因。用 flamegraph 剖析单个基准README 指出有时需要为某个基准生成火焰图flamegraph来验证自己确实在测量正确的东西。完整步骤如下全部来自 benches/README.md第一步带调试符号构建基准二进制CARGO_PROFILE_RELEASE_DEBUGtrue cargo-criterion -p fuel-core-benches --no-runCARGO_PROFILE_RELEASE_DEBUGtrue让 release 构建保留调试符号这是 flamegraph 能还原出函数名的前提。第二步找到刚构建出的基准二进制ls target/release/deps/vm* -lat | head -1输出形如target/release/deps/vm-a17190f2ca5e7169第三步用 flamegraph 运行指定基准--profile-time控制剖析时长示例为 10 秒# 剖析某个 op--bench 参数是正则 flamegraph target/release/deps/vm-a17190f2ca5e7169 --bench ^swwq/swwq$ --profile-time 10 # 剖析依赖型基准带参数的组内成员 flamegraph target/release/deps/vm-a17190f2ca5e7169 --bench ^srwq/100$ --profile-time 10这里的基准 ID 采用组名/成员名的层级结构例如swwq/swwq、srwq/100——这与 benches/src/bin/collect.rs 测试用例中mcli/10000、mcp/100000等 ID 的形态一致组名对应一个指令或一组相似指令斜杠后的数字是该组内某个具体数据点如操作数长度、slot 大小的 ID。用正则锚定^...$可以确保只剖析目标基准避免 10 秒剖析时间被同组其他基准稀释。使用 collect 生成基准数据这一步是把原始计时转化为gas 成本的核心链路README 分两步1. 运行基准并保存 JSON 输出cargo criterion -p fuel-core-benches --message-format json --bench vm bench.json--message-format json让 criterion 把每完成一个基准/一个组的事件以 JSON 行输出到 stdout。README 特别提醒不要直接把管道接给 collect 二进制基准运行很慢建议先落盘保存如上例的bench.json。2. 运行 collect 生成 gas 成本文件cargo run -p fuel-core-benches --bin collect --release -- --input bench.json运行后会在当前目录生成gas-costs.yaml形如burn: 35 call: base: 311 dep_per_unit: 14从 collect 的源码 可以看到collect是一个 clap 命令行工具完整参数比 README 展示的更丰富参数说明-b, --baseline用作基线的 benchmark ID默认noop/noop-i, --inputcriterion JSON 输入路径支持单文件或整个目录目录内所有文件都会读取缺省为 stdin-o, --output输出路径默认当前目录若给的是目录则按格式自动命名-f, --format输出格式yaml默认/json/rust/consensus-parameters-d, --debug打印输入行与解析出的状态-a, --all对依赖型测量保留所有样本值不能与rust格式共用对应地输出文件按格式自动命名为gas-costs.yaml、gas-costs.json、gas-costs.rs或consensus-parameters.rs见 collect.rs 的 main 函数。成本是如何算出来的从 noop 基线到 DependentCost理解collect的内部逻辑能解释为什么 README 示例中burn: 35这样的数字代表35 个 noop 的耗时。其核心流程在 collect.rs 中基线归一化。每个组group中若存在带 throughput 的成员会被视为依赖型基准否则取组内第一个成员的平均耗时除以基线耗时得到相对成本。基线默认是noop/noop其取值逻辑见get_baseline——若录制中找不到该基线会直接 panic提示你确认录制的完整性。依赖型成本的分型拟合。dependent_cost函数先用最小二乘线性回归求出x/y每单位 noop 能处理多少元素然后依据首尾数据点的分布把曲线分成三类Linear首尾点斜率都接近回归线偏差 20%取首点耗时为base、取最小amount为每单位成本Logarithm/Exp对数型取拐点后的线性段做基准指数型则打印警告不支持指数曲线指令需要设置上界最终若amount 1输出DependentCost::LightOperation { base, units_per_gas }否则输出HeavyOperation { base, gas_per_unit }。存储基准的特殊处理。从源码看swrd_*、srdd_*存储写/读两组还会把小于 32 字节的 slot 样本排除在回归之外MIN_SLOT_SIZE_BYTES避免极小 slot 的固定开销扭曲每字节斜率并且会做冷热一致性 sanity check——例如冷读必须比热读贵、冷写不应比热写便宜异常时向 stderr 打印警告。这些组名最终通过STORAGE_BENCH_REMAPS映射到GasCostsValuesV7的storage_read_hot、storage_read_cold、storage_write、storage_clear字段。Rust 代码生成。以-f rust输出时to_rust_code会把mod、move等与 Rust 关键字冲突的名称重映射为mod_op、move_op把ret_contract等收敛为统一的ret/rvrt/retd对 YAML 中出现但GasCostsValuesV7未覆盖的键打印告警并在文件头写入生成时的 git commit hashgit rev-parse HEAD以便追溯。生成 default-gas-costs.rs 并替换README 的最后一个小节说明了如何把基准结果固化进代码cargo run -p fuel-core-benches --bin collect --release -- --input bench.json -f rust --output default-gas-costs.rs这会按上面的模板在当前目录生成default-gas-costs.rs内容是一个pub fn default_gas_costs() - GasCostsValues函数逐字段填充GasCostsValuesV7。README 说明确认无误后可以替换fuel-vm/src/gas/default-gas-costs.rs在当前仓库中对应角色由 benches/src/default_gas_costs.rs 承担——它以GasCostsValuesV7字面量给出当前默认成本其中既能看到相对成本如burn: 867、ecr1: 31208也能看到依赖型成本如call: DependentCost::LightOperation { base: 780, units_per_gas: 65 }、storage_read_cold: { base: 733, units_per_gas: 31 }与collect的输出结构一一对应。小结这套基准体系的分工很清晰benches/benches/vm.rs 负责在状态每轮回滚、分配器固定、存储嵌套层级贴近生产的条件下精确计时单条 VM 指令collect 工具 负责以noop为基线把纳秒级均值换算为相对 gas 成本并对依赖型指令做线性/对数分型拟合与冷热一致性检查最终产物gas-costs.yaml或default-gas-costs.rs就是 VM gas 计量参数的数据源头。掌握cargo criterion --message-format jsoncollect -f rust这条链路你就能在修改指令实现或存储路径后量化其对 gas 成本的影响并复现一次完整的参数刷新流程。【免费下载链接】fuel-coreRust full node implementation of the Fuel v2 protocol.项目地址: https://gitcode.com/GitHub_Trending/fu/fuel-core创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表