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.rhkb.cn/news/169734.html

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

相关文章

RK3568平台开发系列讲解(应用篇)串口应用编程之串口的使用步骤

🚀返回专栏总目录 文章目录 一、配置参数1.1、获取当前串口的配置参数1.2、修改和写入串口的配置参数二、模式2.1、输入模式2.2、输出模式2.3、控制模式2.4、本地模式2.5、特殊控制字符沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 串口设备是嵌入式开发中最常用的…

Node.js在Python中的应用实例解析

随着互联网的发展&#xff0c;数据爬取成为了获取信息的重要手段。本文将以豆瓣网为案例&#xff0c;通过技术问答的方式&#xff0c;介绍如何使用Node.js在Python中实现数据爬取&#xff0c;并提供详细的实现代码过程。 Node.js是一个基于Chrome V8引擎的JavaScript运行时环境…

Flutter的Invalid use of a private type in a public API警告

文章目录 问题描述有问题的源码 问题原因解决方法 问题描述 自己在写Flutter 应用时发现了一个Invalid use of a private type in a public API警告。 发现很多官方的例子也有这个问题。 有问题的源码 有问题的源码如下&#xff1a; class MyTabPage extends StatefulWid…

【三维重建-PatchMatchNet复现笔记】

【三维重建-PatchMatchNet复现笔记】 1 突出贡献2 数据集描述3 训练PatchMatchNet3.1 输入参数3.2 制定数据集加载方式 1 突出贡献 在计算机GPU和运行时间受限的情况下&#xff0c;PatchMatchNet测试DTU数据集能以较低GPU内存和较低运行时间&#xff0c;整体误差位列中等&#…

python sqlalchemy(ORM)- 02 表关系

文章目录 表关系ORM表示 1v1ORM表示 1vm 表关系 1:1&#xff0c;表A 中的一条记录&#xff0c;仅对应表B中的一条记录&#xff1b;表B的一条记录&#xff0c;仅对应表A的一条记录。1:m&#xff0c;表A中的一条记录&#xff0c;对应表B中的多条记录&#xff0c;表B中的一条记录…

【机器学习】集成学习Boosting

文章目录 集成学习BoostingAdaBoost梯度提升树GBDTXGBoostxgboost库sklearn APIxgboost库xgboost应用 集成学习 集成学习&#xff08;ensemble learning&#xff09;的算法主要包括三大类&#xff1a;装袋法&#xff08;Bagging&#xff09;&#xff0c;提升法&#xff08;Boo…

在 Python 中使用 Pillow 进行图像处理【2/4】

第二部分 一、说明 该文是《在 Python 中使用 Pillow 进行图像处理》的第二部分&#xff0c;主要介绍pil库进行一般性处理&#xff1a;如&#xff1a;图像卷积、钝化、锐化、阈值分割。 二、在 Python 中使用 Pillow 进行图像处理 您已经学习了如何裁剪和旋转图像、调整图像大…

26. 通过 cilium pwru了解网络包的来龙去脉

pwru是一种基于eBPF的工具,可跟踪Linux内核中的网络数据包,并具有先进的过滤功能。它允许对内核状态进行细粒度检查,以便通过调试网络连接问题来解决传统工具(如iptables TRACE或tcpdump)难以解决甚至无法解决的问题。在本文中,我将介绍pwru如何在不必事先了解所有内容的…

【java】【重构二】分模块开发版本锁定以及耦合(打包)实战

目录 一、创建dependencyManagement标签 二、 将需要版本控制的依赖版本进行标签设置 三、将需要版本控制的依赖从各子模块迁移到此处 四、将父模块的依赖版本控制 五、删除子模块的全部版本 1、bocai-web-management模块 2、bocai-utils模块 六、打包 1、确定代码都…

shein面试:nacos无入侵配置,做过吗,怎么做?

说在前面 在40岁老架构师 尼恩的读者社区(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如阿里、滴滴、极兔、有赞、shein 希音、百度、网易的面试资格&#xff0c;遇到很多很重要的面试题&#xff1a; 无入侵配置&#xff0c;做过吗&#xff0c;怎么做的&#xff1f;Na…

学习package.json

package.json 文件&#xff0c;它是项目的配置文件&#xff0c;常见的配置有配置项目启动、打包命令&#xff0c;声明依赖包等。package.json 文件是一个 JSON 对象&#xff0c;该对象的每一个成员就是当前项目的一项设置。 {"name": "monorepo_frame",&q…

Go 实现选择排序算法及优化

选择排序 选择排序是一种简单的比较排序算法&#xff0c;它的算法思路是首先从数组中寻找最小&#xff08;大&#xff09;的元素&#xff0c;然后放到数组中的第一位&#xff0c;接下来继续从未排序的元素中寻找最小&#xff08;大&#xff09;元素&#xff0c;然后放到已排序…

Zabbix告警与飞书集成

一、配置媒介 1、下载飞书的Zabbix媒介类型如下&#xff1a; zbx_export_mediatype_feishu.xml 2、Zabbix中导入媒介类型 Zabbix Web中选择管理 > 报警媒介&#xff0c;然后导入该媒介类型。导入规则选择“更新现有的”和“创建新的”。 3、配置飞书媒介类型用户 Zabbi…

【MyBatis进阶】mybatis-config.xml分析以及try-catch新用法

目录 尝试在mybatis项目中书写增删改查 遇见问题&#xff1a;使用mybaties向数据库中插入数据&#xff0c;idea显示插入成功&#xff0c;但是数据库中并没有数据变化? MyBatis核心配置文件剖析 细节剖析&#xff1a; try-catch新用法 截至目前我的项目存在的问题&#xf…

AD20~PCB的板层设计和布线

1、打开51单片机最小系统的工程文件。 2、完成原理图后续工作&#xff1a;打开原理图文件&#xff0c;双击元件“CH340X”窗口右边弹出元件内部属性设置界面&#xff0c;在窗口下方点击“Footprint ->Add…”按钮进入添加元件类型界面&#xff0c;进入元件封装选择界面&…

红日靶场复现1

红日靶场复现1&#x1f388;&#x1f388;&#x1f388;&#x1f388;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f389;&#x1f388;&#x1f388;&#x1f389;&#x1f388;&#x1f388;&#x1f389; 一、主机发现&#x1f388;&#x1…

Http长连接同一个socket多个请求和响应如何保证一一对应?

HTTP/2引入二进制数据帧和流的概念&#xff0c;其中帧对数据进行顺序标识&#xff0c;如下图所示&#xff0c;这样浏览器收到数据之后&#xff0c;就可以按照序列对数据进行合并&#xff0c;而不会出现合并后数据错乱的情况。同样是因为有了序列&#xff0c;服务器就可以并行的…

【MySQL-->数据操作】

文章目录 前言一、insert1.单行插入2.多行插入3.插入更新/替换 二、select1.全列查询2.指定列插入3.列别名4. 表达式计算5.去重6.where条件查询7.排序8.limit分页显示 三、update四、delete五、插入查询结果六、聚合函数六、聚合分组1.格式2.where和having的区别 前言 一、inse…

深入理解Redis集群模式、协议、元数据维护方式

文章目录 &#x1f34a; 集群模式&#x1f34a; 集群协议&#x1f34a; 元数据维护方式&#x1f389; 集中式&#x1f389; gossip 协议 &#x1f4d5;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出…

nginx中gzip推荐配置

#开启gzip压缩功能 gzip on; #设置允许压缩的页面最小字节数; 这里表示如果文件小于10个字节,就不用压缩,因为没有意义,本来就很小. gzip_min_length 10k; #设置压缩缓冲区大小,此处设置为4个16K内存作为压缩结果流缓存 gzip_buffers 4 16k;#压缩版本 gzip_http_version 1…