InfoQ Geekathon 大模型技术应用创新大赛 了解详情
写点什么

6 种 WebAssembly 的优化手段

作者:Matt Butcher, Radu Matei

  • 2023-03-31
    北京
  • 本文字数:3661 字

    阅读完需:约 12 分钟

6种WebAssembly的优化手段

简称为 Wasm 的 WebAssembly 是一种二进制格式,包括 Rust、C、JavaScript、Python、Ruby、.NET 在内等诸多语言都可通过 Wasm 执行。此外,Wasm 也可运行在各种硬件和操作系统之上,其规范的设计快速且紧凑,以及重中之重的安全。


在 2022 年,最初仅为浏览器设计的 Wasm 已经在其他领域大放异彩,实践证明,Wasm 在嵌入式编程、插件、云、边缘计算等领域都非常有用。在这些用例中,性能都是极其重要的因素。快速加载可执行部分是性能中的一环,其中文件的大小往往对原始性能有直接的影响。


在本文中,我们将探讨六种优化 Wasm 性能及文件大小的方法。

语言选择


编程语言之间或多或少都些许区别,其中之一是语言执行时对运行时大小的需求。底层系统语言如 C 或 Rust 都算是轻量级,只需要很小的运行时开销。其他如 Swift 等语言对运行时的需求不小。Swift 的二进制中包含了很多内置行为,因此文件也大多不会小。同理,Java 和 .NET 语言的二进制文件也往往很大。


为展示这其中区别,让我们看看一段“Hello World”程序在 Rust 和 Swift 中的表现。

Rust 中一段简单的“Hello World”如下:

fn main() {    println!("Hello, world!");}
复制代码


用 cargo build —target wasm32-wasi 命令编译后的二进制文件大小为 2.0 M。这是未经优化的文件大小,后文中我们会再回到这点上。


同样的程序在 Swift 中如下:


print("Hello, World!\n")
复制代码


通过 Swiftwasm 中的 swiftc -target wasm32-unknown-wasi hello.swift -o hello.wasm 命令编译至 Wasm 后,会产生 9.1M 的镜像。可见 Swift 版本的程序相较 Rust 而言大了四倍有余。


因此,编程语言的选择会直接影响二进制文件的大小,并在一定程度上影响启动的时间。但对文件大小的优化并不是到此为止了,我们还有其他手段可以进一步优化二进制的大小。

利用编译选项的优化


部分编译器提供了内置的编译选项,以优化其所生成的二进制。C/C++ 的老手们对此并不陌生,而新生语言如 Rust 及 Zig 也提供优化选项。


在上文中简单的三行 Rust 程序中,我们通过默认编译命令cargocommand得到了 2.0M 的二进制文件。但在加上编译选项之后,我们还可以进一步缩小文件大小。cargo build --target wasm32-wasi --release 命令会输出 1.9M 的二进制文件。因为 Rust 的 svelte 运行时存在,这种小型程序能优化掉东西并不多。但对于大型项目而言,--release 选项可以显著减少文件大小。以 Bartholomew CMS 项目为例,默认编译命令会生成 84MB 的二进制文件,而启用 --release 选项的编译则会将文件大小缩减至 7M,效果不可谓不明显。


Rust 中的 --release 选项能做的可不仅仅是缩小文件大小,它还能移除调试器和分析工具所用的符号,从而加快执行速度。在生产环境中的代码执行方面,这可是个非常有用的功能。运行完整 84M 的 Bartholomew 需要数秒的执行时间,但优化后的 7M 文件执行仅需要几毫秒。

借助 wasm-opt 优化文件大小


并不是所有编译器都提供优化的选项,即使是提供优化选项的编译器可能也不会有十分明显的优化效果。

Wasm 的优化工具可以分析 Wasm 二进制文件稳健性的同时,进一步优化文件大小,甚至还可优化 Wasm 可执行文件的性能特征。Binaryen 项目中提供了诸多 Wasm 可用的命令行工具,其中就包括 wasm-opt 优化器。


有 9.1M 大小的 Swift 程序珠玉在前,让我们看看用 wasm-opt 工具运行 -O hello.wasm -o hello-optimized.wasm 能带给我们什么。这条命令生成了一份优化后的二进制文件 hello-optimized.wasm,大小仅有 4.0M,缩小了 50%有余。


wasm-opt 工具提供了多项对二进制的优化,从重复代码移除到代码整理不等。但这里说的“代码”是指 Wasm 指令,而非开发者编写的源码。因此,运行 wasm-opt 工具并不会修改 Swift 源码,仅仅是重写了 Wasm 二进制。这种方式不仅削减了文件大小,同时也优化了运行时性能。在作者的电脑上,优化后的“Hello World”程序执行速度比没经过优化的要快上两倍。


不仅如此,wasm-opt 工具甚至还能进一步优化已经经过优化的 Rust 代码。让前文中 1.9M 的 Rust 二进制进一步压缩至 1.6M。但在这种简单程序上的优化并没有给性能带来多少提升,无论是否进一步优化,运行时间均在十分之一秒左右。但或许更为大型的 Rust 二进制文件可以通过 wasm-opt 获得运行速度的改善。

运行时很重要


二进制格式 Wasm 非常灵活,可以通过 wasm3 这类解释器(如 )按序读取并分块执行,而另外一些 Wasm 运行时,如 Wasmtime,则是借助了 JIT(即时)编译技术,加快了执行的速度。


解释器的优势在”Hello World“这种简单程序、或运行于设备资源有限(如 Raspberry PI)的程序,因为它可以用更少的资源做更少的事。但对于 Bartholomew CMS 这类大型程序而言,JIT 形式的运行时拥有更多优势。这是因为 JIT 编译器会在启动以及执行早期进行额外工作,以优化程序的存内显示,而这种优化也会继续存在于程序的持续运行中。但因为 JIT 过程需要时间,所以对于只运行一小段时间的小型程序而言,反倒是一种性能的损失。


那么我们要如何选择呢?按照传统经验论的说法,如果是在比 Raspberry PI 资源还要有限的设备上运行,那么就用解释器,不然就还是选择支持 JIT 的运行时吧。

说起运行时,还有另一个技巧。

提前(AOT)编译


JIT 运行时会在启动时进行存内优化。但如果我们想在一次优化执行后,将其写回磁盘并在程序的下次运行时重复利用优化呢?这就是“提前(AOT)”编译了。


但 AOT 编译阶段所做的优化内容与之 wasm-opt 的优化有本质上的不同,这也是 AOT 编译的一大缺点。AOT 的优化因为考虑到了操作系统和处理器结构,所以优化后的 Wasm 二进制文件无法移植再移植到其他机器上。除此之外,优化后文件的格式也因运行时的不同而各异,也就是说,一个 AOT 编译的 Wasm 运行时程序无法再被其他 Wasm 运行时执行。


Wasmtime 运行时可将 wasm 模块编译为 AOT 格式,用 wasmtime compile hello.wasm 命令编译之前的 Swift 例子,会生成一个可被 Wasmtime 执行的新文件hello.cwasm。当然,对于“Hello World”这种小程序而言,AOT 编译效果并不明显。但在处理大型程序时,AOT 编译的性能会比解释器或 JIT 运行都要高。不过需要注意的是,多数 AOT 编译器所生成的二进制文件比其等效 Wasm 文件都要大,这是因为 Wasm 运行时中的很多自身元素都会被编译至二进制文件以提高性能。


什么时候该用 AOT 编译器呢?一个很具体的经验论是,只有在确定程序只会在同一套 Wasm 运行时、操作系统、架构配置下运行时再选择 AOT。此外,Wasm 模块应以正常的 Wasm 形式分发,并只在安装中或安装结束后再进行 AOT 编译。

预初始化二进制


第五种优化手段可以说是最神奇的一种。因为 Wasm 是基于堆栈的虚拟机,不仅可以随时停止,还能被写入到磁盘供后续恢复,当然这其中也有限制,但这些对本文的主题并不重要。Wasm 的这个功能有个蛮有趣的应用。


代码中时常会有一部分需要在每次启动时都运行,这部分代码做的事可能也很平常,像是设置变量默认值、创建数据结构实例等等。但每次运行程序时都必须执行同一套初始化逻辑,而每次运行的结果状态也不会有什么区别:变量被初始化为同样的值,数据结构被初始化为同样的状态。


如果我们能在第一次运行初始化的时候,将 Wasm 状态快照后写回磁盘,那么在后续程序执行的时候,我们就拥有了已经完成的状态,是不是就不用再运行初始化步骤了呢?


这个想法组成了 Wizer 项目,Wizer 提供对初始化代码块添加注释,让其在一次执行后被写入一个新的初始化后 Wasm 二进制文件。与 AOT 编译不同,这个新的二进制文件与别的 Wasm 二进制没什么区别,因此依旧是可移植的。


在用的时候可能会感觉 Wizer 有点不太稳定,但 .NET 这类系统可以从 Wizer 中受益良多。

一起上


根据我们在 Fermyon 的经验来看,优化对开发者工具和云运行时都很重要,但这二者的情况并不相同。

对开发者而言,编译器所能提供的优化工具中用得越多越好。比如在编译 Rust 代码时,我们总会带上 --release 选项。我们的开源工具 Spin,允许开发者用多种语言构建 WebAssembly 微服务及网页应用,其中不乏有各种语言模板自己的优化内容。此外,在本地编译中包含 wasm-opt 也很有用,尤其是对于需要大量运行时的语言。开发过程中我们选择的运行时是支持 JIT 的,因为开发阶段 AOT 编译的价值不大。


服务器端就是另一个故事了。以我们基于 SaaS 的 Wasm 运行时平台为例,Fermyon 云 仅接受 Wasm 二进制输入,但在部署到云集群后,这些二进制又变成了通过 AOT 编译过后的文件。因为我们非常清楚主机运行时的配置,所以这种方式很可靠。这些 Wasm 文件被部署到 Arm64 系统后可以相应地被 AOT 编译,我们不用担心这些文件在英特尔的架构上的执行情况。


至于 Wizer,我们其实只在 .NET 上用过,Wizer 在这方面的优化非常好用。

总结


这 6 种优化 Wasm 性能及文件大小各有自己的优缺点,结合使用其中一些方法也可以增加效益。在生产的 Wasm 环境中应用这些手段也会有益处。


原文链接:The Six Ways of Optimizing WebAssembly


相关阅读:

WebAssembly 在工业领域的巨大机遇

Docker 发布 WebAssembly 支持工具预览版


活动推荐:

2023年9月3-5日,「QCon全球软件开发大会·北京站」 将在北京•富力万丽酒店举办。此次大会以「启航·AIGC软件工程变革」为主题,策划了大前端融合提效、大模型应用落地、面向 AI 的存储、AIGC 浪潮下的研发效能提升、LLMOps、异构算力、微服务架构治理、业务安全技术、构建未来软件的编程语言、FinOps 等近30个精彩专题。咨询购票可联系票务经理 18514549229(微信同手机号)。

2023-03-31 10:035061

评论

发布
暂无评论
发现更多内容

腾讯数字生态大会【TechoDay技术回响日】

腾讯云数据库

联想智慧服务荣获第17届“金耳唛杯”年度总冠军

科技大数据

浪潮云说丨构建全域业务联动枢纽,挖掘数据要素创新价值

浪潮云

云计算

用会声会影制作手链的展示视频

懒得勤快

【权限专栏】联盟链的“圆桌会议”

趣链科技

架构训练营模块1作业

Puciu

架构实战营

空调可视化运营中心,赋能精细化运营管理

ThingJS数字孪生引擎

模块2总结

Asha

架构实战营

官方线索 | 1024新华三服务器性能调优挑战赛

穿过生命散发芬芳

1024我在现场

高校人才集聚飞桨启航菁英计划!百度联合中国图象图形学学会助力AI人才培养

百度大脑

人工智能 百度 图像

anyRTC从服务到产品全链路服务保障升级

anyRTC开发者

音视频 直播 实时通信 语音通话 视频通话

模块2

Asha

使用 Spring Boot 和 @WebMvcTest 测试 MVC Web Controller

码语者

Java Spring Boot test

模块一作业

hpl

【引航计划】优质内容合集名单公布

InfoQ写作社区官方

引航计划 热门活动

优酷鸿蒙开发实践|多屏互动开发实践

阿里巴巴终端技术

ios android 鸿蒙 优酷 客户端

资讯|WebRTC M94 更新

网易云信

大前端 chrom

打破 Serverless 落地边界,阿里云 SAE 发布 5 大新特性

阿里巴巴云原生

阿里云 Serverless 云原生 Serverless Kubernetes

快手技术嘉年华 | 与你漫游技术星辰大海

快手中学

技术 校招 快手

终于有人把云原生存储讲明白了

青云技术社区

云计算 云原生 存储 Cloud Native

校招失败,在小公司熬了2年后我终于进了阿里,竭尽全力(Java岗)

Java 程序员 架构 面试 计算机

第二存储解决方案白皮书 | 专为非生产数据而设计的存储方案

QingStor分布式存储

云原生 分布式存储

这才是责任链模式的优雅使用方式

Tom弹架构

Java 架构 设计模式

打破数据壁垒,北鲲云超算混合云模式激活人工智能数据价值

北鲲云

二本渣渣的金九银十辛酸面试之旅:5 面阿里(Java岗) 侥幸上岸

Java 编程 程序员 架构 面试

4个实验,彻底搞懂TCP连接的断开

Java 架构 TCP 后端 网络编程

自定义ViewGroup的触摸反馈

Changing Lin

10月月更

精细运营|营销获客自动化‘攻心’

海比研究院

CRM

事件管理CRM系统是活动策划工作的必要工具

低代码小观

CRM 管理系统 事件管理 CRM系统 活动策划

科技热点周刊|微软发布 Web 版 VSCode、 删除 .NET 6 热重载引发不满、IBM 发布开源混合云介绍指南

青云技术社区

云计算 云原生 kubenetes CockroachDB

CFI技术新探索,struct_san今日登场

腾讯安全云鼎实验室

云安全

  • 扫码添加小助手
    领取最新资料包
6种WebAssembly的优化手段_DevOps & 平台工程_InfoQ精选文章