首页/新闻资讯/正文详情

BAML 基准测试 Workload 深度解析:string::split short literal 100k 与字符串 split 性能测试

发布时间:2026/9/25 7:24:15 来源:云帆数科 栏目:资讯中心
BAML 基准测试 Workload 深度解析:string::split short literal 100k 与字符串 split 性能测试
编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载本篇文章以仓库 baml_language/tools/speedtest 中的 Workload 定义文件 split-short-literal-100k.md 为核心完整剖析 BAML 性能基准测试中字符串按分隔符拆分这一测试场景的写法、模板注入机制、跨语言结果校验流程以及底层 bex_vm 中split的零拷贝实现原理。读完本文你将掌握 speedtest 的 Workload 文件格式与 CLI 用法并能看懂 BAML 与 Python/TypeScript 在同一计算负载下的性能对比是如何被设计、运行和核验的。一、Workload 是什么speedtest 基准测试的测试用例格式BAML 仓库自带一套跨语言性能基准工具 speedtestPython 实现入口位于 cli.py。它并不在代码里硬编码基准用例而是把每个用例定义为独立的 Markdown 文件统一存放在baml_language/tools/speedtest/workloads/下按类别分子目录classes/方法调用、方法链compute/斐波那契、冒泡排序、二叉树、闭包、协程等计算密集用例concurrency/并行 sleep、并行 sum、共享数组interfaces/多态分发、字段访问、match 分发string/字符串拼接、contains、split、substring、trim每个 Workload 文件同时给出同一逻辑负载在三种语言中的等价实现BAML、Python、TypeScript。speedtest 会依次编译并运行它们最终输出 BAML 与 Python/Node/Bun 的耗时对比与倍率。本篇文章的主角string::split short literal 100k位于 string/ 目录属于字符串类别。它的测试目标非常聚焦对一个极短的字面量字符串反复执行split并累加结果长度迭代 10 万次用来考察字符串拆分操作在热循环中的开销。其完整原文如下四段式结构这是所有 Workload 的统一骨架# string::split short literal 100k ## eval-setup py import json src hello world foo bar baz qux delim baml_src json.dumps(src) baml_delim json.dumps(delim) py_src repr(src) py_delim repr(delim) js_src json.dumps(src) js_delim json.dumps(delim) ## BAML baml function main() - int { let s $$baml_src; let delim $$baml_delim; let count 0; for (let i 0; i 100000; i 1) { let parts s.split(delim); count parts.length(); }; return count; } ## Python python s $$py_src delim $$py_delim c 0 for _ in range(100000): c len(s.split(delim)) print(c) ## Typescript ts const s $$js_src; const delim $$js_delim; let c 0; for(let i0;i100000;i) c s.split(delim).length; console.log(c); 四个段落的职责分别是段落语言作用## eval-setupPython生成测试数据为后续各语言代码注入字面量## BAMLBAML被测语言的等价实现输出int结果## PythonPython对照实现print结果## TypescriptTypeScript对照实现console.log结果Workload 的解析由 loader.py 完成标题行# ...成为 Workload 名称文件所在父目录名成为类别category path.parent.name四个代码块按小节名被提取并做模板替换。二、eval-setup$$模板注入机制与跨语言转义Workload 文件的关键设计是eval-setup 段只执行一次 Python 代码把变量注入后续三个语言的代码模板。loader.py 中定义了以$$为定界符的模板类class _DDTemplate(Template): Template using $$var instead of $var, so single $ is literal. delimiter $$选择$$作为定界符而非$是为了让模板正文中出现的单个$如字符串内容里的$符号保持字面含义不会被误当作占位符。解析流程loader.py用正则 ^##\s([\w-])\s*\n\w*\n(.*?) 切出各段代码对eval-setup段执行exec(setup, ...)把baml_src、baml_delim、py_src、py_delim、js_src、js_delim等变量装入命名空间用_DDTemplate(code).safe_substitute(namespace)对 BAML/Python/TypeScript 三段做替换得到真正可运行的源码。eval-setup 中针对不同目标语言选用了不同的序列化函数这是有讲究的BAML 与 TypeScript 用json.dumps产生双引号字符串BAML 字面量语法与 JSON 字符串语法一致可直接嵌入Python 用repr产生带单引号的 Python 字面量且对反斜杠等字符的转义方式与 Python 语法严格匹配。json.dumps/repr同时保证特殊字符引号、换行、反斜杠在目标语言中不会被破坏因此同一份 eval-setup 可以安全地把同一数据注入三种语法体系。对本用例而言注入后的 BAML 代码等价于let s hello world foo bar baz qux;、let delim ;。被测字符串含 5 个空格按 拆分恰好得到6 段因此三轮语言的最终输出都是100000 × 6 600000——这个可预先计算的期望值正是下一节跨语言校验的依据。三、BAML 实现逐行解读与 Python/TypeScript 对照BAML 侧function main() - int { let s $$baml_src; // hello world foo bar baz qux let delim $$baml_delim; // let count 0; for (let i 0; i 100000; i 1) { let parts s.split(delim); count parts.length(); }; return count; }function main() - intWorkload 约定入口函数名为main返回intrunner 通过baml-cli pack main将其打包为可执行文件运行时取 stdout 最后一行作为结果let parts s.split(delim)调用 BAML 字符串方法split返回字符串数组parts.length()数组长度外层 10 万次循环保证每次调用都真实执行BAML 编译器不会把循环内与循环外无关的计算折叠掉从而保证被测的是热路径本身。Python 侧s $$py_src delim $$py_delim c 0 for _ in range(100000): c len(s.split(delim)) print(c)Python 的str.split(delim)与 BAML 的s.split(delim)语义对齐都按字符串分隔符切分、返回列表len()取长度。TypeScript 侧const s $$js_src; const delim $$js_delim; let c 0; for(let i0;i100000;i) c s.split(delim).length; console.log(c);TypeScript 的String.prototype.split同样返回数组length取长度。三段代码的负载结构完全同构同一字符串、同一分隔符、同一迭代次数、同一累加逻辑这是后续跨语言公平对比的前提。与内联字面量变体的区别string 类别下还有一个不依赖 eval-setup 的变体 string-split-100k.md它没有## eval-setup段直接把字面量写死在各语言代码中BAML 里let s hello world foo bar baz qux;。区别在于本用例通过模板注入保证三份代码拿到的是同一份经转义的数据内联变体省去了注入环节更贴近源码中直接写死字面量的常见写法也少了一层解释器解析开销。两类用例互为补充共同覆盖字面量来自变量与字面量写死在源码两种真实场景。四、从 Workload 到基准结果runner 的完整流水线Workload 文件只是配方真正的执行与计时在 runner.py 中完成主要分四步1. 打包 BAML 为独立可执行文件def pack_baml(binary, baml_file, output_path): result subprocess.run( [binary, pack, main, --file, baml_file, -o, output_path], ... )runner 调用baml-cli pack mainrunner.py把 BAML 源码连同main入口编译打包成独立二进制后续计时直接运行该二进制排除了解释启动与源码解析的干扰。2. 跨语言输出一致性校验基准测试的第一道关卡是正确性如果 BAML 的输出与 Python/Node/Bun 不一致说明三个实现并未执行同一语义测出的耗时对比毫无意义。runner 会依次运行打包后的 BAML、python3 -S、node、bun取各自 stdout 最后一行对比runner.pyfor lang, cmd in checks: out get_output(cmd) if out is not None and out ! expected: sys.stderr.write(f MISMATCH: baml{expected}, {lang}{out}\n) row[mismatch] True若出现MISMATCH该行结果会被标记(!)。对本用例而言三者都应输出600000。3. 自适应计时与固定次数计时计时分两种模式runner.py自适应模式默认目标测量时长为--measurement-time默认 5 秒。先丢弃 3 次预热运行预热 OS 缓存/CPU用预热中位数估算单次耗时再反推需要采样的次数并夹取到[min_samples5, max_samples100]固定次数模式--runs N指定每个 Workload 固定跑 N 次。结果以中位数median为准同时记录标准差、样本数与 min/max最终汇总为 Markdown 表格列Benchmark、baml、python3、baml/py、node、baml/node、bun、baml/bun并按类别分组展示。4. 保存结果与基线每次运行的数据会存入结果目录默认~/.speedtest/并更新baselines/branch/latest可用--tag打标签类似基准的 git tag。同时支持--profile samply 对 profiling 版 baml-cli 录制 CPU 火焰图数据。相关 CLI 参数参数说明默认值--build先cargo build --release -p baml_pack_host -p baml_cli再测关闭--filter只运行名称包含子串的 Workload可重复指定全部--only-baml跳过 python/node/bun只测 BAML关闭--runs N固定采样次数覆盖自适应计时自适应--measurement-time SECS每个 Workload 自适应计时的目标秒数5.0--baml PATH指定 baml-cli 路径默认target/release/baml-cli自动探测--tag NAME给本次运行打标签无--profile/--profile-baml用 samply 录制 BAML profiling 火焰图关闭--results-dir PATH结果保存目录~/.speedtest/CLI 定义见 cli.py还提供compare、open、list、baselines子命令。例如只跑本用例speedtest run --filter split-short-literal-100k --build五、源码原理bex_vm 中零拷贝zero-copy的 split 实现为什么这个基准值得专门测因为 BAML 的split不是普通的切完复制实现而是零拷贝切片。实现在 bex_vm/src/package_baml/string.rs// Zero-copy: each segment is a zero-copy substring Slice into the original. fn split(string: BexStr, delimiter: BexStr) - VecBexStr { let s string.as_str(); let d delimiter.as_str(); if d.is_empty() { return char_substrings(string); } let base s.as_ptr() as usize; s.split(d) .map(|part| { let start part.as_ptr() as usize - base; string.substring(start, start part.len()) }) .collect() }关键细节基于 Rust 标准库str::split按分隔符迭代出各段str指针算术定位用part.as_ptr() - base计算出每个切片段在原字符串中的字节偏移再调用substring零拷贝切片BexStr内部是Inline / Flat / Slice / Concat四变体枚举见 bex_str.rs其中Slice持有一个始终是 Flat 的 parent、offset与len不复制字节内容只记录视图元数据空分隔符特判delimiter为空时按char_indices切分成单个字符子串char_substrings与常见语言中空分隔符按字符切分的语义一致。这意味着在本用例的 10 万次循环里每次s.split(delim)都不产生字符串内容的拷贝——切出来的 6 段都是指向原字面量的Slice视图内存分配被大幅压缩bex_str/src/tests.rs中也直接以matches!(s1, BexStr::Slice { .. })断言切片结果见 tests.rs。这也解释了为什么基准要同时跑string-split-100k字面量写死与split-short-literal-100k字面量来自模板变量——两者在是否能走内联/切片优化路径上存在细微差异需要分别测量。六、分档设计与其他 string 类别 Workload 的横向对比split基准在 string 类别下按字面量长度 × 迭代次数分了三档形成一组受控变量实验Workload 文件被测字符串分隔符迭代次数每轮切分段数split-short-literal-100k.mdhello world foo bar baz qux短 100,0006split-medium-literal-10k.md8 个 chunk 以\|连接中\|10,0008split-long-literal-1k.md10 个长 chunk 以###连接长###1,00010三档保持切分段数同一量级同时让单次 split 扫描的字节数递增、迭代次数递减从而把拆分短字符串的调用开销与拆分长字符串的扫描开销分开量化——前者主要考验函数调用/数组分配/切片视图构造后者主要考验字符串扫描本身。这也是 string/ 目录 整体命名规范short/medium/long 迭代次数的设计意图用可控变量拆解性能瓶颈。七、运行、对比与结果解读单跑本用例# 先构建 baml-cli 与 pack_host再只跑本 Workload speedtest run --build --filter split-short-literal-100k # 跳过对照语言只看 BAML 自身耗时 speedtest run --only-baml --filter split-short-literal-100k # 固定采样 10 次覆盖自适应计时 speedtest run --filter split-short-literal-100k --runs 10两次运行对比speedtest run --tag before # 打基线标签 speedtest run --tag after # 改动后再次运行 speedtest compare before aftercompare采用 critcmp 风格的终端 diffcompare.py按类别分组展示两轮的中位数、变化百分比用统计显著性标记sig_marker基于中位数与标准差与5%阈值区分显著变化/噪声变化若两份记录的 BAML 源码不一致还会标注(src changed)防止拿不同代码比出无意义结果。compare还内置_render_md路径可直接输出 Markdown 表格便于贴进文档或 CI 报告。读取结果speedtest list # 列出全部 Workload 名称 speedtest baselines # 查看已保存的基线 speedtest open # 打开浏览器 UI 查看结果小结string::split short literal 100k是 BAML 性能基准体系中一个典型的最小化受控用例它用四段式 Markdown 同时承载 BAML、Python、TypeScript 三种等价实现通过$$模板机制与json.dumps/repr转义保证三端拿到同一数据再经 runner 的打包、跨语言输出校验、自适应计时与基线存档最终量化 BAML 在短字符串高频拆分场景下的相对性能。配合 bex_vm 的零拷贝 split 实现 与 BexStr 切片设计这套基准不仅能回答快不快更能解释为什么快——这正是它的设计价值所在。赞分享编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载相关推荐Rakam-API高级功能Webhook集成与实时事件处理Rakam API高级功能Webhook集成与实时事件处理 在当今数据驱动的世界中 实时事件处理 和 Webhook集成 已成为现代应用分析的核心需求编程语言AI Agent编译器CLI人工智能3小时做出会回应的虚拟桌宠VPet零基础定制完整指南3小时做出会回应的虚拟桌宠VPet零基础定制完整指南 你可能不知道一只桌宠的全部生命就是一堆 PNG 图片和几行文本配置。VPet Simulator桌面应用游戏开发awesome-computer-vision 资源获取完整指南一份清单搞定论文、数据集与工具库awesome computer vision 资源获取完整指南一份清单搞定论文、数据集与工具库 刚进入计算机视觉CV方向时你大概率遇到过这种状况论文编程语言AI Agent编译器CLI人工智能上一篇CANN Ascend C权重形状设置API下一篇Applera1n iOS激活锁绕过工具终极完整教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关推荐

cyrus-sasl 2.1.21编译与配置:从源码包到SMTP/LDAP认证实战
cyrus-sasl 2.1.21编译与配置:从源码包到SMTP/LDAP认证实战

简介:这是Cyrus SASL 2.1.21的源码压缩包,面向邮件系统运维、后端开发及安全测试人员,用于为SMTP/IMAP/POP3等服务搭建可扩展的认证与安全层,重点解决Postfix邮件服务器在发送与接收环节的SASL认证配置问题。资源共620个文件&… · 2026/9/25 7:24:15

python的智能制造导论工业场景模拟第一百一十五篇:搭建离散事件仿真,模拟多品种混线生产,统计在制品库存,评估不同排产策略库存压力。
python的智能制造导论工业场景模拟第一百一十五篇:搭建离散事件仿真,模拟多品种混线生产,统计在制品库存,评估不同排产策略库存压力。

离散事件仿真:多品种混线生产,统计在制品库存,评估不同排产策略库存压力周四上午,生产计划员小刘把三张工单甩在会议桌上,脸色不太好看。"这个月第三条线要同时跑A、B、C三种产品,订单量分别是A 500件… · 2026/9/25 7:24:09

Atlas 300V 24G部署YOLO全流程:昇腾推理卡架构解析与实战避坑
Atlas 300V 24G部署YOLO全流程:昇腾推理卡架构解析与实战避坑

很多人第一次拿到 Atlas 300V 24G 这块卡的时候,第一反应都是:这玩意儿是不是跟显卡一样,插上就能用?然后照着网上那一堆基于 CUDA 写出来的 YOLO 部署教程去操作,下载个 PyTorch,pip install ultralytics&… · 2026/9/25 7:24:03

SVM检测恶意URL:37维手工特征与线性核工程实践
SVM检测恶意URL:37维手工特征与线性核工程实践

简介:本资源是一套基于机器学习的恶意URL检测实战项目,面向计算机、人工智能、大数据等专业的本科生及初阶开发者,适用于课程设计、毕业设计与安全算法入门实践。项目完整实现从URL特征提取、模型训练(含SVM等经典算法&#xff09… · 2026/9/25 7:53:39

Atlas 300V 24G推理加速卡上高效部署YOLOv5全流程指南
Atlas 300V 24G推理加速卡上高效部署YOLOv5全流程指南

先来说个真实经历。入职第二年接手了一个园区安防项目,甲方丢过来一批盒子,点名要跑YOLOv5做实时检测,厂家给的资料就一行字:Atlas 300V 24G推理卡。当时团队里没人碰过昇腾,第一反应是这卡到底能不能用来训练&#xf… · 2026/9/25 7:53:39

SQL注入绕过登录原理与防御:从拼接逻辑到实战靶场
SQL注入绕过登录原理与防御:从拼接逻辑到实战靶场

第一次在 PortSwigger Academy 上做 SQL 注入绕过登录(Login Bypass)这个实验的时候,我其实有点不以为然。万能密码这东西听起来像十几年前的考古内容,总觉得在参数化查询、ORM 普及的今天,早就没什么实战价值了。但真… · 2026/9/25 7:53:39

Atlas 300V 24G NPU上部署YOLO:从环境配置到性能优化
Atlas 300V 24G NPU上部署YOLO:从环境配置到性能优化

最近有人问我“Atlas”是什么,说实话第一反应是数据库中间件那头大象,结果他后面跟了一句“部署YOLO”,又补了个“300V 24G”,我立马就明白他说的其实是昇腾Atlas系列的AI加速卡。这名字在AI领域有点被说烂了,因为它既… · 2026/9/25 7:53:33

昇腾Atlas 300V 24G加速卡部署YOLO全流程实战
昇腾Atlas 300V 24G加速卡部署YOLO全流程实战

1. 先搞清楚Atlas 300V 24G的定位:是加速卡,但不是你以为的那种加速卡1.1 一张卡解决什么问题看到热搜里连续出现“atlas部署yolo”和“atlas 300v 24g 是运算加速卡吗”这两条,我就知道又有一批做边缘AI或服务器推理的同学被这张卡吸引过来了… · 2026/9/25 7:53:27

ExternalDNS 与 AWS Load Balancer Controller 集成实战:ALB/NLB Ingress 的 DNS 自动化管理
ExternalDNS 与 AWS Load Balancer Controller 集成实战:ALB/NLB Ingress 的 DNS 自动化管理

云原生 【免费下载链接】external-dns Configure external DNS servers dynamically from Kubernetes resources 项目地址: https://gitcode.com/gh_mirrors/ex/external-dns 点击查看 免费下载 ExternalDNS 与 AWS Load Balancer Controller(原 ALB In… · 2026/9/25 7:53:20

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码