motoko-benchmarks-generation
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMotoko Benchmarks with bench‑helper
使用bench‑helper进行Motoko基准测试
What This Is
这是什么
bench-helperrun(row, col)bench/*.bench.mobench-helperrun(row, col)bench/*.bench.moPrerequisites
前提条件
mops.toml (add dependencies and toolchain)
If you already have a , just add under .
If your project still uses instead of , you can keep it — benches themselves can be written with
without affecting your runtime canisters.
mops.tomlbench-helper[dev-dependencies]mo:basemo:coremo:basemops.toml(添加依赖项和工具链)
如果你已经有,只需在下添加。如果你的项目仍在使用而非,可以继续保留——基准测试本身可以用编写,不会影响你的运行时容器(canister)。
mops.toml[dev-dependencies]bench-helpermo:basemo:coremo:baseDirectory & File Conventions
目录与文件约定
- Put benches under at the repo root.
bench/ - Name files with the suffix , one benchmark per file; for example:
.bench.mo.bench/base64.bench.mo - Each bench file is a Motoko that exposes a single
module { ... }function.public func init() : Bench.V1 - Inside , construct a
initand returnBench.SchemawhereBench.V1(schema, run)performs the measured operation.run : (rowIndex : Nat, colIndex : Nat) -> ()
Minimal skeleton
motoko
import Array "mo:core/Array";
import Text "mo:core/Text";
import Bench "mo:bench-helper";
module {
public func init() : Bench.V1 {
let schema : Bench.Schema = {
name = "My bench";
description = "What this bench measures";
rows = ["size 16", "size 64", "size 256"]; // your row labels
columns = ["operation A", "operation B"]; // your column labels
};
// Prepare inputs outside of `run` so they are not re-created on every iteration
let inputs : [[Nat8]] = [
Array.init<Nat8>(16, 0),
Array.init<Nat8>(64, 0),
Array.init<Nat8>(256, 0),
];
// Build a table of routines to measure: routines[row][col] : () -> ()
let routines : [[() -> ()]] = Array.tabulate(
rows.size(),
func(ri) {
let input = inputs[ri]; // capture precomputed input
[
func() { ignore input.size() }, // operation A @ inputs[ri]
func() { ignore input.toArray() }, // operation B @ inputs[ri]
]
},
);
// The runner calls this many times; keep it tiny and branch-free.
Bench.V1(schema, func(ri : Nat, ci : Nat) = routines[ri][ci]());
};
};Note: if you're not using "core" dependency, replace "mo:core" imports with "mo:base"
- 将基准测试放在仓库根目录的文件夹下。
bench/ - 文件命名以为后缀,每个文件对应一个基准测试;例如:
.bench.mo。bench/base64.bench.mo - 每个基准测试文件是一个Motoko ,暴露一个单独的
module { ... }函数。public func init() : Bench.V1 - 在内部,构建一个
init并返回Bench.Schema,其中Bench.V1(schema, run)执行被测量的操作。run : (rowIndex : Nat, colIndex : Nat) -> ()
最小化骨架
motoko
import Array "mo:core/Array";
import Text "mo:core/Text";
import Bench "mo:bench-helper";
module {
public func init() : Bench.V1 {
let schema : Bench.Schema = {
name = "My bench";
description = "What this bench measures";
rows = ["size 16", "size 64", "size 256"]; // 你的行标签
columns = ["operation A", "operation B"]; // 你的列标签
};
// 在`run`之外准备输入,避免每次迭代都重新创建
let inputs : [[Nat8]] = [
Array.init<Nat8>(16, 0),
Array.init<Nat8>(64, 0),
Array.init<Nat8>(256, 0),
];
// 构建要测量的例程表:routines[row][col] : () -> ()
let routines : [[() -> ()]] = Array.tabulate(
rows.size(),
func(ri) {
let input = inputs[ri]; // 捕获预计算的输入
[
func() { ignore input.size() }, // 操作A @ inputs[ri]
func() { ignore input.toArray() }, // 操作B @ inputs[ri]
]
},
);
// 运行器会多次调用此函数;保持函数简洁且无分支。
Bench.V1(schema, func(ri : Nat, ci : Nat) = routines[ri][ci]());
};
};注意:如果你没有使用“core”依赖项,请将“mo:core”导入替换为“mo:base”
How It Works
工作原理
- Schema
- and
namedescribe the bench.description - enumerate different operations or variants you measure (e.g., "encode", "decode").
rows - enumerate different input categories (e.g., message sizes).
cols
- Runner contract
- You return a versioned record ; the runner calls
Bench.V1(schema, run)many times to record timings.run(rowIndex, colIndex) - Side effects/results inside should be consumed (e.g.,
run) to prevent dead‑code elimination.ignore ...
- You return a versioned record
- 模式(Schema)
- 和
name描述基准测试。description - 列举你要测量的不同操作或变体(例如:"encode"、"decode")。
rows - 列举不同的输入类别(例如:消息大小)。
cols
- 运行器约定
- 你返回一个带版本的记录;运行器会多次调用
Bench.V1(schema, run)以记录计时。run(rowIndex, colIndex) - 内部的副作用/结果应该被消耗(例如:
run),以防止死代码消除。ignore ...
- 你返回一个带版本的记录
Common Pitfalls
常见陷阱
- Rows/cols mismatch
- Ensure your table has dimensions
routines. If you add or remove a row/col label, update how you buildrows.size() x cols.size(); otherwise some cells will be no‑ops.routines
- Ensure your
- Doing expensive setup inside
run- Generate inputs once in and capture them in closures. Only do the core operation in
init.run
- Generate inputs once in
- Forgetting to consume results
- Use to consume return values; otherwise the compiler might drop the call as dead code.
ignore
- Use
- Non‑determinism and timing noise
- Keep free of logging/printing and random allocation; keep GC pressure comparable across rows.
run
- Keep
- 行/列不匹配
- 确保你的表的维度为
routines。如果你添加或删除了行/列标签,请更新rows.size() x cols.size()的构建方式;否则某些单元格将成为空操作。routines
- 确保你的
- 在内部执行昂贵的设置操作
run- 在中生成一次输入,并在闭包中捕获它们。仅在
init中执行核心操作。run
- 在
- 忘记消耗结果
- 使用来消耗返回值;否则编译器可能会将调用视为死代码而丢弃。
ignore
- 使用
- 非确定性和计时噪声
- 确保中没有日志/打印和随机分配操作;保持各行的GC压力相当。
run
- 确保
More examples
更多示例
bench-helper reference benches: https://github.com/research-ag/bench-helper/tree/main/bench
bench-helper参考基准测试:https://github.com/research-ag/bench-helper/tree/main/bench
Verify It Works
验证运行效果
The exact runner/command may vary depending on your environment. After adding to and writing
files:
bench-helpermops.toml.bench.mo- Ensure your project resolves dependencies:
bash
mops install - Run benchmarks:
bash
mops bench - Consult the package README for the latest recommended runner command for your toolchain/version.
bench-helper
具体的运行器/命令可能因环境而异。在将添加到并编写文件后:
bench-helpermops.toml.bench.mo- 确保项目已解析依赖项:
bash
mops install - 运行基准测试:
bash
mops bench - 查阅包的README文档,获取适用于你的工具链/版本的最新推荐运行器命令。
bench-helper