性能分析工具

功能简介

cjprof(Cangjie Profile)是仓颉语言的性能分析工具,支持以下功能:

  • 对仓颉语言程序进行 CPU 热点函数采样,导出采样数据。

  • 对热点函数采样数据进行分析,生成 CPU 热点函数统计报告或火焰图。

  • 导出仓颉语言应用程序堆内存,并对其进行分析生成分析报告。

目前 cjprof 仅支持 Linux 系统。

使用说明

通过 cjprof --help 即可查看命令使用方法。支持 recordreportheap 子命令,分别用于采集 CPU 热点函数信息, 生成 CPU 热点函数报告(包含火焰图)和导出与分析堆内存。

cjprof --help
 Usage: cjprof [--help] COMMAND [ARGS]

The supported commands are:
  heap      Dump heap into a dump file or analyze the heap dump file
  record    Run a command and record its profile data into data file
  report    Read profile data file (created by cjprof record) and display the profile

注意:

由于 cjprof record 依赖系统的 perf 权限,因此使用需要满足以下两个条件之一:

  • 使用 root 用户或 sudo 权限执行。
  • 系统的 perf_event_paranoid 参数(通过 /proc/sys/kernel/perf_event_paranoid 文件)配置为 -1 。

否则可能会出现权限不足的问题。

采集 CPU 热点函数信息

命令

cjprof record

格式

cjprof record [<options>] [<command>]
cjprof record [<options>] -- <command> [<options>]

选项

-f, --freq <freq> 指定采样频率,单位为赫兹(Hz),即每秒采样次数,默认为 1000 Hz,当指定为 max 或超过系统支持的最大频率时,取系统支持的最大频率。

-o, --output <file> 指定采样结束后生成的采样数据文件名,默认为 cjprof.data

-p, --pid <pid> 指定被采样应用程序的进程 ID,当指定 <command> 新启动应用程序进行采样时,该选项会被忽略。

示例

  • 采样正在运行的应用程序。
# 以 10000 Hz 的采样频率对正在运行的应用程序(进程号为 12345)进行采样,采样结束后将采样数据生成在当前路径下名为 sample.data 的文件中。
cjprof record -f 10000 -p 12345 -o sample.data
  • 新启动应用程序并对其进行采样。
# 执行当前路径下的 `test` 应用程序,参数为 `arg1 arg2` ,并以系统支持的最大采样频率对其进行采样,采样结束后将采样数据生成在当前路径下名为 `cjprof.data` (默认文件名)的文件中。
cjprof record -f max -- ./test arg1 arg2

注意事项

  • 开始采样后,只有被采样程序退出后才会结束采样,如果需要提前结束采样,可以在采样过程中通过按 Ctrl+C 主动停止采样。

生成 CPU 热点函数报告

命令

cjprof report

格式

cjprof report [<options>]

选项

-F, --flame-graph 生成 CPU 热点函数火焰图,而非默认的文本报告。

-i, --input <file> 采样数据文件名,默认为 cjprof.data

-o, --output <file> 生成的 CPU 热点函数火焰图文件名,默认为 FlameGraph.svg,仅当生成火焰图时才有效。

示例

  • 生成默认的 CPU 热点函数文本报告。
# 分析 sample.data 中的采样数据,生成 CPU 热点函数文本报告。
cjprof report -i sample.data
  • 生成 CPU 热点函数火焰图。
# 分析 cjprof.data(默认文件)中的采样数据,生成名为 test.svg 的 CPU 热点函数火焰图。
cjprof report -F -o test.svg

报告形式说明

  • 文本形式的报告包含函数采样总占比(包含子函数)、函数采样占比(自身)以及函数名(如果没有对应的符号信息则显示为地址)三部分,报告结果以函数采样总占比降序排列。

  • 火焰图中的横轴代表采样占比大小,越宽表示采样占比越大,即运行时间越长,纵轴表示调用栈,父函数在下,子函数在上。

导出和分析堆内存

命令

cjprof heap

格式

cjprof heap [<options>]

选项

-D, --depth <depth> 指定对象的引用/被引用关系最大展示深度,默认为 10 层,仅在指定了 --show-reference 时才能生效。

-d, --dump <pid> 导出仓颉应用程序当前时刻的堆内存,pid 为应用程序进程号,当指定为应用程序的子线程号时,同样可导出。

-i, --input <file> 指定进行分析的堆内存数据文件名,默认为 cjprof.data

-o, --output <file> 指定导出的堆内存数据文件名,默认为 cjprof.data

--show-reference[=<objnames>] 分析报告中展示对象的引用关系,objnames 为需要展示的对象名,多个对象使用 ; 隔开,不指定时默认展示所有对象。

--incoming-reference 展示对象的被引用关系,而非引用关系,需要与 --show-reference 配合使用。

-t, --show-thread 分析报告中展示仓颉线程栈,以及在栈中引用的对象。

-V, --verbose 维测选项,解析堆内存数据文件时打印解析日志。

示例

  • 导出堆内存数据。
# 将正在运行的应用程序(进程号为 12345)当前时刻的堆内存导出到当前路径下名为 heap.data 的文件中
cjprof heap -d 12345 -o heap.data

注意:

导出堆内存时会向进程发送 SIG_USR1 信号,在不确定目标进程是否为仓颉应用程序时,需要谨慎操作,否则可能会给目标进程误发送信号导致非预期错误。

  • 分析堆内存数据,展示对象信息。
# 解析并分析 ~ 目录下名为 heap.data 的堆内存数据文件,展示堆中各激活对象的对象类型名、实例个数、浅堆大小和深堆大小。
cjprof heap -i ~/heap.data

执行上述命令的效果如下:

Object Type           Objects        Shallow Heap   Retained Heap
====================  =============  =============  =============
AAA                               1            80             400
BBB                               4            32             196
CCC                               2            16              32
  • 分析堆内存数据,展示仓颉线程栈及对象引用。
# 解析并分析当前目录下名为 cjprof.data(默认文件)的堆内存数据文件,展示仓颉线程栈与栈中引用的对象。
cjprof heap --show-thread

执行上述命令的效果如下:

Object/Stack Frame                   Shallow Heap   Retained Heap
===================================  =============  =============
thread0
  at Func2() (/home/test/test.cj:10)
    <local> AAA @ 0x7f1234567800                80            400
  at Func1() (/home/test/test.cj:20)
    <local> CCC @ 0x7f12345678c0                16             16
  at main (/home/test/test.cj:30)
  • 分析堆内存数据,展示对象的引用关系。
# 解析并分析当前目录下名为 cjprof.data(默认文件)的堆内存数据文件,展示 AAA 和 BBB 类型对象的引用关系。
cjprof heap --show-reference="AAA;BBB"

执行上述命令的效果如下:

Objects with outgoing references:
Object Type                          Shallow Heap   Retained Heap
===================================  =============  =============
AAA @ 0x7f1234567800                            80            400
  BBB @ 0x7f1234567880                          32             48
    CCC @ 0x7f12345678c0                        16             16
  CCC @ 0x7f12345678e0                          16             16
BBB @ 0x7f1234567880                            32             48
  CCC @ 0x7f12345678c0                          16             16
  • 分析堆内存数据,展示对象的被引用关系。
# 解析并分析当前目录下名为 cjprof.data(默认文件)的堆内存数据文件,展示 CCC 类型对象的被引用关系。
cjprof heap --show-reference="CCC" --incoming-reference

执行上述命令的效果如下:

Objects with incoming references:
Object Type                          Shallow Heap   Retained Heap
===================================  =============  =============
CCC @ 0x7f12345678c0                            16             16
  BBB @ 0x7f1234567880                          32             48
    AAA @ 0x7f1234567800                        80            400
CCC @ 0x7f12345678e0                            16             16
  AAA @ 0x7f1234567800                          80            400

堆内存分析报告说明

  • 对象类型名使用 RawArray<Byte>[]RawArray<Half>[]RawArray<Word>[]RawArray<DWord>[] 分别表示 1 字节、2 字节、4 字节和 8 字节大小的基础数据类型原始数组。

  • 浅堆是指对象自身所占用的堆内存大小,深堆是指对象被垃圾回收后,可以被释放的所有对象(即仅能通过该对象直接或间接引用到的对象)的浅堆大小之和。

  • 当对象的引用关系层级超出最大展示深度后,或是存在循环引用出现重复对象后,会使用 ... 来省略后续引用。