高效开发!使用Chrome对MoonBit生成的Wasm进行性能分析!

在 [我们前一篇博客][call-wasm-from-js] 中,我们介绍了如何在前端 JavaScript 中使用 MoonBit 驱动的 Wasm 库 [Cmark]。在本文中,我们将探索如何直接从 Chrome 浏览器中对该库进行性能分析。希望这篇教程能对你在使用 MoonBit 在类似的场景中进行开发时提供一些洞察,从而实现更好的整体性能。

在这里插入图片描述

具体而言,在本文中,我们将重点介绍如何对我们之前 [在前端应用中使用 Cmark 的示例][cmark-frontend-example] 做最小程度的修改,以便将 Chrome 内置的 V8 性能分析器应用到 [Cmark] 的 Wasm 代码中。

对 Cmark 库进行性能分析

我们很容易可以重构原始的前端应用程序,并添加一个新的导航栏以包含 “Demo” 和 “Profiling” 两个链接。点击第一个链接将使浏览器渲染原本的 A Tour of MoonBit for Beginners 示例的 HTML,点击第二个链接将导航到我们的新文档进行性能分析。(如果你对实际实现感兴趣,你可以在本文的末尾找到最终代码的链接。)

现在,我们已经准备为实际实现 Wasm 性能分析着手编写一些代码了。那么,与 JavaScript 性能分析相比,进行 Wasm 性能分析是否有不同之处?

实际上,我们可以使用与 JavaScript 相同的 API 来进行 Wasm 性能分析。Chromium 文档中有一篇 [文章][console-apis] 详细描述了这些 API,简而言之:

  • 当我们调用 console.profile() 时,V8 性能分析器将开始记录 CPU 性能概况;
  • 之后,我们可以调用我们希望分析的性能关键函数;
  • 最后,当我们调用 console.profileEnd() 时,性能分析器将停止记录,并将结果数据可视化显示在 Chrome 的性能标签页中。

考虑到这一点,让我们来看一下实际的性能分析功能实现:

async function profileView() {
  const docText = await fetchDocText("../public/spec.md");
  console.profile();
  const res = cmarkWASM(docText);
  console.profileEnd();
  return (
    `<h2>Note</h2>
<p>
  <strong
    >Open your browser's
    <a
      href="https://developer.chrome.com/docs/devtools/performance"
      rel="nofollow"
      >Performance Tab</a
    >
    and refresh this page to see the CPU profile.</strong
  >
</p>` + res
  );
}

如你所见,我们必须最小化性能分析器激活期间执行的代码范围。因此,我们在该范围内仅调用了 [cmarkWASM()] 函数。

另一方面,我们选择了 [《CommonMark 规范》][spec] 的 0.31.2 版本(即前文中提到的 spec.md)作为性能分析模式的输入文档。我们选择这一文档的主要原因是该文档使用了许多不同的 Markdown 特性,同时它的长度也足以使许多 Markdown 解析器遇到问题:

> wc -l spec.md  # 行数
    9756 spec.md
> wc -w spec.md  # 词数
   25412 spec.md

我们重新组织了前端应用程序,使得点击导航栏中的 “Profiling” 链接将触发上面定义的 profileView() 函数,从而得到以下结果:

在这里插入图片描述

如果你曾深入研究过性能优化,那么你应该不会对这个火焰图应该感到陌生了…

等等,wasm-function[679]wasm-function[367] 这些名字又是什么?我们该如何知道哪个函数对应哪个编号?

事实证明,我们需要在构建 Wasm 文件时保留一些调试信息。毕竟,我们一直使用以下命令构建我们的 MoonBit 项目:

> moon -C cmarkwrap build --release --target=wasm-gc

…而去除调试信息是 moon 在生成 release 版本时的标准行为。

幸运的是,我们可以使用一个额外的标志 --no-strip 来保留符号信息,而不必依赖于慢速的 debug 版本。让我们使用这个标志重新构建项目:

> moon -C cmarkwrap build --release --no-strip --target=wasm-gc

注意

类似地,如果我们想对生成的 Wasm 文件使用 wasm-opt,可以使用 wasm-opt--debuginfo(或 -g)标志来保留优化后输出中的函数名。

保留函数名后,我们终于可以在性能标签页中看到实际情况了!

在这里插入图片描述

分析火焰图

如上图所示的火焰图可以很好地总结函数调用及其各自的执行时间。如果你不太熟悉它,火焰图的主要思路如下:

  • Y 轴 表示调用栈,最顶部的函数最先被调用;
  • X 轴 表示执行时间,每个矩形节点的宽度对应于某个函数及其子函数的调用所花费的总时间。

既然我们正在研究 Cmark 库的性能,我们应该向下检索,并特别注意那里的 @rami3l/cmark/cmark_html.render() 节点。例如,在该节点处,我们可以清楚地看到 render() 的执行被分成了两个主要部分,分别被图中的两个子节点代表:

  • @rami3l/cmark/cmark.Doc::from_string(),表示将输入的 Markdown 文档转换为语法树;
  • @rami3l/cmark/cmark_html.from_doc(),表示将语法树渲染为最终的 HTML 文档。

为了更好地查看性能情况,我们可以单击火焰图中的 render() 节点。这会让 Chrome 更新“自底向上”视图,并仅显示由 render() 递归调用的函数。这样,我们将会得到如下所示的结果:

在这里插入图片描述

在“自底向上”视图中按自时间(即排除子函数所用时间的总时间)对条目进行排序,我们可以轻松找出那些自己消耗最多时间的函数,进而对这些函数的实现进行进一步的细致检查。同时,我们还需要尽量消除深层次的调用栈,这可以通过查找火焰图中较长的垂直条形找到。

实现高性能

在开发过程中,Cmark 已经使用我们上面展示的性能分析方法进行了数百次性能分析,以追求令人满意的性能。那么,它在与流行的 JavaScript Markdown 库的比较中表现如何呢?

在这个测试中,我们选择了 [Micromark] 和 [Remark]——这两个在 JavaScript 生态系统中广泛使用的 Markdown 库——作为我们的参考。我们在这个测试中使用了最新版本的 Chrome 133 作为我们的 JS 和 Wasm 运行时,并使用 [Tinybench] 来测量每个库的平均吞吐量。

以下是这些库在 MacBook M1 Pro 上将《CommonMark 规范》转换为 HTML 的平均吞吐量:

测试(从最快到最慢)样本数平均值/Hz±/%
cmark.mbt (WASM-GC + wasm-opt)21203.663.60
cmark.mbt (WASM-GC)19188.463.84
micromark1015.482.07
remark1014.283.16

结果非常明确:得益于持续的性能分析和优化过程,Cmark 现在比 JavaScript 基于的库快了大约 12 倍,相比于 Micromark 快了 13 倍。并且,wasm-opt 的额外优化步骤可以为 Cmark 提供额外的性能提升,将这些因子提高到大约 13 倍和 14 倍。

总之,Cmark 的性能证明了 MoonBit 在前端开发场景中提供可见效率提升的强大能力。

如果你对这个演示的细节感兴趣,可以在 [GitHub][cmark-frontend-example-profiling] 上查看最终代码。用于基准测试的代码也可以在 [这里][cmark-frontend-example-bench] 获得。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/970075.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

《安富莱嵌入式周报》第350期:Google开源Pebble智能手表,开源模块化机器人平台,开源万用表,支持10GHz HRTIM的单片机,开源CNC控制器

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 视频版&#xff1a; https://www.bilibili.com/video/BV1YPKEeyEeM/ 《安富莱嵌入式周报》第350期&#xff1a;Google开…

2.【BUUCTF】bestphp‘s revenge

进入题目页面如下 进行代码审计 <?php // 1. 高亮显示当前PHP文件的源代码&#xff0c;方便开发者查看代码内容&#xff0c;在生产环境中不应使用此函数&#xff0c;可能会导致代码泄露。 highlight_file(__FILE__);// 2. 定义变量 $b &#xff0c;其值为字符串 implode &…

HarmonyOS:使用List实现分组列表(包含粘性标题)

一、支持分组列表 在列表中支持数据的分组展示&#xff0c;可以使列表显示结构清晰&#xff0c;查找方便&#xff0c;从而提高使用效率。分组列表在实际应用中十分常见&#xff0c;如下图所示联系人列表。 联系人分组列表 在List组件中使用ListItemGroup对项目进行分组&#…

【vue3】入门基础知识点

Vue3核心语法 组合式API【vue3】与选项式API【vue2】 setup setup和data、methods同级别, 可与data等共存&#xff0c;data里面可以读取使用setup中声明的变量&#xff0c;而setup不能使用data中声明的变量&#xff08;setup加载时间早于beforeCreated&#xff09;setup中的…

DeepSeek官方发布R1模型推荐设置

今年以来&#xff0c;DeepSeek便在AI领域独占鳌头&#xff0c;热度一骑绝尘。其官方App更是创造了惊人纪录&#xff0c;成为史上最快突破3000万日活的应用&#xff0c;这一成绩无疑彰显了它在大众中的超高人气与强大吸引力。一时间&#xff0c;各大AI及云服务厂商纷纷投身其中&…

M3U8工作原理以及key解密视频流详解

文章目录 前言一、M3U8是什么&#xff1f;二、HLS—M3U8的工作原理1.分段视频流2.生成播放列表3.客户端请求和解析4.片段下载和播放 三、.m3u8文件内部是什么样的&#xff1f;四、简单介绍下AES-128算法五、拿到KEY后如何去解密&#xff1f;1.手动解密.ts文件2.前人栽树&#x…

重读《Java面试题,10万字208道Java经典面试题总结(附答案)》

最近重读了这篇文章&#xff0c;对很多概念模糊的地方加了拓展和补充。 目录 1、JDK 和 JRE 有什么区别&#xff1f; 2、 和 equals 的区别是什么&#xff1f; 3、final 在 java 中有什么作用&#xff1f; 4、java 中的 Math.round(-1.5) 等于多少&#xff1f; 5、String…

AI知识库 - Cherry Studio

1 引言&#xff1a; 最近 DeepSeek 很火啊&#xff0c;想必大家都知道&#xff0c;DeepSeek 这个开源的模型出来后&#xff0c;因其高质量能力和R1 的思维链引发了大家本地部署的热潮。我也不例外&#xff0c;本地部署了一个 14B 的模型&#xff0c;然后把&#xff0c;感觉傻傻…

Ai笔记本-Ainote(IOS 应用)帮助支持页面

简介 一个 iCloud 实时同步的笔记工具&#xff0c;支持markdown 格式解析、分享 PDF文件。 方便存储各种AI生成的markdown 格式回答&#xff0c;自动保存到 iCloud 永不丢失&#xff0c;支持分享为 PDF 格式笔记。 联系方式 如果您在使用过程中有任何问题或建议&#xff0c;…

1、Prometheus 监控系统(上)

Prometheus 监控系统&#xff08;上&#xff09; 认识一下 PrometheusPrometheus 的特点Prometheus 的生态组件Prometheus 的工作模式Prometheus 的工作流程Prometheus 的局限性&#xff1a; 部署 PrometheusPrometheust Server 端安装和相关配置部署 Exporters部署 Node Expor…

【设计模式】-工厂模式(简单工厂、工厂方法、抽象工厂)

工厂模式(简单工厂、工厂方法、抽象工厂) 介绍 简单工厂模式 简单工厂模式不属于23种GoF设计模式之一&#xff0c;但它是一种常见的设计模式。它提供了一种创建对象的接口&#xff0c;但由子类决定要实例化的类是哪一个。这样&#xff0c;工厂方法模式让类的实例化推迟到子类…

应急响应(linux 篇,以centos 7为例)

一、基础命令 1.查看已经登录的用户w 2.查看所有用户最近一次登录&#xff1a;lastlog 3.查看历史上登录的用户还有登录失败的用户 历史上所有登录成功的记录 last /var/log/wtmp 历史上所有登录失败的记录 Lastb /var/log/btmp 4.SSH登录日志 查看所有日志&#xff1a;…

【实测】用全志A733平板搭建一个端侧Deepseek算力平台

随着DeepSeek 的蒸馏技术的横空出世&#xff0c;端侧 SoC 芯片上运行大模型成为可能。那么端侧芯片跑大模型的效果如何呢&#xff1f;本文将在全志 A733 芯片平台上部署一个 DeepSeek-R1:1.5B 模型&#xff0c;并进行实测效果展示。 端侧平台环境 设备&#xff1a;全志A733平板…

nuxt中引入element-ui组件控制台报错问题

在使用element-ui组件的外层加一层 <client-only placeholder"Loading..."><van-button type"primary">主要按钮</van-button> </client-only> 实际使用&#xff1a; <div class"tab"><client-only placehol…

数据结构(考研)

线性表 顺序表 顺序表的静态分配 //线性表的元素类型为 ElemType//顺序表的静态分配 #define MaxSize10 typedef int ElemType; typedef struct{ElemType data[MaxSize];int length; }SqList;顺序表的动态分配 //顺序表的动态分配 #define InitSize 10 typedef struct{El…

【广州大学主办,发表有保障 | IEEE出版,稳定EI检索,往届见刊后快至1个月检索】第二届电气技术与自动化工程国际学术会议 (ETAE 2025)

第二届电气技术与自动化工程国际学术会议 (ETAE 2025) The 2nd International Conference on Electrical Technology and Automation Engineering 大会官网&#xff1a;http://www.icetae.com/【更多详情】 会议时间&#xff1a;2025年4月25-27日 会议地点&#xff1a…

【弹性计算】弹性计算的技术架构

弹性计算的技术架构 1.工作原理2.总体架构3.控制面4.数据面5.物理设施层 虽然弹性计算的产品种类越来越多&#xff0c;但不同产品的技术架构大同小异。下面以当前最主流的产品形态 —— 云服务器为例&#xff0c;探查其背后的技术秘密。 1.工作原理 云服务器通常以虚拟机的方…

EasyRTC轻量级SDK:智能硬件音视频通信资源的高效利用方案

在智能硬件这片广袤天地里&#xff0c;每一份资源的精打细算都关乎产品的生死存亡。随着物联网技术的疾速演进&#xff0c;实时音视频通信功能已成为众多设备的标配。然而&#xff0c;硬件资源的捉襟见肘&#xff0c;让开发者们常常陷入两难境地。EasyRTC&#xff0c;以它的极致…

Linux | 进程相关概念(进程、进程状态、进程优先级、环境变量、进程地址空间)

文章目录 进程概念1、冯诺依曼体系结构2、进程2.1基本概念2.2描述进程-PCB2.3组织进程2.4查看进程2.5通过系统调用获取进程标识符2.6通过系统调用创建进程-fork初识fork の 头文件与返回值fork函数的调用逻辑和底层逻辑 3、进程状态3.1状态3.2进程状态查看命令3.2.1 ps命令3.2.…

【ESP32接入国产大模型之Deepseek】

【ESP32接入国产大模型之Deepseek】 1. Deepseek大模型1.1 了解Deepseek api1.2 Http接口鉴权1.3. 接口参数说明1.3.1 请求体(request)参数1.3.2 模型推理 2. 先决条件2.1 环境配置2.2 所需零件 3. 核心代码3.1 源码分享3.2 源码解析3.3 连续对话修改后的代码代码说明示例输出注…