Linuxasync-profiler

Posted 宣之于口

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linuxasync-profiler相关的知识,希望对你有一定的参考价值。

async-profiler

本文涉及的图片取自Profiling JVM Applications in Production

async-profiler是一个对系统性能影响很少的Java采样分析器,不会存在安全点偏差问题. 它具有特定于HotSpot的API,以收集堆栈跟踪并跟踪内存分配。探查器可与基于HotSpot JVM的OpenJDK,Oracle JDK和其他Java运行时一起使用。

async-profiler可以跟踪以下类型的事件:

  • CPU周期
  • 硬件和软件性能计数器,例如高速缓存未命中,分支未命中,页面错误,上下文切换等。
  • Java堆中的分配
  • 满足的锁定尝试,包括Java对象监视器和ReentrantLocks

一、基本概念

1. JVMTI Agents

某些探查器使用openJDK内部API调用AsyncGetCallTrace(ASGT)便于非安全点收集堆栈跟踪。AsyncGetCallTrace不是官方的JVM API。要使用ASGT,请先创建一个JVMTI Agents

JVMTI(JVM Tool Interface)是JVM提供的一套标准的C/C++编程接口,是实现Debugger、Profiler、Monitor、Thread Analyser等工具的统一基础,在主流Java虚拟机中都有实现。

当我们要基于JVMTI实现一个Agent时,需要实现如下入口函数:

// $JAVA_HOME/include/jvmti.h

JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);

使用C/C++实现该函数,并将代码编译为动态连接库(Linux上是.so),通过-agentpath参数将库的完整路径传递给Java进程,JVM就会在启动阶段的合适时机执行该函数。在函数内部,我们可以通过JavaVM指针参数拿到JNI和JVMTI的函数指针表,这样我们就拥有了与JVM进行各种复杂交互的能力。

更多JVMTI相关的细节可以参考官方文档

2. AsyncGetCallTrace

第一个没有安全点偏差问题的Java sampling profilers, 用于非安全点收集堆栈跟踪。生成单个线程的堆栈,而无需等待安全点。

二、分析

1. CPU profiling

在这种模式下,profiler 收集堆栈跟踪示例,其中包括Java方法、native调用、JVM代码和内核函数。

为了能够准确的生成Java和native代码的确切性能报告,常用的方法是接收perf_events生成的调用堆栈,并将它们与AsyncGetCallTrace生成的调用堆栈进行匹配。此外Async-profiler还提供了一种可以在AsyncGetCallTrace失败的某些情况下,恢复堆栈跟踪的解决方法

2. ALLOCATION profiling

async-profiler不使用侵入性技术,例如字节码检测工具或昂贵的DTrace探针,这些技术会对性能产生重大影响。它也不会影响转义分析或防止JIT优化, 如分配消除。仅测量实际堆分配.

探查器具有TLAB驱动的采样功能。它依赖于HotSpot特定的回调来接收两种通知:

  • 在新创建的TLAB中分配对象时(火焰图中的浅绿色帧)
  • 当在TLAB之外的慢路径上分配对象时(棕色框架)

这意味着不对每个分配进行计数,而仅对每N kB进行分配,其中N是TLAB的平均大小。这使得堆采样非常便宜并且适合于生产。另一方面,收集的数据可能不完整,尽管在实践中通常会反映出最主要的分配来源

采样间隔可以通过-i选件进行调整。例如,-i 500k平均分配500 KB的空间后,将采样一个样本。但是,小于TLAB大小的间隔不会生效。

三、与perf对比

1. perf

  • 仅支持Java 8u60及更高版本(以禁用FPO)
  • 禁用FPO对性能有较小的影响(在极端情况下最高可达10%)
  • 方法名解析需要映射(map)文件:perf-map-agent
  • 不支持interpreter frames
  • 堆栈深度通常限制为127 - 从Linux 4.8开始可以使用: /proc/sys/kernel/perf_event_max_stack
  • 支持系统范围内的分析

2. async-profiler

与直接将perf_events与Java代理一起使用相比较,该方式具有以下优点:

  • 它适用于较旧的Java版本,因为它不需要-XX:+PreserveFramePointer,这个参数只在JDK 8u60和更高版本中可用
  • 不需要引入-XX:+PreserveFramePointer,因为它可能导致较高的性能开销,在极少数情况下可能高达10%
  • 不需要生成映射文件来将Java代码地址映射到方法名
  • 可以与interpreter frames一起工作
  • 不需要为了后续的进一步分析而需要生成perf.data文件

四、使用教程

1. 安装

$ git clone https://github.com/jvm-profiling-tools/async-profiler
$ cd async-profiler
$ make

2. 参数

./profiler.sh [action] [options] <pid>

部分参数:

# Actions
start/stop		# 开始分析/结束分析
list			# 显示可用分析事件的列表。此选项仍然需要PID,因为受支持的事件可能因JVM版本而异

# Options
-d N 			# 分析持续时间
-e event		# cpu, alloc, lock, cache-misses etc
-f filename     # 将配置文件信息转储到的文件名 <filename>

3. 使用

a. 程序运行时动态载入

启动Java应用程序,然后使用代理开始分析,收集性能情况然后停止分析

$ jps
9234 Jps
8983 Computey
$ ./profiler.sh start 8983
$ ./profiler.sh stop 8983

或者可以通过 -d 指定分析时间

$ ./profiler.sh -d 30 8983

b. 作为代理启动

如果您需要在JVM启动后立即配置一些代码,而不是使用profiler.sh脚本,则可以在命令行上附加async-profiler作为代理。例如:

$ java -agentpath:/path/to/libasyncProfiler.so=start,file=profile.svg ...

4. 火焰图可视化

async-profiler提供了开箱即用的火焰图支持。指定-o svg参数以将分析结果转储为交互式SVG,可在所有主流浏览器中立即查看。另外,如果目标文件名以结尾,则会自动选择SVG输出格式.svg

$ jps
9234 Jps
8983 Computey
$ ./profiler.sh -d 30 -f /tmp/flamegraph.svg 8983

五、实验

本实验参照该实验手册:linux-tracing-workshop

Task 1: Profiling Java Code

首先,运行我们将要分析的Java应用程序。 它是同一主要计数应用程序的Java版本:

$ java slowy/App
Press ENTER to start.

暂时不要按ENTER, 在另一个shell中运行jps找到Slowy应用程序的进程ID

$ jps
6043 App
6076 Jps

然后运行收集工具之后,在Java应用程序的控制台中按ENTER,以便收集工具记录一些有意义的工作

# 进入 目录
./profiler.sh -d 15 6043

默认情况下,分析频率为100Hz(每10ms CPU时间)这是打印到Java应用程序终端的输出示例,显示Java程序中的瓶颈:slowy.App.isPrime,导致该方法的最热的调用堆栈来slowy.App.main

Started [cpu] profiling
--- Execution profile ---
Total samples       : 376

Frame buffer usage  : 0.0035%

--- 3729803417 ns (99.20%), 373 samples
  [ 0] slowy.App.isPrime
  [ 1] slowy.App.main

--- 10213575 ns (0.27%), 1 sample
  [ 0] finish_task_switch_[k]
[...]

          ns  percent  samples  top
  ----------  -------  -------  ---
  3729803417   99.20%      373  slowy.App.isPrime
    10213575    0.27%        1  finish_task_switch_[k]
    10013086    0.27%        1  Symbol::operator new(unsigned long, int, Arena*, Thread*)
     9997484    0.27%        1  slowy.App.main

Task 2: Flame Graph visualization

同样运行Java application, 并查看pid

$ jps
6841 Jps
6827 App

然后可以直接利用该命令,输出火焰图:

./profiler.sh -d 15 -f /tmp/flamegraph.svg 6827

ps: async-profiler 支持容器,perf 不支持,待验证

参考文档:

1. JVMTI 官方文档

2. Java应用性能分析工具:async-profiler

3. honest-profiler

4. async-profiler

5. Basics on profiling JVM in Linux

以上是关于Linuxasync-profiler的主要内容,如果未能解决你的问题,请参考以下文章

Linuxasync-profiler

偏差和方差

(集成电路)啥是时钟偏差?怎样尽量减小

2020-2021年顶会上关于解决偏差(bias)问题的文献整理

2020-2021年顶会上关于解决偏差(bias)问题的文献整理

poi获取点为啥与实际地图有偏差