async-profiler 基本原理

0. 是什么

This project is a low overhead sampling profiler for Java that does not suffer from Safepoint bias problem. It features HotSpot-specific APIs to collect stack traces and to track memory allocations. The profiler works with OpenJDK, Oracle JDK and other Java runtimes based on HotSpot JVM.

async-profiler can trace the following kinds of events:

  • CPU cycles
  • Hardware and Software performance counters like cache misses, branch misses, page faults, context switches etc.
  • Allocations in Java Heap
  • Contented lock attempts, including both Java object monitors and ReentrantLocks

一个没有 Safepoint bias 问题的 profiler,可以追踪 CPU 周期,也可以追踪 Java 堆中的分配、锁争用,以及软件和硬件的性能计数器。

1. 怎么用

async-profiler 是基于 JVMTI(JVM tool interface) 开发的 Agent,自然而然有两种使用方式:a.跟随 Java 进程启动,自动载入共享库;b.程序运行时通过 attach api 动态载入。

a. 启动时

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

b. 运行时

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

profiler.sh 脚本中封装了调用 attach api 的逻辑 —— jattach。

参数配置参考文档 README/Profiler Options

2. 实现

attach

通过本地 socket 与 JVM 进行交互的逻辑封装在 src/jattach/jattach.c,由于不是 profile 的重点逻辑,所以简单略过。

JVMTI

JVMTI 入口函数实现的逻辑在 src/vmEntry.cpp

通过 profiler.sh 脚本 attach 到 JVM 时就会调用 Agent_OnAttach 方法,如果是跟随 Java 进程启动那么会调用 Agent_OnLoad 方法。

首先进行一些初始化的逻辑,封装在 VM::init 方法中:

L36 获取 JVM 环境。每个 agent 都有自己的环境,在指定 agent 行为前,首先要获取环境信息,后面的操作都是针对这个环境。

L47 添加 capabilities。JVMTI 中有很多事件,每个事件都对应一些 Capabilities,如果你想为此事件编写回调函数,首先得开启相应的 Capabilities

Field Description Since
can_generate_all_class_hook_events Can generate ClassFileLoadHook events for every loaded class. 1.0
can_get_bytecodes Can get bytecodes of a method GetBytecodes 1.0
can_get_constant_pool Can get the constant pool of a class - GetConstantPool 1.0
can_get_source_file_name Can get the source file name of a class 1.0
can_get_line_numbers Can get the line number table of a method 1.0
can_generate_compiled_method_load_events Can generate events when a method is compiled or unloaded 1.0
can_generate_monitor_events Can generate events on monitor activity 1.0
can_tag_objects Can set and get tags, as described in the Heap category. 1.0

L61 注册回调函数。事件回调函数的接口是由JVMTI指定的。

Callback Description
VMInit The VM initialization event signals the completion of VM initialization. Once this event is generated, the agent is free to call any JNI or JVM TI function.
VMDeath The VM death event notifies the agent of the termination of the VM. No events will occur after the VMDeath event.
ClassLoad A class load event is generated when a class is first loaded.
ClassPrepare A class prepare event is generated when class preparation is complete.
CompiledMethodLoad Sent when a method is compiled and loaded into memory by the VM.
CompiledMethodUnload Sent when a compiled method is unloaded from memory.
DynamicCodeGenerated Sent when a component of the virtual machine is generated dynamically.
ThreadStart Thread start events are generated by a new thread before its initial method executes.
ThreadEnd Thread end events are generated by a terminating thread after its initial method has finished execution.
MonitorContendedEnter Sent when a thread is attempting to enter a Java programming language monitor already acquired by another thread.
MonitorContendedEntered Sent when a thread enters a Java programming language monitor after waiting for it to be released by another thread.

注:通过 attach 动态加载 agent 不会触发 VMInit 事件回调,因为此时 VM 已经初始化完毕;但是通过 -agentpath 跟随 Java 进程启动加载,在 Agent_OnLoad 入口方法执行后就会触发 VMInit 事件回调。

L63-L69 指定事件。当 JVM 发生一个事件,回调为此事件编写的函数,所以需要指定哪个事件发生时通知 agent。

注:ThreadStartThreadEndMonitorContendedEnterMonitorContendedEntered 事件的指定逻辑在 ProfilerLockTracer 启动和停止的方法中。

L71-L81 获取 AsyncGetCallTrace

如果是通过 attach 动态加载,那么加载所有的方法,并且生成 JVMTI_EVENT_DYNAMIC_CODE_GENERATED、JVMTI_EVENT_COMPILED_METHOD_LOAD 事件。

VM::init 初始化之后就是解析参数,最终调用 Profiler::run 方法执行 profile 的逻辑。

profiler

profiler 的逻辑位于 src/profiler.cpp

根据 action 执行对应的函数。

开始 profile 就会执行 start 方法:

L530 分配 frame_buffer,如果需要存储的 call traces 大于这个缓存将会溢出。

L545-L551 初始化 Hotspot 和 JVMTI 相关的资源。

L554 如果要输出 JFR 那么启动 _jfr,相关格式输出的逻辑封装在 FlightRecorderRecording 中。

L560 根据 event 选择 engine,如果是支持 perf_events 的 linux 系统,那么还提供了很多系统底层的事件。

Basic events:
  cpu
  alloc
  lock
  wall
  itimer
Perf events:
  page-faults
  context-switches
  cycles
  instructions
  cache-references
  cache-misses
  branches
  branch-misses
  bus-cycles
  L1-dcache-load-misses
  LLC-load-misses
  dTLB-load-misses
  mem:breakpoint
  trace:tracepoint

先看一下 EVENT_CPU 在 perf_events 的实现 PerfEvents

L462 接收操作系统信号 SIGPROF 执行 signalHandler

L471 每个线程打开相应的 perf_events 计数器,注册 SIGPROF 事件。

L425 回调 Profiler 采样调用栈信息

L402 通过 AsyncGetCallTrace 异步获取调用栈。

L418 将调用栈存储到 _frame_buffer

JDK-8178287 列举了一些无法获取调用栈的情况,这里做了一个补救方案,但是最终还得依赖 AsyncGetCallTrace 本身的修复更新。

其它类型 engine 的处理流程类似,具体的数据细节这里暂且略过。

回过头来在再看一下 ACTION_DUMP:

首先关闭各种资源,_jfr 会在关闭的时候输出。

然后是根据配置各种 dump:

  • dumpCollapsed 输出 FlameGraph 脚本所需的格式
  • dumpFlameGraph 输出火焰图 svg 或者调用树 html
  • dumpSummary 输出汇总信息
  • dumpTraces 输出调用栈列表
  • dumpFlat 输出 top N hot methods
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容