linux perf
perf是Linux性能分析工具的集合,它提供了丰富的命令来收集和分析程序运行时的性能数据。perf能够报告CPU使用率、缓存命中率、分支预测成功率等多种硬件级别的事件,同时也支持软件级别的事件,如页面错误、任务切换等。perf是理解程序性能瓶颈、进行性能优化的重要工具。
perf的主要作用
- 性能分析:通过监控硬件和软件事件,帮助开发者理解程序的性能瓶颈。
- 热点函数定位:找出程序中CPU使用时间最多的函数。
- 系统监控:监控系统级别的性能指标,如CPU使用率、上下文切换次数等。
- 调用栈分析:提供函数调用栈信息,帮助开发者理解函数调用关系。
perf的基本用法
-
安装:在大多数Linux发行版中,
perf工具包含在linux-tools包中。可以通过包管理器安装,例如,在Ubuntu上使用sudo apt-get install linux-tools-common linux-tools-generic。 -
列出可用事件:使用
perf list命令可以查看所有可监控的事件。 -
性能统计:
perf stat命令用于收集和报告程序的性能统计信息。例如,perf stat ./your_program会运行your_program并报告其性能统计。 -
记录性能事件:
perf record命令用于记录特定性能事件。例如,perf record -e cycles ./your_program会记录程序运行时的CPU周期事件。 -
生成报告:
perf report命令用于分析perf record收集的数据,并生成报告。这个报告可以帮助开发者定位性能瓶颈。 -
注解源代码:
perf annotate命令用于将性能事件映射到源代码上,帮助开发者理解哪些代码行是热点。 -
查看调用栈:使用
perf record时加上-g选项可以记录调用栈信息,然后使用perf report查看,这对于理解函数间的调用关系非常有用。
示例
-
收集性能统计:
perf stat -e cache-misses,cache-references,instructions,cycles ./your_program这个命令会运行
your_program,并报告缓存未命中次数、缓存引用次数、指令数和CPU周期数。 -
记录和报告性能数据:
perf record -g ./your_program perf report这会记录
your_program的性能数据,并生成一个性能报告,报告中包含了热点函数和调用栈信息。
通过使用perf工具,开发者可以深入了解程序的运行时性能,从而进行有效的性能优化。
分析Java项目的性能时,perf可以帮助你理解底层的系统和硬件层面的性能问题,但由于Java运行在虚拟机(JVM)之上,直接使用perf可能不足以提供足够的信息来定位到具体的Java方法。不过,通过结合使用perf和其他工具,可以有效地分析Java应用的性能。以下是一些步骤和技巧:
1. 开启JVM的本地符号
为了让perf能够识别Java方法,需要确保JVM启动时带有适当的参数来导出本地符号。对于HotSpot JVM,可以使用以下参数:
-XX:+PreserveFramePointer -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints
这些参数的作用是:
-XX:+PreserveFramePointer:保留帧指针,以便perf可以构建调用栈。-XX:+UnlockDiagnosticVMOptions:解锁诊断选项。-XX:+DebugNonSafepoints:确保即使在非安全点也能生成足够的调试信息。
2. 使用perf record收集性能数据
运行你的Java应用,并使用perf record来收集性能数据。例如:
perf record -F 99 -p $(pgrep -n java) -g -- sleep 30
这个命令会:
-F 99:以每秒99次的频率采样。-p $(pgrep -n java):指定要监控的进程ID,这里使用pgrep来找到Java进程的PID。-g:记录调用栈信息,以便分析。-- sleep 30:收集30秒的性能数据。
3. 使用perf report分析性能数据
收集完数据后,使用perf report来查看性能报告。这将显示CPU使用最多的函数和调用栈。
4. 使用perf-map-agent和FlameGraph工具
由于perf默认可能无法解析Java方法名称,你可以使用perf-map-agent来生成Java方法的映射文件,然后perf就能识别Java方法了。perf-map-agent是一个开源工具,可以在GitHub上找到。
perf默认情况下可能无法解析Java方法名称,因为Java方法在运行时是由Java虚拟机(JVM)动态编译的,而不是直接作为二进制代码存在。为了让perf能够识别Java方法,可以使用perf-map-agent来生成一个包含Java方法名称和相应内存地址的映射文件。这个映射文件随后可以被perf使用,以便在性能分析报告中显示具体的Java方法名称。
使用perf-map-agent的步骤
-
- 安装
perf-map-agent:
- 首先,确保你有一个编译环境(如
gcc和make),因为安装perf-map-agent可能需要编译一些源代码。 - 克隆
perf-map-agent的GitHub仓库:git clone https://github.com/jvm-profiling-tools/perf-map-agent.git - 进入
perf-map-agent目录,并使用cmake和make编译项目:cd perf-map-agent cmake . make
- 安装
-
- 生成映射文件:
- 在运行你的Java应用的同时,使用
perf-map-agent生成映射文件。这通常涉及到运行一个特定的脚本或命令,该命令会附加到运行中的JVM进程,并生成映射文件/tmp/perf-<pid>.map,其中<pid>是JVM进程的ID。 - 例如,使用
create-java-perf-map.sh脚本(这个脚本随perf-map-agent提供):
这里./create-java-perf-map.sh <pid><pid>是你的Java应用的进程ID。
-
- 使用
perf进行性能分析:
- 现在,当你使用
perf record和perf report进行性能分析时,perf将能够利用生成的映射文件来解析Java方法名称。 - 进行性能分析:
perf record -F 99 -p <pid> -g -- sleep 30 perf report
- 使用
-
- 查看性能报告:
- 使用
perf report查看性能报告时,你应该能看到具体的Java方法名称,而不仅仅是内存地址。这使得分析Java应用的性能问题变得更加直观和容易。
注意事项
- 确保你的
perf版本和Linux内核版本兼容,以便正确地解析映射文件。 - 使用
perf-map-agent时,可能需要根据你的系统环境调整编译命令或脚本。 - 生成的映射文件仅在Java应用运行期间有效。如果Java应用重启,你需要重新生成映射文件。
通过使用perf-map-agent,perf工具能够提供更加详细和有用的性能分析数据,帮助开发者优化Java应用的性能。
生成映射文件后,你还可以使用Brendan Gregg的FlameGraph工具来生成火焰图,这是一种直观展示性能瓶颈的图表。
FlameGraph是一个强大的工具,用于可视化和分析软件性能,特别是CPU使用情况。对于Java项目,结合perf、perf-map-agent和FlameGraph,可以有效地识别性能热点和瓶颈。以下是如何使用这些工具来分析和优化Java项目的步骤:
FlameGraph使用步骤
步骤1:收集性能数据
-
确保Java应用以允许性能分析的模式运行。这通常意味着需要使用特定的JVM参数,如
-XX:+PreserveFramePointer,以便perf能够获取到更准确的调用栈信息。 -
使用
perf收集性能数据。找到Java应用的进程ID(PID),然后运行:perf record -F 99 -p [PID] -g -- sleep [duration]其中
[PID]是Java进程的ID,[duration]是收集数据的时间长度(秒)。
步骤2:生成映射文件
-
安装
perf-map-agent。按照之前的指导安装并编译perf-map-agent。 -
生成映射文件。在Java应用运行的同时,使用
perf-map-agent为perf生成映射文件:cd perf-map-agent/out java -cp attach-main.jar:$JAVA_HOME/lib/tools.jar net.virtualvoid.perf.AttachOnce [PID]这将为
perf生成一个映射文件,使其能够解析Java方法名称。
步骤3:生成FlameGraph
-
使用
perf生成堆栈折叠文件:perf script > out.perf -
使用FlameGraph工具生成火焰图:
cd FlameGraph ./stackcollapse-perf.pl ../out.perf > out.folded ./flamegraph.pl out.folded > flamegraph.svg这将生成一个名为
flamegraph.svg的火焰图文件,你可以使用任何支持SVG格式的浏览器或图像查看器打开它。
图片示例
步骤4:分析火焰图
- 查看火焰图:火焰图的每一个“火焰”代表一个函数调用栈,其中的宽度表示该函数及其子函数占用CPU时间的比例。
- 识别热点:火焰图的顶部是CPU使用最多的函数。寻找“宽”的火焰,这些是你的性能热点。
- 深入分析:从热点函数开始,向下追踪其调用栈,了解性能瓶颈的来源。
步骤5:优化代码
- 优化热点函数:针对火焰图中识别出的热点函数,考虑算法优化、减少不必要的计算、优化数据结构等方法。
- 重构代码:如果性能瓶颈是由于不合理的代码结构引起的,考虑重构代码以提高效率。
- 利用并发:对于可以并行处理的任务,考虑使用Java的并发和多线程功能来提高性能。
5. 结合使用jstack
对于Java应用,jstack是一个非常有用的工具,它可以生成Java线程的堆栈跟踪。通过将perf的输出与jstack的输出相结合,可以更准确地定位性能问题。
jstack 是一个用于生成 Java 线程堆栈跟踪的工具,它可以帮助开发者分析和诊断 Java 应用程序的性能问题,特别是线程相关的问题。以下是如何使用 jstack 分析 Java 项目的步骤:
jstack使用步骤
步骤1:找到 Java 进程 ID
首先,你需要找到正在运行的 Java 应用程序的进程 ID(PID)。你可以使用 jps 或 ps 命令来找到 PID。
jps -l
或者:
ps -ef | grep java
步骤2:生成线程堆栈跟踪
使用 jstack 命令生成指定 Java 进程的线程堆栈跟踪。假设 PID 是 12345,你可以运行:
jstack -l 12345 > thread_dump.txt
这将生成一个包含所有线程堆栈跟踪的文件 thread_dump.txt。
步骤3:分析线程堆栈跟踪
打开 thread_dump.txt 文件,分析其中的线程堆栈信息。以下是一些常见的分析方法:
-
查找死锁:
jstack会自动检测死锁并在输出中报告。如果存在死锁,你会在输出中看到类似 “Found one Java-level deadlock” 的信息。 -
分析线程状态:每个线程的堆栈跟踪信息会包含线程的状态(如
RUNNABLE、BLOCKED、WAITING等)。通过分析线程状态,可以了解线程是否在等待资源、被阻塞或正在运行。 -
查找热点代码:如果某些线程的堆栈跟踪信息显示它们在相同的方法中花费了大量时间,这些方法可能是性能瓶颈。你可以重点分析这些方法,寻找优化的机会。
-
分析锁争用:如果多个线程在等待相同的锁,可能会导致性能问题。通过分析堆栈跟踪信息中的锁信息,可以识别锁争用的情况。
示例分析
以下是一个简单的 jstack 输出示例:
"main" #1 prio=5 os_prio=0 tid=0x00007f8c5400a000 nid=0x1b03 runnable [0x00007f8c58bfe000]java.lang.Thread.State: RUNNABLEat com.example.MyClass.myMethod(MyClass.java:123)at com.example.MyClass.run(MyClass.java:456)at java.lang.Thread.run(Thread.java:748)"Thread-1" #2 prio=5 os_prio=0 tid=0x00007f8c5400b000 nid=0x1b04 waiting on condition [0x00007f8c58cff000]java.lang.Thread.State: WAITING (parking)at sun.misc.Unsafe.park(Native Method)- parking to wait for <0x00000000d5c6c6c8> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)at com.example.MyClass.run(MyClass.java:789)at java.lang.Thread.run(Thread.java:748)
在这个示例中:
- 主线程(
main)处于RUNNABLE状态,正在执行com.example.MyClass.myMethod方法。 Thread-1线程处于WAITING状态,正在等待一个ReentrantLock。
优化建议
-
优化热点代码:对于处于
RUNNABLE状态的线程,分析其堆栈跟踪信息,找出占用大量时间的方法,并进行优化。 -
减少锁争用:对于处于
BLOCKED或WAITING状态的线程,分析其等待的锁,尝试减少锁的持有时间或使用更细粒度的锁。 -
避免死锁:如果检测到死锁,分析相关线程的堆栈跟踪信息,找出死锁的原因,并修改代码以避免死锁。
通过使用 jstack 生成和分析线程堆栈跟踪信息,可以有效地诊断和优化 Java 应用程序的性能问题。
总结
虽然perf主要用于分析底层系统和硬件性能,但通过上述方法,它也可以结合使用perf-map-agent、FlameGraph、jstack工具,成为分析Java应用性能的有力工具。
相关文章:
linux perf
perf是Linux性能分析工具的集合,它提供了丰富的命令来收集和分析程序运行时的性能数据。perf能够报告CPU使用率、缓存命中率、分支预测成功率等多种硬件级别的事件,同时也支持软件级别的事件,如页面错误、任务切换等。perf是理解程序性能瓶颈…...
Linux--网络层IP
IP协议 IP协议,全称Internet Protocol(互联网协议),是TCP/IP协议族中的核心协议之一,用于在互联网络上进行数据的传输。IP协议的主要功能是确保数据从一个网络节点(如计算机、服务器、路由器等)…...
浅谈vite之import.meta
一. 解析 开发者使用一个模块时,有时需要知道模板本身的一些信息(比如模块的路径)。现在有一个提案,为 import 命令添加了一个元属性 import.meta,返回当前模块的元信息。 import.meta只能在模块内部使用,如…...
【Pytorch实用教程】Pytorch中nn.Sequential的用法
nn.Sequential 是 PyTorch 中用于构建神经网络的一种容器类,它可以按顺序封装多个子模块(层),并依次将输入数据传递给这些子模块。这样可以简化模型的定义,使得代码更加简洁和易读。 文章目录 基本用法方法一:直接传递子模块方法二:使用 `OrderedDict`动态构建模型优点注…...
Shopify被封?Shopify店铺开店到防封全面指南
Shopify,作为独立电商建站领域的佼佼者,其SaaS模式简化了建站流程,无需编程背景即可创建线上店铺,吸引了众多商家的目光。本文将详细讲解Shopify店铺从注册、运营到防封的每一个关键环节,为商家提供一站式指导…...
11. 盛最多水的容器
一题目: 二:代码: class Solution { public:int maxArea(vector<int>& height) {int l0;int rheight.size()-1;int ans0;while(l<r){int a(r-l)*min(height[l],height[r]);ansmax(ans,a);if(height[l]<height[r]) l;else r-…...
react如何父子组件传参
在React中,父子组件之间的传参主要通过props(属性)来实现。子组件通过props接收来自父组件的数据,而父组件则可以通过在子组件标签上设置属性(即props)来传递数据。下面是一个简单的例子来说明这个过程。 …...
【C++】二维数组 数组名
二维数组名用途 1、查看所占内存空间 2、查看二维数组首地址 针对第一种用途,还可以计算数组有多少行、多少列、多少元素 针对第二种用途,数组元素、行数、列数都是连续的,且相差地址是有规律的 下面是一个实例 #include<iostream&g…...
【蘑菇书EasyRL】强化学习,笔记整理
【蘑菇书EasyRL】强化学习,笔记整理 1.笔记整理1.1 学习和决策代码框架 2. 遇到的buggym 环境,新版本python无法使用env_specs envs.registry.all() 报错 蘑菇书的教程地址: https://datawhalechina.github.io/easy-rl/#/chapter1/chapter1?…...
尚硅谷谷粒商城项目笔记——三、安装docker【电脑CPU:AMD】
三、安装docker 注意: 因为电脑是AMD芯片,自己知识储备不够,无法保证和课程中用到的环境一样,所以环境都是自己根据适应硬件软件环境重新配置的,这里的虚拟机使用的是VMware。 首先关闭防火墙和安全策略 systemctl…...
【8-9月份唯一机械电气计算机主题的IEEE会议】第七届机电一体化与计算机技术工程国际学术会议(MCTE 2024,8月23-25)
由广东博士创新发展促进会、输变电装备技术全国重点实验室联合主办,重庆大学电气工程学院、AEIC学术交流中心协办的第七届机电一体化与计算机技术工程国际学术会议(MCTE 2024)将于2024年8月23-25日在中国广州隆重举行。 大会诚挚邀请您投递相…...
YOLOv8改进 | 主干网络 | 简单而优雅且有效的VanillaNet 【华为诺亚方舟】
秋招面试专栏推荐 :深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 专栏目录 :《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有80+篇内容,内含各种Head检测头、损失函数Loss、…...
Tomcat高可用集群(实例详解)
一.环境准备 虚拟机的版本:VMware-workstation-full-15.5.6-16341506.exe系统镜像版本:CentOS-6.10-x86_64-bin-DVD1.iso,全新安装,桌面版,可上网系统内存大小:1GB系统硬盘大小:20GB连接工具版…...
搭建自己的金融数据源和量化分析平台(五):更新两市退市股票信息
在前面的股票列表设计中,我们有一个list_status字段,可能的值为L上市 D退市 P暂停上市。 由于股票可能会被退市,因此需要该字段来维护上市状态。 深市爬虫: # 读取深交所最新退市股票列表 def get_delisted_stock_list():cache_f…...
Redis复习总结
之前写的博客太杂,最近想把Redis的知识点再系统的过一遍,带着自己的理解使用简短的话把一些问题总结一下,尤其是开发中和面试中的高频问题,基础知识点参考–>Redis入门、Spring Cache,这篇不再赘述。 目录 基础简介;与Memcached的区别;为什么作为mysql缓存?如何保证R…...
基于JSP的医院挂号系统
你好,我是专注于医疗信息系统的计算机专业毕业生。如果您对医院挂号系统感兴趣或有相关需求,欢迎随时联系我。 开发语言:Java 数据库:MySQL 技术:JSP技术 工具:MyEclipse 系统展示 首页 管理员功能模…...
Chainlit快速实现AI对话应用1 分钟内实现聊天数据的持久化保存
概述 默认情况下,Chainlit 应用不会保留其生成的聊天和元素。即网页一刷新,所有的聊天记录,页面上的所有聊天记录都会消失。但是,存储和利用这些数据的能力可能是您的项目或组织的重要组成部分。 一旦启用,数据持久性…...
STM32DMA数据传输
我估计大多数人学这么久连听说都没听说过DMA,更不用提知道它是干嘛的。其实DMA的本质就是一个数据的搬运工。平常的时候当我们没有配置的时候,一直都是CPU在搬运数据,但是这个活又累又没有技术含量,所以DMA的重要性还是有的。 目…...
Python学习笔记50:游戏篇之外星人入侵(十一)
前言 本篇文章接着之前的内容,继续对游戏功能进行优化,主要是优化游戏状态以及对应的处理。 状态 一个游戏包含多种状态,这个状态是一个可以很复杂也可以很简单的内容。条件所限,我们这个游戏的状态就比较简单: 未…...
vue3踩坑问题记录
//vue3element-plus //1、placeholder换行显示 const startTxt ref() const contentText ref<any>() startTxt.value "请描述问题内容、例如:" historyData.prompt.forEach((el:any)>{contentText.value \n${el.question}}) <ElInputv-mo…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
打手机检测算法AI智能分析网关V4守护公共/工业/医疗等多场景安全应用
一、方案背景 在现代生产与生活场景中,如工厂高危作业区、医院手术室、公共场景等,人员违规打手机的行为潜藏着巨大风险。传统依靠人工巡查的监管方式,存在效率低、覆盖面不足、判断主观性强等问题,难以满足对人员打手机行为精…...
STM32---外部32.768K晶振(LSE)无法起振问题
晶振是否起振主要就检查两个1、晶振与MCU是否兼容;2、晶振的负载电容是否匹配 目录 一、判断晶振与MCU是否兼容 二、判断负载电容是否匹配 1. 晶振负载电容(CL)与匹配电容(CL1、CL2)的关系 2. 如何选择 CL1 和 CL…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
算法—栈系列
一:删除字符串中的所有相邻重复项 class Solution { public:string removeDuplicates(string s) {stack<char> st;for(int i 0; i < s.size(); i){char target s[i];if(!st.empty() && target st.top())st.pop();elsest.push(s[i]);}string ret…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...
Tauri2学习笔记
教程地址:https://www.bilibili.com/video/BV1Ca411N7mF?spm_id_from333.788.player.switch&vd_source707ec8983cc32e6e065d5496a7f79ee6 官方指引:https://tauri.app/zh-cn/start/ 目前Tauri2的教程视频不多,我按照Tauri1的教程来学习&…...
算法250609 高精度
加法 #include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; char input1[205]; char input2[205]; int main(){while(scanf("%s%s",input1,input2)!EOF){int a[205]…...
Unity VR/MR开发-开发环境准备
视频讲解链接: 【XR马斯维】UnityVR/MR开发环境准备【UnityVR/MR开发教程--入门】_哔哩哔哩_bilibili...
