前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >WebAssembly 动态 | WebAssembly 的发展风险及Wasmtime 1.0 性能概览

WebAssembly 动态 | WebAssembly 的发展风险及Wasmtime 1.0 性能概览

作者头像
张汉东
发布2022-12-08 21:03:06
1.2K0
发布2022-12-08 21:03:06
举报
文章被收录于专栏:Rust 编程

本篇文章关注 WebAssembly 的相关动态。

Fermyon | WebAssembly 的风险

今早看到来自 fermyon 官方博客的文章[1],介绍了 WebAssembly 现存的一些风险和他们的应对方法:

  • 标准化进展非常缓慢。为此 Fermyon 加入了 字节码联盟 亲自推动标准化进程,并通过构建 Spin 代码实现来充分利用标准
  • 语言支持不够。Fermyon 认为前 20 种语言中至少有 15 种必须完全支持 WebAssembly 以及 WASI 和组件,才能正确地认为 WebAssembly 被很好地采用。Fermyon 采取的立场是将注意力集中在最受欢迎的语言上,这就是为什么使用 Rust 而不是 C 或Zig。

“这方面也有一些好消息:

  1. 语言支持正在迅速增长,今年C#、Python和Ruby都增加了支持
  2. wasi 支持现在是进入 wasm 游戏领域的筹码
  3. 在主流实现语言未能发挥作用的地方,该语言的替代实现正在加紧发展,比如 tinygo 对于 wasm 的支持就超越了 go
  • 生态系统不是可选的。WebAssembly 有望成为下一波计算浪潮,但除非 Fermyon 能围绕它建立生态系统,所以 Fermyon 正在努力联合相关其他企业合作共建社区。
  • 社区实现碎片化。(比如 deno 和其他非标准化实现,文章没有明说)。可悲的是,有时这仅仅是由于无知和不参与:“我们不知道有一个标准为此而出现”。所以目前发布的组件规范(正在进行中,但正在迅速成熟)旨在解决这类问题,这个标准使得在不同的主机实现之间共享 WebAssembly 二进制文件成为可能。还有一个不幸的趋势,即一些开发人员选择与组件模型相反的工作,创建与他们自己的主机运行时的强链接。走这条路一方面会导致平台锁定,另一方面会毫无意义地重新编写相同的代码(针对略有不同的主机进行工具化)。幸运的是,那些准备最好的人(Fastly、Mozilla、Microsoft)反而选择推动互操作性标准以造福所有人。这是正确的第一步。为了阻止破坏性的碎片化“手榴弹”,我们必须增加社会压力,不要我行我素,而要坚持互操作性标准。做到这一点的一个关键方法是彼此公开合作(通过字节码联盟、W3 和 CNCF 等组织),不仅要创建和实施标准,还要创建对话论坛。

“Fermyon 的愿景是,在五年内,WebAssembly 将成为常态,而不是小众市场。新一波应用程序将能够利用 WebAssembly 的速度、安全性和组件模型。为了实现这一目标,我们每个人都可以发挥作用。

Wasmtime 1.0 性能概览

近日字节码联盟发布了 wasmtime 1.0 性能概览[2] 的一篇文章,为将在 9.20号发布的 wasmtime 1.0 稳定版做前期铺垫,介绍了 wasmtime 团队近期在编译器和运行时中所做的工作。这里只做重点摘要,并非全文翻译,对细节感兴趣的可进一步参阅原文。

什么是性能

让 Wasmtime 和 Cranelift 变得更快意味着什么?所谓的“快”是什么意思?

“Cranelift 也被用于 Rust Debug 模式编译后端

当 Wasmtime 执行 Wasm 程序时,CPU既执行从Wasm字节码编译的本地指令,也执行 "Wasmtime Runtime "的一部分,Wasmtime Runtime 用于维护数据结构以帮助实现Wasm语义。这两部分的执行有两个阶段:启动初始化(Wasm代码的编译,和运行时的初始化)和 稳态(steady-state)执行。这两个层面的四个组合都对性能有一定的影响,可以分别进行优化。

Compiler (Cranelift)

Runtime (Wasmtime)

启动阶段

代码编译时间

Wasm 模块实例化时间

稳态阶段

生成代码的速度

运行时的基本速度

wasmtime 对于改善这四个象限中的每一项都做了大量工作。

Wasm 模块实例化

WebAssembly 之所以安全是因为wasm 模块每个实例与生俱来的隔离性。为了有效地利用这种隔离性,Wasm的一些应用将每一个工作单元实例化为一个新的实例,例如服务器上每个传入的请求。因此,极快的模块实例化是像Wasmtime这样的Wasm VM的一个关键要求。

现在 wasmtime 的模块实例化速度已经被优化到了微秒级别。这是如何做到的呢?

虚拟内存技术

在过去,wasmtime 是通过为 wasm 应用初始化一大块内存(通过malloc或mmap或一些其他分配器),然后将数据复制到正确的位置。

现在,是从现代计算机使用的虚拟内存技术获得灵感,实现了一个 实例分配器[3]使用了mmap 、madvise 和写时复制(copy-on-write)的技术将实例化的成本大大的降低了。

延迟初始化

Wasmtime运行时在开始执行已编译的Wasm代码之前,要花费大量时间来初始化数据结构。所以,团队为函数引用表和它们所指向的函数闭包对象实现了延迟初始化[4]

优化结果

SpiderMonkey.wasm 的实例化时间从大约2毫秒到5微秒,快了400倍。

运行时性能

Wasm 执行过程中的大部分 CPU 时间通常花在Wasm程序本身,或它调用的 "hostcalls"(这是Wasmtime用户插入Wasmtime的代码,无法直接控制),除此之外,Wasmtime本身有一些部分在某些情况下必须运行,这部分代码就是 Wasmtime Runtime 的性能优化之处。

加速栈走查(Stack-Walking)

之前,为了让Wasmtime列举所有的栈帧(stackframes),Cranelift编译器产生了所谓的 "unwind info"。这是一种元数据,描述了编译后的代码将在任意给定点上把值放在栈中。利用这些元数据,Wasmtime的 "unwinder"能够逆向程序状态:它理解一个活动函数每次调用的栈帧,最终找出谁调用了它,并在栈上迭代,直到它到达Wasm的初始入口。整个过程非常慢。

团队对此进行了改进,确保始终保持一个帧指针的链表,从而达到栈走查像遍历链表那么简单。这种性能改进是一个巨大的质量改进:它允许启用栈跟踪,并大幅提高Wasmtime的健壮性。

加速多任务协作 与 代际(Epoch) 中断

Wasmtime的一个常见用例是同时并发运行许多不同的 WebAssembly guests,并在它们之间设置时间片。Wasmtime内置支持在一个异步事件循环上运行对Wasm的调用。

Wasmtime 用户在这种情况下可能遇到的一个问题是如何限制 Wasm 程序的执行时间。通常,当与事件循环异步运行时,计算密集型任务应拆分为多个段,以便事件循环不会停止超过最大“时间片”。

通过将 Wasm 字节码标准编译为本地机器代码,Wasm 中的循环成为编译代码中的循环,并运行尽可能多的迭代,没有限制。如果用户从事件循环中调用此函数,则该事件循环可能会无限期停止。

因此,特别是在运行不受信任的代码时,Wasmtime 用户必须建立一种在一定时间限制后重新获得控制权的方法。所以 Wasmtime 必须提供一种在某个时间点中断 Wasm 执行的方法。

之前,实现这一行为的主要方式是通过“燃料(fuel)”。这是一种机制,通过该机制,已编译的 Wasm 代码增加了对“操作”进行计数的代码,根据限制检查当前计数,如果超出限制,则返回给调用者或事件循环。“燃料(fuel)”是一种有效的机制,但它成本很高:它需要用“计数”来扩充每一段代码,并经常将该计数存储到内存中并检查它。

团队使用了基于代际的中断[5]取代了 “燃料(fuel)”机制,性能提升了两倍。

“使用 “燃料”机制还是代际中断,是一种权衡。“燃料”机制更加精准,而代际中断性能更好。

Cranelift 编译代码的质量

Cranelift 用于将Wasm字节码编译成计算机可以直接执行的本地机器代码。

寄存器分配器改造:regalloc2

在过去的一年里,wasmtime引入了新的寄存器分配器 regalloc2[6]。寄存器分配器是编译器的一个部分,它为程序中的值分配存储位置。在真正的CPU中,指令对寄存器中的数据进行操作,寄存器是一些小的存储位置,每个位置可以容纳一个值(例如,一个64位的数字)。寄存器分配器决定在什么时候将哪些值保存在哪些寄存器中。做好这一点可以大大改善程序的性能,因为它意味着更少的数值移动。WebAssembly,作为一个抽象的、与硬件无关的虚拟机,没有大多数指令的输入和输出位置的概念。

regalloc2的设计是为了支持更高级的算法,以决定如何向寄存器分配数值。当引入时,它将SpiderMonkey.wasm的运行时性能提高了约5%,将另一个CPU密集型基准测试bz2的性能提高了4%

更好的模式管理:新的后端、ISLE和持续的调整

指令选择问题是指选择最佳的CPU指令来实现一个给定的程序行为。因为每个CPU都有自己独特的指令集,而且这些指令可以以许多不同的方式组合,这是一个非常难解决的组合难题。Cranelift最初采用了一种新的编译器后端设计,可以实现更高级的模式匹配,目前采取的方法是用模式匹配DSL(特定领域语言)来表达底层的指令,这样我们就可以更容易地调整这些模式。

未来:中端优化

在未来,我们计划为Cranelift引入更先进的中端优化。中端优化器 "是编译器的一部分,在程序被 "降级"为机器特定的形式之前(也就是在指令选择之前),以各种方式对程序进行转换,使其更快。有一套经典的优化方法,几乎所有的编译器都会执行,包括简化常数表达式(1+1变成2)等基本规则。但也有许多更复杂和微妙的转换。

Cranelift: 编译时优化

除了优化Cranelift生成的代码,编译过程本身如果太慢,那么Wasmtime可能需要很长的时间来启动新的代码,将会阻碍生产力(对于Wasm开发人员)和响应能力(对于访问新应用程序的最终用户)。因此,编译器的速度是一个重要的指标。

广义上讲,我们可以通过在后端关键部分选择更好的算法来提高编译时间,如寄存器分配器或优化通道,或通过做一般的程序优化,如减少内存使用。

regalloc2

切换到 regalloc2 显着改善了编译时间,因为寄存器分配占编译时间的很大一部分:测量单线程时间(不是并行编译),SpiderMonkey.wasm 的构建速度提高了 6%,bz2 的构建速度提高了 10%。

中端优化器:将多个passes合并为一

算法重新设计也可以大大缩短编译时间。在我们的中端优化器原型中,我们对编译器设计的相关部分采取了一种新的方法:几个不同的 "程序",或以某种方式改造程序的特定算法,被合并成一个统一的框架,只对程序进行一次处理。

标准程序优化

一种特别有效的提高速度的改变是减少内存的分配和使用。程序分配的内存越少,它的运行速度就越快,至少有两个原因:内存分配器本身可能很慢,而且使用更多的内存也会导致更多的缓冲区未命中和内存流量。由于其多线程编译模式,Cranelift也倾向于对分配器施加特别大的压力。

总结

高性能是任何希望成为构建高效、持久系统的基础的软件的一个关键方面。如果 WebAssembly 想要成功,它的运行速度必须能达到与本地代码竞争的水平。这也是 wasmtime 性能优化的终极目标。

通过该篇文章我们简单了解了 Wasmtime 和 Cranelift 性能优化的相关工作,以及当前 wasmtime 1.0 的性能状态(详细数据见原文)。后续的文章将介绍该团队如何确保 Wasmtime 安全以及编译器生成正确的代码。

参考资料

[1]

文章: https://www.fermyon.com/blog/risks-of-webassembly

[2]

wasmtime 1.0 性能概览: https://bytecodealliance.org/articles/wasmtime-10-performance

[3]

实例分配器: https://github.com/bytecodealliance/wasmtime/pull/3697

[4]

实现了延迟初始化: https://github.com/bytecodealliance/wasmtime/pull/3733

[5]

基于代际的中断: https://github.com/bytecodealliance/wasmtime/pull/3699

[6]

regalloc2: https://github.com/bytecodealliance/regalloc2

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-09-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 觉学社 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Fermyon | WebAssembly 的风险
  • Wasmtime 1.0 性能概览
    • 什么是性能
      • Wasm 模块实例化
        • 虚拟内存技术
        • 延迟初始化
        • 优化结果
      • 运行时性能
        • 加速栈走查(Stack-Walking)
        • 加速多任务协作 与 代际(Epoch) 中断
      • Cranelift 编译代码的质量
        • 寄存器分配器改造:regalloc2
        • 更好的模式管理:新的后端、ISLE和持续的调整
        • 未来:中端优化
      • Cranelift: 编译时优化
        • regalloc2
        • 中端优化器:将多个passes合并为一
        • 标准程序优化
      • 总结
        • 参考资料
        相关产品与服务
        云服务器
        云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档