经典思辨|用于 WebAssembly 的灵活非侵入式动态插桩技术

文摘   科技   2024-06-24 12:06  
提要

本文是对发表于ASPLOS'24的文章《Flexible Non-intrusive Dynamic Instrumentation for WebAssembly》的解读。该文提出了一种新的WebAssembly动态分析框架,能够在不中断程序执行的情况下进行灵活的动态插桩。作者在开源的Wizard Research Engine中实现了这一创新设计,提供了一套完整的插桩原语层次结构,支持通过低级可编程探针构建高级复杂分析。与仿真或机器码插桩相比,在字节码级别注入探针增加了表达能力,并大大简化了实现,Wizard重用了引擎的JIT编译器、解释器和去优化机制,而不需要构建新的机制。Wizard支持动态插桩的插入和移除,并提供一致性保证,这是组合多个分析而不互相干扰的关键。作者详细介绍了在高性能多层WebAssembly引擎中的完整实现,展示了专门设计的优化以最小化插桩开销,并评估了在各种分析负载下的性能特征。该设计适合生产环境中的WebAssembly引擎采用,因为在不使用探针时,执行性能不受影响。

研究背景
MPIWasm运行时基于Wasmer运行时实现,支持:(1)通过将基于MPI的HPC应用程序编译为Wasm来实现高性能执行;(2)通过零复制内存操作实现 MPI 调用的低开销;(3)支持高性能互连,例如Infiniband和Intel OmniPath;(4)通过在Wasm和主机MPI库间提供转换层使得开发人员无需了解目标 HPC 系统上存在的特定MPI库或网络互连。

随着WebAssembly(Wasm)的广泛应用,尤其是在云计算、边缘计算和物联网等领域,理解和优化Wasm程序的动态行为变得至关重要。WebAssembly作为一种便携、高效的字节码形式,能够在多种环境中提供接近原生的执行性能。然而,现有的Wasm引擎在动态分析方面的支持非常有限,通常只提供基本的字节码级别的调试功能,如单步执行和基本的源代码映射,缺乏详细的动态插桩能力。这使开发者难以深入理解Wasm程序的运行时行为,无法高效进行调试、性能分析和优化。


传统的插桩方法,如静态重写和动态重写,虽然能够在一定程度上实现程序的动态分析,但存在显著的缺点:
  • 侵入性强:许多现有的插桩方法会改变程序的语义,导致被插桩的程序行为发生变化。这种侵入性不仅可能引入新的错误,还会影响程序的正常执行,尤其是在需要高精度分析的场景下。
  • 性能开销大:插桩操作往往会引入额外的运行时开销,影响程序的执行效率。特别是在高性能需求的WebAssembly应用中,这种开销可能是不可接受的。
  • 缺乏灵活性:现有的插桩工具和方法在动态插入和移除探针时往往缺乏灵活性,无法在程序运行过程中根据需要调整插桩策略。这限制了动态分析的实时性和准确性。
  • 一致性问题:在动态插入和移除探针时,如何保证插桩操作的一致性,使得多个分析能够无干扰地组合使用,是一个复杂的问题。缺乏一致性保证的插桩操作可能导致分析结果不准确,甚至引起程序崩溃。
  • 多线程支持不足:随着WebAssembly逐渐引入多线程支持,如何在多线程环境中实现一致性和高效的插桩成为新的挑战。多线程环境下的数据竞争和同步问题需要得到有效解决,以确保插桩操作的正确性和性能。
方法设计
MPIWasm运行时基于Wasmer运行时实现,支持:(1)通过将基于MPI的HPC应用程序编译为Wasm来实现高性能执行;(2)通过零复制内存操作实现 MPI 调用的低开销;(3)支持高性能互连,例如Infiniband和Intel OmniPath;(4)通过在Wasm和主机MPI库间提供转换层使得开发人员无需了解目标 HPC 系统上存在的特定MPI库或网络互连。
论文提出了一种名为Wizard的非侵入性动态插桩框架,这是首个面向WebAssembly的此类系统。该框架通过在字节码层面注入探针(probes),支持灵活、详细的动态分析。以下是Wizard框架的主要设计细节和实现方式。

全局探针(Global Probes)

全局探针是一种在每条指令执行时触发回调的机制。尽管全局探针的效率较低,但它们是实现追踪、计数和调试等任务的最简单方式。全局探针的实现方式如下。
  • 调度表切换:为了避免在未启用全局探针时产生额外开销,Wizard采用了调度表切换技术。当全局探针未启用时,解释器使用正常的调度表;当启用全局探针时,调度表切换到包含探针调用的版本。这种方法确保了在未启用探针时的零开销。


局部探针(Local Probes)

局部探针附加到特定的字节码位置,仅在该位置被执行时触发。局部探针适用于分支分析、调用图构建、代码覆盖等任务。其实现方式如下。
  • 字节码覆盖:局部探针通过覆盖原始字节码的位置来实现。当解释器遇到被覆盖的字节码时,它会调用相应的探针回调。覆盖的原始字节码被保存在旁边,以便在探针回调后继续执行原始指令。
  • 零开销:未被插桩的指令不会产生额外开销,因为它们不需要额外的检查或处理。

图1:在解释器中实现插桩的示意图

FrameAccessor API

为了支持更复杂的动态分析,如污点跟踪、模糊测试和调试,探针回调需要访问程序的执行状态。FrameAccessor API提供了一个访问执行帧状态的接口。其设计和实现如下。
  • 状态读取:FrameAccessor对象提供了一系列方法,用于读取执行帧的本地变量、操作数栈等状态信息。探针回调可以通过这些方法获取所需的状态信息。
  • 延迟分配:FrameAccessor对象在第一次被请求时才会分配,从而减少不必要的开销。
  • 一致性保证:为了确保探针回调在多次调用之间的一致性,FrameAccessor对象在执行帧中保留一个引用。这个引用在函数入口被清除,并在函数返回时进行验证。

    一致性保证

    为了确保探针的插入和移除过程中的一致性,Wizard框架提供了以下一致性保证。
    • 确定性触发顺序:探针按照插入顺序触发。如果在触发探针时插入了新的探针,新探针将在下一次事件发生时触发。
    • 帧修改一致性:探针对执行帧的修改立即生效,并且修改后的状态会在后续执行中得到反映。这通常需要即时的反优化处理,以确保JIT编译的代码不会依赖已被修改的状态。


    JIT内联优化


    为了减少探针的开销,Wizard框架在JIT编译过程中对常见探针逻辑进行了内联优化。具体实现如下。

    • 计数器探针内联:对于简单的计数器探针,JIT编译器会将计数器的递增操作直接内联到编译后的代码中,从而避免了调用探针回调的开销。
    • 操作数栈探针优化:对于需要访问操作数栈顶元素的探针,JIT编译器会直接传递栈顶值给探针回调,避免了不必要的状态重建。


    多层次一致性策略(multi-tier consistency)

    在多层次执行引擎中,确保探针一致性是一个挑战。Wizard框架采用了一种基于即时反优化的策略。
    • 即时反优化:当探针修改了执行帧的状态时,当前的JIT编译代码会立即反优化,回退到解释器执行。这确保了后续执行不会依赖已被修改的状态。
    • 动态层次调整:在动态层次配置模式下,反优化后的代码仍然可以根据热度重新编译,以确保性能。
    实验评估
    MPIWasm运行时基于Wasmer运行时实现,支持:(1)通过将基于MPI的HPC应用程序编译为Wasm来实现高性能执行;(2)通过零复制内存操作实现 MPI 调用的低开销;(3)支持高性能互连,例如Infiniband和Intel OmniPath;(4)通过在Wasm和主机MPI库间提供转换层使得开发人员无需了解目标 HPC 系统上存在的特定MPI库或网络互连。

    图2: 在PolyBenchC套件中,使用局部探针和全局探针实现的热度监视器(左)和分支监视器(右)的平均相对执行时间。柱状图上方的点表示探针触发次数。

    在本论文中,作者通过执行三套基准测试和几种不同的实现策略来评估监控代码的性能。作者比较了在 Wizard 中对 Wasm 代码进行插桩、字节码重写、使用 Wasabi 进行字节码注入,以及使用 DynamoRIO 进行本地代码插桩的效果。

    实验设置

    作者通过执行不同监控器并测量整个程序的总执行时间(包括引擎启动和程序加载时间)来评估 Wizard 的性能。作者选择了“热度”(hotness)和“分支”(branch)监控器,这些监控器分别在每条指令和分支指令上插入 CountProbe。基准测试套件包括 PolyBench/C、Ostrich 和 Libsodium,并对每个程序运行5次取平均值。作者定义了绝对开销相对执行时间,其中绝对开销是插桩执行时间与未插桩执行时间之差,相对执行时间是两者的比值。作者报告了 Wizard 解释器、JIT(有和没有内联优化)、DynamoRIO、Wasabi 和字节码重写的相对执行时间

    全局探针与局部探针的对比

    全局探针可以模拟局部探针的行为,但会在每个字节码指令处引入更大的性能开销。作者比较了在 Wizard 解释器中使用全局探针和局部探针实现的分支和热度监控器。结果表明,对于热度监控器,由于探针触发次数相同,全局和局部探针的相对开销相似。然而,对于分支监控器,局部探针的相对执行时间在 1.0–2.2× 之间,而全局探针在 7.7–16.4× 之间,见图2。

    图3: 在 Wizard、Wasabi 和 DynamoRIO 中,所有套件上所有程序的热度监控器(下)和分支监控器(上)的相对执行时间,按绝对执行时间排序。

    JIT优化效果

    作者评估了 JIT 内联优化对不同类型探针的影响。对于热度监控器,内联优化将相对执行时间从 7–134× 降低到 2.2–7.7×。对于分支监控器,内联优化将相对执行时间从 1.0–16.6× 降低到 1.0–2.8×。

    解释器与JIT的对比

    作者发现,运行在 Wizard 解释器中的监控器的相对开销远低于 JIT,因为解释器运行速度较慢,并且在检查状态时需要做的额外工作较少。对于分支监控器,解释器中的相对执行时间为 1.0–2.2×,而在 JIT 中为 1.0–16.6×。对于热度监控器,解释器中的相对执行时间为 7.0–13.5×,而在 JIT 中为 7.0–134×。

    与现有工具的对比

    作者将Wizard与其他现有工具进行了对比。结果显示,Wizard在执行时间和开销方面优于这些工具。
    • 与字节码重写的比较
      作者使用 Walrus 实现了通过字节码重写的热度和分支监控器,并在 Wizard 的 JIT 中运行这些转换后的字节码。结果表明,内联优化后的 JIT 执行时间低于字节码重写,见图4。
    • 与 Wasabi 的比较
      Wasabi 是一个动态插桩工具,其插桩代码必须用 JavaScript 编写,因此需要一个同时运行 JavaScript 的 Wasm 引擎(如 V8)。结果显示,Wasabi 的插桩大大慢于 Wizard,因为调用 JavaScript 函数的开销很大。热度监控器在 Wasabi 中的执行时间增加了 36.8–6350.2×,而在 Wizard 的 JIT 中为 7–134×(或内联优化后的 2.2–7.7×)。分支监控器在 Wasabi 中的执行时间增加了 29.9–4721.5×,而在 Wizard 的 JIT 中为 1.0–16.6×(或内联优化后的 1.0–2.8×),见图3和图4。
    • 与 DynamoRIO 的比较
      作者还比较了本地代码插桩。由于无法直接比较,作者将相同的基准程序编译为 x86-64 汇编,并使用 DynamoRIO 进行插桩。结果显示,DynamoRIO 的热度监控器使执行时间增加了 3.9–192×,而分支监控器增加了 4.4–153×,见图3和图4。作者通过测量多个标准基准测试和插桩方法的分支和热度监控器的相对执行时间来评估 Wizard 的插桩开销。对于稀疏探针的监控器(如分支监控器),局部探针显著提高了性能(相对执行时间为 1.0–2.2×,而全局探针为 7.7–16.4×)。在 Wizard 的 JIT 中运行监控器进一步提高了性能,未内联优化的相对执行时间为 1.0–16.6×,内联优化后的为 1.0–2.8×。这大大优于 DynamoRIO 和 Wasabi,后者的相对执行时间分别为 4.4–153× 和 29.9–4721.5×。JIT 内联优化甚至可以产生比侵入式字节码重写更低的插桩开销。结果表明,Wizard 的插桩架构既灵活又高效。

    图4: 在Wizard、Wasabi和DynamoRIO中,三种套件下热度监控器(左)和分支监控器(右)的平均相对执行时间。比率相对于未加工具的执行时间。

    总结
    MPIWasm运行时基于Wasmer运行时实现,支持:(1)通过将基于MPI的HPC应用程序编译为Wasm来实现高性能执行;(2)通过零复制内存操作实现 MPI 调用的低开销;(3)支持高性能互连,例如Infiniband和Intel OmniPath;(4)通过在Wasm和主机MPI库间提供转换层使得开发人员无需了解目标 HPC 系统上存在的特定MPI库或网络互连。
    该论文介绍了一种用于WebAssembly的非侵入式动态插桩系统,实现于开源的Wizard研究引擎。该系统提供了灵活且完整的插桩原语层次结构,支持通过低级可编程探针构建高级复杂分析。与仿真或机器码插桩相比,在字节码级别注入探针提高了表达能力,并通过重用引擎的JIT编译器、解释器和去优化机制简化了实现。Wizard支持动态插桩的插入和移除,并提供一致性保证,确保多个分析的无干扰组合。通过性能评估,验证了插桩系统的有效性和性能优势,尤其是在执行时间和插桩开销上具有显著优势,适用于生产环境中的应用。未来工作方面,作者计划探索更多高级钩子的直接引擎支持,例如内存访问和陷阱事件。此外,作者还打算研究将探针代码以IR(中间表示)的形式提供给JIT,以实现更高效的内联优化,可能使用Wasm字节码作为IR。同时,随着WebAssembly线程提案的推进,作者将进一步研究多线程环境下的插桩一致性和性能优化。

    编辑:韩宇栋

    原文作者:Ben L. Titzer, Elizabeth Gilbert, Bradley Wei Jie Teo, Yash Anand, Kazuyuki Takayama, Heather Miller

    数据空间技术与系统
    数据空间技术与系统全国重点实验室面向国家数据空间建设的中长期战略需求和重大任务,开展数联网基础软件与数据空间操作系统的技术体系、标准规范、核心系统、试验环境、应用示范与开源生态等重点任务研究。
     最新文章