nodejs+wasm+rust debug及性能分析

文章目录

    • 背景
    • v8引擎自带的profile
    • linux的perf采集
    • wasm三方库性能分析
      • 编译debug版本wasm
      • rust程序debug调试
        • 异常模型
        • 正常模型
        • 结论
        • 优化

参考
Node使用火焰图优化CPU爆涨 - 掘金
【Node.js丨主题周】理解perf 与火焰图-腾讯云开发者社区-腾讯云
Easy profiling for Node.js Applications | Node.js
Diagnostics - Flame Graphs | Node.js
perf性能分析工具使用分享

背景

一个node服务在处理模型的时候,发现超时了,并且超过了3分钟的上限触发了报警。行吧,一般来说十几秒足够处理了,初步定位是mikktspace-wasm库的性能问题。

wasm正逐渐走进我们的程序生活,不少计算库都在用高性能语言重写,并通过wasm作为第三方包提供能力。例如博主最近用到的渲染相关的计算包,基本都是用c++和rust实现的,然后web端直接调用wasm即可。

写这篇博客呢,是因为博主一开始只是定位到三方库有问题就暂停了,毕竟是做后端的,也是存在一定的认知障碍吧,对不熟的东西也存在敬畏之心。然而根因不找到实在是难受,一路debug和性能分析下来,回头看看也没那么难。希望以后遇到类似的问题也可以乘风破浪,一路追下去,技术都是相通的,不应该存在壁垒。

v8引擎自带的profile

1、运行程序并采集
node --prof index.js xxx
v8会自动采集,并生成isolate-xxx文件
2、生成txt
node --prof-process isolate-xxx > processed.txt
vim直接打开,就可以查看采集的结果。采集结果分析参考以上链接。
3、查看火焰图npm install -g flamebearer
node --prof-process --preprocess -j isolate-xxx | flamebearer安装flamebearer,并执行上面的命令,会自动打开浏览器,查看生成的火焰图。

image.png

注意
运行node程序需要带两个参数:
–perf-basic-prof


通过--perf-basic-prof或 --perf-basic-prof-only-functions我们都可以启动支持
perf_events 的Node.js 应用程序。
--perf-basic-prof-only-functions产生较少的输出,因此它是开销最小的选项。
生成的文件在/tmp/perf-PID.map

–interpreted-frames-native-stack

Node.js 8.x 及更高版本对 V8 引擎中的 JavaScript 编译管道进行了新的优化,这有时会导致
性能无法访问函数名称/引用。使用以上参数可以解决。

linux的perf采集

1、perf采集
perf record -F 99 -g -- node --perf-basic-prof-only-functions index.js会在本地目录生成perf.data文件。2、生成火焰图
perf script | /home/xxx/FlameGraph/stackcollapse-perf.pl | /home/xxx/FlameGraph/flamegraph.pl > perf.svg下载FlameGraph项目,然后使用该项目提供的脚本生成火焰图即可。3、浏览器打开
python -m http.server 8000
浏览器访问ip:8000/perf.svg即可4、运行的时候查看cpu占用
perf top -p pid

使用js的三方库生成火焰图

1、采集perf (同上)
2、安装stackvis库
npm install -g stackvis3、script解析perf.data
perf script > perf.out4、生成火焰图的html
stackvis perf < perfs.out > flamegrap.htm5、浏览器查看(同上)

image.png

wasm三方库性能分析

如上所示,有些库使用wasm,导致只能看到库函数占用了97%的cpu,但是却看不到细节。针对这种情况可以考虑编译对应第三方库版本的debug版wasm文件,替换一下,重新采样。

编译debug版本wasm

例如:https://github.com/donmccurdy/mikktspace-wasm 这个库,是用rust编译成wasm的
(1)安装rust环境
https://developer.mozilla.org/zh-CN/docs/WebAssembly/Rust_to_Wasm
(2)编译debug版本

1、编译target为nodejs,对应commonjs标准
~/.cargo/bin/wasm-pack build --dev --target nodejs -d ./pkg/main --out-name mikktspace_main解释:--dev: 编译debug版本-d : 指定输入结果目录,设置为pkg/main--out-name: 指定生成的文件名前缀,wasm文件会自动加上_bg.wasm后缀2、编译target为bundler,对应打包工具的导入标准
~/.cargo/bin/wasm-pack build --dev -d ./pkg/bundler --out-name mikktspace_module3、查看编译的wasm是否是debug的(1)安装wabtsudo pacman -Si wabtwabt自带的有wasm-objdump,可以查看wasm的头信息(2)wasm-objdump -h mikktspace_main_bg.wasmmikktspace_main_bg.wasm:        file format wasm 0x1Sections:Type start=0x0000000e end=0x000000fa (size=0x000000ec) count: 35Import start=0x00000100 end=0x00000268 (size=0x00000168) count: 7Function start=0x0000026e end=0x00000542 (size=0x000002d4) count: 722Table start=0x00000548 end=0x0000054d (size=0x00000005) count: 1Memory start=0x00000553 end=0x00000556 (size=0x00000003) count: 1Global start=0x0000055c end=0x00000565 (size=0x00000009) count: 1Export start=0x0000056b end=0x000005fb (size=0x00000090) count: 7Elem start=0x00000601 end=0x00000663 (size=0x00000062) count: 1Code start=0x00000669 end=0x00048a07 (size=0x0004839e) count: 722Data start=0x00048a0d end=0x0004d858 (size=0x00004e4b) count: 1Custom start=0x0004d85e end=0x0005b3f4 (size=0x0000db96) "name"Custom start=0x0005b3fa end=0x0005b475 (size=0x0000007b) "producers"Custom start=0x0005b47b end=0x0005b4a7 (size=0x0000002c) "target_features"可以看到没有debuginfo信息。4、配置cargo.toml
参考:https://rustwasm.github.io/docs/wasm-pack/cargo-toml-configuration.html[package.metadata.wasm-pack.profile.dev.wasm-bindgen]
dwarf-debug-info = false5、重新编译并查看
Custom start=0x00062694 end=0x0014bc2d (size=0x000e9599) ".debug_info"多了一些debuginfo信息。

(3)替换node_moudles中的mikktspace/dist下的main和module目录
(4)重新perf采集数据,生成svg
image.png
成功采集到mikktspace这个库的调用栈以及cpu耗时。

(5)对比正常和异常情况下的火焰图

正常
image.png
相比上面的火焰图,可以发现正常的火焰图:

  1. cpu耗时分布较合理
  2. 无长时间耗时函数分布
  3. 异常火焰图耗时较久的函数DegenEpilogue在正常火焰图中并没有。

因此重点看下DegenEpilogue函数即可。

rust程序debug调试

参考:https://github.com/fucking-translation/blog/blob/main/src/lang/rust/14-%E4%BD%BF%E7%94%A8GDB%E8%B0%83%E8%AF%95Rust%E5%BA%94%E7%94%A8.md

1、编译debug版本
cargo默认编译出来的就是debug版本。指定编程生成的程序名为debug
cargo build --example debug2、rust-gdb调试
rust-gdb调试指令和gdb一样。
(1) 进入gdb
rust-gdb debug
(2) 设置断点
b xxx.rs:10(3) 开启可视化
layout src
如果页面乱了,ctrl+l 可以恢复代码页面(4) 调试
n : 下一步
s : 进入函数内部
c: 运行到下一个断点
异常模型

1、generateTspace部分,iNrActiveGroup = 19w,循环19w次,速度较快,10s执行完整个函数。
2、运行到DegenEpilogue, iNrTrianglesIn = 24w,
while t < iTotTris {} 这个循环耗时90s

// iDegenTriangles = 32412
// iDegenTriangles代表不合法的三角形面
iNrTrianglesIn = iTotTris - iDegenTriangles;

while t < iNrTrianglesIn {} 不耗时

正常模型

1、generateTspace部分,iNrActiveGroup = 172w,16s运行完整个函数
2、运行到DegenEpilogue, iNrTrianglesIn = 58w
while t < iTotTris {} 这个循环没走
原因是不符合whilet条件,t= iTotTris ,关键就在上一步传过来的iNrTrianglesIn和iTotTris

// iDegenTriangles = 0
// iDegenTriangles代表不合法的三角形面
iNrTrianglesIn = iTotTris - iDegenTriangles;

while t < iNrTrianglesIn {} 不耗时

结论

异常的模型中,不合法三角形的数量较多,需要通过DegenEpilogue函数进行辅助处理。正常的模型因为不合法三角形面数量较少,因此不需要进行DegenEpilogue函数处理。

mikktspace计算切面算法有多种语言实现,其中rust程序和c++程序对比来说,c++使用了二分来提升性能,rust和c程序均采用遍历的方式。可以考虑使用hash表减少循环层数或者二分提升查询性能。

mikktspace的c++库:https://github.com/naetherm/mikktspace
mikktspace的c库:https://github.com/mmikk/MikkTSpace

优化

rust程序中,存在双层循环如下:

// iTotTris - t = 3w
while t < iTotTris {// iNrTrianglesIn * 3 = 72wwhile bNotFound && j < 3i32 * iNrTrianglesIn {}
}双层循环情况下,性能较差。内部的循环使用hash表代替,直接通过key去获取。优化后单次循环耗时从ms级
优化到ns级。优化前耗时:90s
优化后耗时:27ms

end

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【1419. 数青蛙】

目录 一、题目描述二、算法原理三、代码实现 一、题目描述 二、算法原理 三、代码实现 代码实现1&#xff1a;我自己写的比较挫&#xff0c;但是比较简单。 class Solution { public:int minNumberOfFrogs(string croakOfFrogs) {unordered_map<char,int> hash;hash[c]…

word修改公式默认字体并打出漂亮公式

文章目录 word公式简介传统方法1——mathtype传统方法2——word自带公式编辑器最简洁方法——更改word自带公式字体快捷方式效果展示 word公式简介 word自带的公式字体Cambria Math不可否认很丑&#xff0c;要打出latex格式的漂亮字体很困难。使用Markdown工具很多只能导出为不…

MSVCR100.dll丢失修复方法,MSVCR100.dll丢失的解决方法

今天我要和大家分享的是&#xff1a;msvcr100.dll丢失的6种解决方法。 首先&#xff0c;让我们来了解一下msvcr100.dll丢失的原因。msvcr100.dll是Microsoft Visual C 2010的一个组件&#xff0c;它包含了许多运行库文件&#xff0c;这些文件是许多应用程序所必需的。当msvcr1…

算法、语言混编、分布式锁与分布式ID、IO模型

一、算法初识 数据结构和算法是程序的基石。我们使用的所有数据类型就是一种数据结构&#xff08;数据的组织形式&#xff09;&#xff0c;写的程序逻辑就是算法。 算法是指用来操作数据、解决程序问题的一组方法。 对于同一个问题&#xff0c;使用不同的算法&#xff0c;也…

编译原理-词法分析器

文章目录 对于词法分析器的要求概念词法分析器的功能和输出形式 词法分析器的设计词法分析器的结构单词符号的识别&#xff1a;超前搜索状态转换图 正规表达式和有限自动机正规式和正规集确定有限自动机&#xff08;DFA&#xff09;非确定有限自动机&#xff08;NFA&#xff09…

【经典PageRank 】02/2 算法和线性代数

系列前文&#xff1a;【经典 PageRank 】01/2 PageRank的基本原理-CSDN博客 一、说明 并非所有连接都同样重要&#xff01; 该算法由 Sergey 和 Lawrence 开发&#xff0c;用于在 Google 搜索中对网页进行排名。基本原则是重要或值得信赖的网页更有可能链接到其他重要网页。例…

【数据结构练习题】消失的数字 --- 三种解法超详解

✨博客主页&#xff1a;小钱编程成长记 &#x1f388;博客专栏&#xff1a;数据结构练习题 &#x1f388;相关博文&#xff1a;添加逗号 消失的数字 1. &#x1f388;题目2. &#x1f388;解题思路✨方法一&#xff1a;先排序&#xff0c;再找缺失的值✨方法二&#xff1a;按位…

scrapy的安装和使用

一、scrapy是什么&#xff1a;Scrapy是一个为了爬取网站数据&#xff0c;提取结构性数据而编写的应用框架&#xff0c;可以应用在包括数据挖掘&#xff0c;信息处理或存储历史数据等一系列的程序 二、scrapy的安装&#xff1a;pip install scrapy -i https://pypi.douban.com/…

如何系列 如何玩转远程调用之OpenFegin+SpringBoot(非Cloud)

文章目录 简介原生Fegin示例基础契约日志重试编码器/解码器自定义解码器 请求拦截器响应拦截器表单文件上传支持错误解码器断路器指标metrics客户端 配合SpringBoot&#xff08;阶段一&#xff09;配合SpringBoot&#xff08;阶段二&#xff09;1.EnableLakerFeignClients2.Lak…

初识Kubernetes

一、k8s的由来及其技术运用 1.1 k8s的简介 Kubernetes&#xff0c;词根源于希腊语的 舵手、飞行员。在国内又称k8s&#xff08;因为k和s之间有8个字母&#xff0c;所以得名。“国内程序员的幽默”&#xff09;。用于自动部署、扩展和管理“容器化&#xff08;containerized…

【软件安装】Linux系统中安装MySQL数据库服务

这篇文章&#xff0c;主要介绍如何在Linux系统中安装MySQL数据库服务。 目录 一、Linux安装MySQL 1.1、下载MySQL安装包 1.2、解压MySQL安装包 1.3、更改存放目录 1.4、创建用户组和用户 1.5、创建数据目录data 1.6、创建my.cnf配置文件 1.7、初始化数据库 1.8、添加m…

云计算要学习哪些技术?

学习云计算需要涉及多个技术领域和相关的工具、平台和框架。以下是一个详细的介绍&#xff0c;帮助您了解学习云计算所需的技术。 1. 虚拟化技术 虚拟化是云计算的基础&#xff0c;因此了解虚拟化技术至关重要。学习虚拟化技术时&#xff0c;需要掌握以下知识点&#xff1a; …

C# 使用 LibUsbDotNet 实现 USB 设备检测

国庆节回来后的工作内容&#xff0c;基本都在围绕着各种各样的硬件展开&#xff0c;这无疑让本就漫长的 “七天班” &#xff0c;更加平添了三分枯燥&#xff0c;我甚至在不知不觉中学会了&#xff0c;如何给打印机装上不同尺寸的纸张。华为的 Mate 60 发布以后&#xff0c;人群…

RK3568平台开发系列讲解(应用篇)串口应用编程之串口介绍

🚀返回专栏总目录 文章目录 一、串口介绍1.1、数据传输方式1.2、数据格式1.3、波特率1.4、硬件流控制和软件流控制1.5、错误检测1.6、串口编程二、串口设备节点介绍沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 串口设备是嵌入式开发中最常用的外设之一,通过串口…

图论01-【无权无向】-图的基本表示-邻接矩阵/邻接表

文章目录 1. 代码仓库2. 图的基本表示的比较3. 邻接矩阵&#xff1a;Array和TreeSet3.1 图示3.2 Array主要代码解析3.3 测试输出3.4 使用TreeSet的代码 4. 邻接表&#xff1a;LinkedList4.1 图示4.2 LinkedList主要代码解析4.3 测试输出 5. 完整代码5.1 邻接表 - Array5.2 邻接…

数据库MongoDB

MongoDB记录是一个文档&#xff0c;由一个字段和值对组成的数据结构&#xff0c;文档类似于JSON对象。 一个文档认为就是一个对象&#xff0c;字段的数据类型是字符型&#xff0c;值除了使用基本类型外&#xff0c;还可以包括其他文档&#xff0c;普通数组和文档数组。 一、…

rust学习——方法 Method

文章目录 方法 Method定义方法self、&self 和 &mut self方法名跟结构体字段名相同 带有多个参数的方法关联函数多个 impl 定义为枚举实现方法 rust 结构体与枚举的区别回答1回答2 方法 Method 从面向对象语言过来的同学对于方法肯定不陌生&#xff0c;class 里面就充斥…

【proteus】8086仿真/汇编:创建项目并添加汇编代码文件

1.创建好新项目 2.点击source code 弹出VSM 3. 4.注意两个都不勾选 可以看到schematic有原理图出现 5. 再次点击source code 6.project/project settings&#xff0c;取消勾选embed 7. add 8.输入文件名保存后&#xff1a; 注意&#xff1a;proteus不用写dos的相关语句 。

C++第一篇--关键字以及命名空间

&#x1f4d9; 作者简介 &#xff1a;RO-BERRY &#x1f4d7; 学习方向&#xff1a;致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f4d2; 日后方向 : 偏向于CPP开发以及大数据方向&#xff0c;欢迎各位关注&#xff0c;谢谢各位的支持 目录 &#x1f384; 前言 …

31一维信号滤波(限幅滤波、中值滤波、均值滤波、递推平均滤波),MATLAB程序已调通,可直接运行。

一维信号滤波&#xff08;限幅滤波、中值滤波、均值滤波、递推平均滤波&#xff09;&#xff0c;MATLAB程序已调通&#xff0c;可直接运行。 31matlab、中值滤波、信号处理 (xiaohongshu.com)