Taichi 微基准测试套件(benchmarks)完全指南:安装、运行、结果解析与性能可视化
2026/9/10 10:34:18 网站建设 项目流程

Taichi 微基准测试套件(benchmarks)完全指南:安装、运行、结果解析与性能可视化

【免费下载链接】taichiProductive, portable, and performant GPU programming in Python.项目地址: https://gitcode.com/GitHub_Trending/ta/taichi

导读

Taichi 仓库的benchmarks目录提供了一套面向多后端(CUDA / Vulkan / OpenGL 等)的官方微基准测试(microbenchmark)框架,覆盖填充(fill)、内存拷贝(memcpy)、SAXPY、原子操作(atomic ops)、数学函数吞吐(math ops)、矩阵运算(matrix ops)与 2D 模板计算(stencil 2D)等典型负载。本文以 benchmarks/README.md 为主线,结合benchmarks目录下的源码实现,完整讲解这套基准测试的安装、运行、结果序列化与可视化流程,并深入剖析其测试用例生成机制与计时原理,帮助你在自己的机器上复现结果并读懂 Taichi 的性能数据。


一、benchmarks 目录结构与整体工作流

在动手运行之前,先了解benchmarks目录的组织方式,这有助于理解后续每一步命令背后发生了什么:

benchmarks/ ├── README.md # 官方使用说明(本文主体) ├── requirements.txt # 额外依赖:jsbeautifier、bokeh ├── run.py # 入口:运行全部基准测试并保存结果 ├── deserialize.py # 将分散的结果文件合并为单个 results.json ├── suite_microbenchmarks.py # MicroBenchmark 套件定义与结果落盘逻辑 ├── utils.py # JSON 美化输出、时间戳等公共工具 └── microbenchmarks/ # 各测试计划与基础设施 ├── _plan.py # BenchmarkPlan:用例生成与调度核心 ├── _items.py # 测试维度(数据类型、数据规模、容器、算子等) ├── _metric.py # 计时指标(内核耗时 / 端到端耗时) ├── _utils.py # 计时器、标签工具、架构映射、随机填充 ├── atomic_ops.py # 原子操作(归约)测试 ├── fill.py # 填充测试(含稀疏结构) ├── math_opts.py # 一元数学函数吞吐测试 ├── matrix_ops.py # 矩阵加 / 乘 / 乘加测试 ├── memcpy.py # 内存拷贝测试 ├── saxpy.py # SAXPY 测试 └── stencil2d.py # 2D 模板计算(gather / scatter / BLS)

整体工作流为:安装依赖 → 运行run.py生成./results目录 → 用deserialize.py合并为单个 JSON → 用可视化工具(基于 Bokeh)交互式查看性能数据。下面按这个流程逐一展开。


二、环境准备与额外依赖安装

按照 benchmarks/README.md 的说明,运行基准测试需要先安装少量额外依赖:

python3 -m pip install -r requirements.txt

其中 benchmarks/requirements.txt 内容只有两个包:

  • jsbeautifier:用于美化 JSON 输出。在 benchmarks/utils.py 的dump2json()中,通过jsbeautifier.beautify(json.dumps(...), options)将结果格式化为缩进 4 空格的易读 JSON;
  • bokeh:可视化工具库。文档中可视化脚本的默认地址为localhost:5006/visualization,这正是 Bokeh Server 的默认端口(5006),说明可视化环节依赖 Bokeh 服务。

此外,基准测试脚本在 benchmarks/run.py 中导入taichi._lib.core,因此你还需要一个可用的 Taichi Python 环境(即当前仓库对应的已安装版本)。建议在 Taichi 已正确安装的虚拟环境中执行上述命令。


三、运行全部基准测试

安装完依赖后,在benchmarks目录下执行:

python3 run.py

这是官方文档给出的唯一启动入口。根据 benchmarks/run.py 的源码,整个运行过程可以拆解为三步:

  1. 记录环境信息BenchmarkInfo通过ti_python_core.get_commit_hash()获取当前 Taichi 的 commit hash,并记录带格式的时间戳(见 benchmarks/utils.py 的datatime_with_format(),输出 ISO 格式时间);
  2. 创建并运行套件BenchmarkSuites实例化benchmark_suites列表中的套件并依次调用run()。当前 benchmarks/run.py 中注册的套件只有一个MicroBenchmark
  3. 落盘保存suites.save(benchmark_dir)将结果写入os.path.join(os.getcwd(), "results"),最后把包含 commit hash、时间与套件信息的_info.json一并写入results目录。

注意 benchmarks/run.py 使用os.getcwd()拼接结果路径,因此结果文件夹results会生成在你执行命令时的当前目录下,而不是固定的benchmarks/results。若希望在仓库内统一管理,可以先cd到目标目录再运行。

3.1 默认启用的后端

需要特别留意 benchmarks/suite_microbenchmarks.py 中MicroBenchmark.config的默认配置:

config = { "cuda": {"enable": True}, "vulkan": {"enable": False}, "opengl": {"enable": False}, }

即默认只对 CUDA 后端执行测试,Vulkan 与 OpenGL 默认关闭。如果需要测试其他后端,需要修改该config字典将对应项置为Trueget_benchmark_info()会据此生成启用的架构列表,run()也只遍历 enable 为 True 的架构)。底层架构映射见 benchmarks/microbenchmarks/_utils.py 的get_ti_arch(),它支持的键包括cudavulkanopenglmetalx64cc。换句话说,如果你当前机器没有可用的 CUDA 环境,需要自行将cuda关闭并把vulkan/opengl(或x64)打开后才能跑通。

3.2 结果落盘结构

运行完成后,results目录的布局如下(由 benchmarks/suite_microbenchmarks.py 的save_as_json()决定):

results/ ├── _info.json # 顶层信息:commit_hash、datetime、suites └── microbenchmarks/ # 套件目录(suite_name) └── cuda/ # 架构目录 ├── _info.json # 该架构下各 case 的维度 tags 信息 ├── atomic_ops.json # 每个测试计划一个 JSON ├── fill.json ├── math_ops.json ├── matrix_ops.json ├── memcpy.json ├── saxpy.json └── stencil_2d.json

其中run.py最后写入的顶层 [results/_info.json] 包含suites字段,其结构为{suite_name: {archs: [...]}},供后续deserialize.py索引使用。


四、源码级剖析:微基准测试套件的内部机制

理解这套基准测试的输出格式,关键在于掌握 benchmarks/microbenchmarks/_plan.py 的用例生成机制与各测试计划的维度组合。

4.1 七个内置测试计划

benchmarks/microbenchmarks/init.py 中定义了benchmark_plan_list,共 7 个测试计划:

计划类测试主题定义文件
AtomicOpsPlan原子操作归约microbenchmarks/atomic_ops.py
FillPlan常量填充(含稀疏结构)microbenchmarks/fill.py
MathOpsPlan一元数学函数吞吐microbenchmarks/math_opts.py
MatrixOpsPlan矩阵加 / 乘 / 乘加microbenchmarks/matrix_ops.py
MemcpyPlan内存拷贝microbenchmarks/memcpy.py
SaxpyPlanSAXPY(z = 17*x + ymicrobenchmarks/saxpy.py
Stencil2DPlan2D 模板计算(gather / scatter / BLS)microbenchmarks/stencil2d.py

4.2 用例生成:维度笛卡尔积

每个计划继承BenchmarkPlan,通过create_plan(*items)将多个**维度(BenchmarkItem)**做笛卡尔积生成全部用例(benchmarks/microbenchmarks/_plan.py):

case_list = list(itertools.product(*items_list))

每个用例用tags2name()(benchmarks/microbenchmarks/_utils.py)将标签列表用下划线拼接成唯一名称,例如saxpy_field_f32_16KB_end2end_time_ms。所有用例存放在self.plan字典中,result字段初始为None,运行后被填充为实际测得的毫秒数。

Funcs类实现了一套基于标签子集匹配的函数分发机制(benchmarks/microbenchmarks/_plan.py):add_func(tag_list, func)注册某个实现函数及其标签,get_func(tags)返回标签是当前用例标签子集的第一个函数。这正是fillstencil_2d等计划能够为fieldndarraysparse分别提供不同 kernel 实现的原因。

4.3 公共测试维度

由 benchmarks/microbenchmarks/_items.py 定义,各计划共享以下维度:

  • DataType(dtype)i32i64f32f64四种类型。remove_integer()可去掉整型(math_ops 只用浮点);remove(["i64","f64"])可限制为i32/f32(matrix_ops 如此);
  • DataSize(dsize):按size_bytes = (4**i) * 1024(i 取 2、4、6、8)生成16KB、256KB、4MB、64MB四档数据规模,标签由size2tag()(benchmarks/microbenchmarks/_utils.py)格式化为16KB等;
  • Container(container)fieldti.field)与ndarrayti.ndarray)两种容器,fill 与 stencil_2d 还会额外追加sparse(稀疏结构,实现为None占位,由专门函数处理);
  • MetricType(get_metric):计时指标,详见 4.5 节。

4.4 各计划的特有维度与 kernel 实现

SAXPY(saxpy.py):维度为Container × DataType × DataSize × MetricType。kernel 为z[i] = 17 * x[i] + y[i],元素数为dsize / dtype_size / 3(三份数组)。fieldsaxpy_field(模板参数),ndarraysaxpy_arrayti.types.ndarray()参数)。

Memcpy(memcpy.py):维度同上。kernel 为dst[I] = src[I]ti.grouped遍历),元素数为dsize / dtype_size / 2

Fill(fill.py):维度为Container × DataType × DataSize × MetricTypecontainer额外含sparse。稠密填充 kernel 将每个元素赋值为ti.cast(0.7, dtype)fill_sparse使用ti.root.pointer(...).dense(...)构建稀疏结构,先通过ti.activate(block, [i])激活全部块再填充,且 repeat 基数固定为 1。

AtomicOps(atomic_ops.py):维度为AtomicOps × Container × DataType × DataSize × MetricTypeAtomicOps完整包含atomic_add / sub / and / or / xor / max / min七种原子操作,但AtomicOpsPlan构造时remove(["atomic_sub","atomic_and","atomic_xor","atomic_max"])实际测试 atomic_add、atomic_or、atomic_min 三种。测试形态为原子归约:atomic_op(y[None], x[i])。由于and/or/xor是逻辑操作、只支持整型,_remove_conflict_items()(benchmarks/microbenchmarks/_plan.py)会在生成阶段剔除“逻辑原子操作 × 浮点类型”的非法组合。

MathOps(math_opts.py):维度为MathOps × DataType(浮点) × ElementNum × ForLoopCycle × MetricTypeMathOps覆盖 14 个一元函数:sin、cos、tan、asin、acos、tanh、sqrt、rsqrt、exp、log、round、floor、ceil、absForLoopCycle生成 8/16/32/64/128/256 六档内层循环次数;每个元素是一个 16 分量向量(local_data_num = 16),用于填满指令流水线。该测试关注的是一元算子的吞吐上限而非访存带宽。

MatrixOps(matrix_ops.py):维度为MatrixOps × BlockMN × ElementNum × DataType(i32/f32) × MetricTypeMatrixOps提供mat_addA+B)、mat_mulA@B)、mat_mmaA@B+C)三种@ti.funcBlockMN为 1×1、2×2、3×3、4×4 四种分块;每个元素执行 2048 轮 × 4 次矩阵操作。

Stencil2D(stencil2d.py):维度为Scatter × BloclLocalStorage × Container × DataType × DataSize2D × MetricType,是维度最丰富的计划。Scatter区分scattery[I+offset] += x[I])与gether(gather,y[I] = Σ x[I+offset]);BloclLocalStorage控制是否开启块局部存储(BLS),dsize_2d为 128×128、512×512、2048×2048、8192×8192 四档。sparse分支通过ti.block_local(x/y)ti.block_dim(64)实现带 BLS 的稀疏模板测试,且仅对 16KB~64MB 之间的规模生效(否则返回None)。源码注释还引用了tests/python/bls_test_template.py作为 BLS 用法的参考实现。

4.5 计时指标:内核耗时与端到端耗时

benchmarks/microbenchmarks/_metric.py 定义了两种指标,两者都先执行若干次预热(compile & warmup),再正式计时:

  • kernel_elapsed_time_ms:调用ti.init(kernel_profiler=True, ...)初始化,计时前ti.profiler.clear_kernel_profiler_info(),随后用ti.profiler.get_kernel_profiler_total_time()取得纯 kernel 执行时间。它排除了启动与调度开销,只统计 GPU/后端内核实际执行耗时;
  • end2end_time_ms:调用ti.init(kernel_profiler=False, ...),使用 benchmarks/microbenchmarks/_utils.py 的End2EndTimer,基于time.perf_counter()并在tick/tock前后各调用一次ti.sync(),统计包含启动开销在内的完整调用耗时。

两者最终都换算为单次平均毫秒数:total_time * 1000 / repeat

另外,benchmarks/microbenchmarks/_utils.py 的scaled_repeat_times()会按环境放大重复次数以稳定测量:

if (arch == "cuda") | (arch == "vulkan") | (arch == "opengl"): repeat *= 10 # GPU 后端重复 10 倍 if datasize <= 4 * 1024 * 1024: repeat *= 10 # 数据 ≤ 4MB 时再重复 10 倍

所有计划的basic_repeat_times默认为 10(稀疏类用例固定为 1),小规模数据在 GPU 上最多会重复 1000 次,以降低计时噪声。


五、结果序列化:deserialize.py 合并为单个 JSON

run.py生成的是分散在多个目录、多个文件中的结果。若需要把全部结果合并为单个 JSON 文件便于脚本分析或归档,使用 benchmarks/deserialize.py:

python3 deserialize.py

默认将合并结果写入./results/results.json。也可以显式指定输入结果目录与输出路径:

python3 deserialize.py --folder PATH_OF_RESULTS_FOLDER --output_path PATH_YOU_WIHS_TO_STORE

两个参数(benchmarks/deserialize.py)说明如下:

  • -f, --folder:结果文件夹路径,默认./results
  • -o, --output_path:输出目录(最终生成<output_path>/results.json),默认./results

从源码看,ResultsBuilder的合并逻辑分两层:

  1. 读取顶层_info.jsonsuites字段,按suite_name → arch → case建立索引,并读取每个架构目录下的_info.json与各 case 的 JSON 文件;
  2. 对每个 case 的结果,去掉首位的 case 名称标签(data["tags"] = data["tags"][1:]),并剔除resultNone的条目(benchmarks/deserialize.py)——这正是稀疏模板等场景下因规模不适用而跳过用例的占位结果。

合并完成后,脚本还会调用print_info()打印一份去掉results字段的概要信息,方便你快速核对本次测试覆盖了哪些架构与用例。输出 JSON 统一使用 benchmarks/utils.py 的dump2json()做美化格式化。


六、性能可视化:交互式查看基准结果

拿到合并或分散的结果后,官方文档提供了一个基于 Bokeh 的可视化工具,用于交互式剖析性能问题:

python3 visualization.py

默认读取./results目录,也可指定结果文件路径:

python3 visualization.py --folder PATH_OF_RESULTS_FOLDER

默认服务地址为localhost:5006/visualization(5006 是 Bokeh Server 的默认端口,这也是requirements.txt需要安装 bokeh 的原因)。如需远程访问,可显式指定监听地址与端口:

python3 visualization.py --host YOUR_IP_ADDRESS --port PORT_YOU_WISH_TO_USE

需要说明的是:当前仓库快照的benchmarks/目录中并未包含visualization.py脚本本体(文档保留了对该工具的使用说明),因此若你的检出中缺少该文件,可以:

  • 先依赖deserialize.py生成的results.json做离线分析;
  • 或在本地基于 Bokeh 自行实现同接口的可视化脚本(默认--folder ./results--host localhost--port 5006)。

无论如何,resultsresults.json中的结构化数据(每项包含tagsresult(毫秒)、指标类型等)都足够支撑自定义绘图。


七、扩展与自定义:从源码出发新增测试计划

这套框架的扩展点非常清晰,如果你想新增一个微基准测试,可以参考既有计划的写法:

  1. benchmarks/microbenchmarks/下新建模块,定义继承BenchmarkPlan的计划类,在__init__中:
    • 调用super().__init__("your_plan_name", arch, basic_repeat_times=...)
    • create_plan(...)组合需要的维度(可复用ContainerDataTypeDataSizeMetricType,或自定义BenchmarkItem);
    • add_func(tag_list, func)注册实现函数,必要时用remove_cases_with_tags()剔除不合理的组合;
  2. 在 benchmarks/microbenchmarks/init.py 的benchmark_plan_list中注册新计划;
  3. 按需在 benchmarks/suite_microbenchmarks.py 的MicroBenchmark.config中调整启用的后端。

实现函数遵循统一签名:def func(arch, repeat, ..., get_metric),最终调用get_metric(repeat, kernel, *args)返回毫秒耗时(参考 benchmarks/microbenchmarks/saxpy.py)。


八、快速参考:命令速查表

目的命令说明
安装额外依赖python3 -m pip install -r requirements.txt安装 jsbeautifier 与 bokeh
运行全部基准python3 run.py生成./results目录(默认仅 CUDA 后端)
合并结果为单 JSONpython3 deserialize.py输出./results/results.json
指定输入输出python3 deserialize.py --folder DIR --output_path OUT_DIR自定义合并路径
启动可视化python3 visualization.py默认localhost:5006/visualization
远程可视化python3 visualization.py --host IP --port PORT开放远程访问

运行前请确认:已安装与当前仓库匹配的 Taichi Python 包;benchmarks目录是执行命令的工作目录(或注意results会写入当前工作目录);本机具备默认启用的 CUDA 后端,否则需按第三节调整MicroBenchmark.config

【免费下载链接】taichiProductive, portable, and performant GPU programming in Python.项目地址: https://gitcode.com/GitHub_Trending/ta/taichi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询