1# hiprofiler 2 3<!--Kit: Performance Analysis Kit--> 4<!--Subsystem: HiviewDFX--> 5<!--Owner: @zyxzyx--> 6<!--Designer: @Maplestroy--> 7<!--Tester: @gcw_KuLfPSbe--> 8<!--Adviser: @foryourself--> 9 10 11## Hiprofiler简介 12 13 14HiProfiler调优组件旨在为开发者提供一系列调优能力,可以用来帮助分析内存、性能等问题。 15 16 17整体架构包括PC端和设备端。主体部分是PC端的数据展示页面和设备端的性能调优服务。PC端和设备端服务采用C/S模型,PC端的调优数据在[DevEco Studio](https://cbg.huawei.com/#/group/ipd/DevEcoToolsList)和[Smartperf](https://gitee.com/openharmony/developtools_smartperf_host)网页中展示。设备端程序运行在系统环境中,包含多个部分,其中hiprofilerd进程负责与DevEco通信,作为调优服务。设备端还包括命令行工具hiprofiler_cmd和数据采集进程hiprofiler_plugins。调优服务控制数据采集进程获取调优数据,数据最终流向DevEco Studio,整个过程可抽象为生产者-消费者模型。目前已完成多个插件,包括nativehook、CPU、ftrace、GPU、hiperf、xpower和memory数据采集,实现了CPU、GPU、内存和能耗等多维度调优。 18 19 20 21Hiprofiler工具对标业界调优工具,并提供更多能力,比如[跨语言回栈、能耗数据获取、长时间堆内存抓栈功能](#插件参数说明)等。 22 23 24 25## 环境要求 26 27- 根据hdc命令行工具指导,完成[环境准备](hdc.md#环境准备)。 28 29- 确保设备已正常连接,并执行hdc shell。 30 31 32## 架构简介 33 341. PC端通过DevEco或Smartperf调用hiprofiler_cmd命令行工具; 35 362. hiprofiler_cmd进程启动hiprofilerd调优服务和hiprofiler_plugins插件进程; 37 383. hiprofiler_plugins开启对应插件,将获取到的调优数据汇总至hiprofilerd进程; 39 404. hiprofilerd进程将调优数据以proto格式存储到文件,或者实时返回给PC端; 41 425. PC端解析数据,生成泳道,展示获取到的调优数据。 43 44 45 46 47## 命令行说明 48 49使用hiprofiler_cmd命令行工具可以调用不同插件并输入不同参数,以满足不同的调优需求。示范命令如下: 50 51```shell 52$ hiprofiler_cmd \ 53 -c - \ 54 -o /data/local/tmp/hiprofiler_data.htrace \ 55 -t 30 \ 56 -s \ 57 -k \ 58<<CONFIG 59 request_id: 1 60 session_config { 61 buffers { 62 pages: 16384 63 } 64 } 65 plugin_configs { 66 plugin_name: "ftrace-plugin" 67 sample_interval: 1000 68 config_data { 69 hitrace_categories: "binder" 70 buffer_size_kb: 204800 71 flush_interval_ms: 1000 72 flush_threshold_kb: 4096 73 trace_period_ms: 200 74 } 75 } 76CONFIG 77``` 78 79 80| 命令 | 命令说明 | 81| -------- | -------- | 82| -c | 设置该选项后,需要将配置文件放入/data/local/tmp目录下,将路径作为参数输入。 | 83| -o | 自定义文件保存路径(需要以/data/local/tmp开头)。若不设置路径,则调优数据自动保存至/data/local/tmp/hiprofiler_data.htrace。重复调优会覆盖原来路径的文件。 | 84| -k | 杀掉已存在的调优服务进程。 | 85| -s | 拉起调优服务进程。 | 86| -t | 设置调优持续时间,单位:s。 | 87 88 89输入完hiprofiler_cmd参数后,需要输入插件配置信息,以<<CONFIG开头,CONFIG结尾,中间内容以json格式输入。 90 91 92以下是session config字段介绍: 93 94 95| 字段 | 字段说明 | 96| -------- | -------- | 97| buffers | 共享内存页的数量。 | 98| split_file | 是否拆分文件。true代表拆分文件;false代表不拆分文件。 | 99| split_file_max_size_mb | 设置split_file为true的情况下,定义每个拆分文件的最大大小。 | 100 101 102plugin_configs字段介绍: 103 104 105| 字段 | 字段说明 | 106| -------- | -------- | 107| plugin_name | 开启插件的名字。 | 108| sample_interval | 插件获取调优数据的间隔,单位:ms。 | 109| config_data | 插件具体参数。每个插件需要的参数不同,参考各插件proto定义。<br/>(代码路径:developtools/profiler/protos)。 | 110 111 112生成的trace文件通过hdc file recv命令导到本地,然后上传到smartperf网站或者DevEco Studio进行解析。 113 114 115## 支持插件列表 116 117| 插件名字 | 简介 | 规格说明 | 118| -------- | -------- | -------- | 119| native_hook | 获取堆内存分配的调用栈信息。 | 采集的进程仅支持[使用调试证书签名的应用](#使用调试证书签名的应用) | 120| ftrace-plugin | 获取内核打点的trace事件,以及hitrace打点的数据。 | - | 121| cpu-plugin | 获取进程CPU使用率信息,包括进程级和线程级的使用率。 | - | 122| gpu-plugin | 获取进程GPU使用率信息。 | - | 123| xpower-plugin | 获取进程能耗使用情况的数据。 | - | 124| memory-plugin | 获取进程内存占用情况,主要是获取进程smaps节点的数据。 | - | 125| diskio plugin | 获取进程磁盘空间占用情况。 | - | 126| network profiler | 通过进程内打点,获取进程HTTP请求的详细信息。 | 采集的进程仅支持[使用调试证书签名的应用](#使用调试证书签名的应用) | 127| network plugin | 获取进程网络流量统计信息。 | - | 128| hisysevent plugin | 通过hisysevent命令,获取hisysevent的事件记录数据。 | - | 129| hiperf plugin | 通过调用hiperf命令获取进程的指令计数信息以及对应的堆栈。 | - | 130| hidump plugin | 通过SP_daemon命令获取相关数据。 | - | 131 132 133## 使用调试证书签名的应用 134 135 136> **注意:** 137> 138> 确认命令指定的应用是否为可调试应用,可执行hdc shell "bm dump -n bundlename | grep appProvisionType"查询,预期返回信息为"appProvisionType": "debug"。 139 140以包名com.example.myapplication为例,可执行如下命令查询: 141 142```shell 143hdc shell "bm dump -n com.example.myapplication | grep appProvisionType" 144``` 145 146如果包名对应的应用是可调试应用,预期返回信息如下: 147 148```shell 149"appProvisionType": "debug", 150``` 151 152构建可调试应用需要使用调试证书进行签名,申请调试证书及签名可参考:[申请调试证书](https://developer.huawei.com/consumer/cn/doc/app/agc-help-add-debugcert-0000001914263178)。 153 154 155## 插件参数说明 156 157**native_hook 插件** 158 159获取堆内存分配的调用栈信息(通过malloc、mmap、calloc或realloc等基础库函数分配堆内存的调用栈),包括跨语言堆内存分配信息(如在ArkTS语言中调用napi分配native堆内存),还能展示内存泄漏未释放堆内存调用栈信息。 160 161nativehook参数列表: 162 163| 参数名字 | 类型 | 参数含义 | 详细介绍 | 164| -------- | -------- | -------- | -------- | 165| fp_unwind | bool | true表示使用fp回栈方式进行回栈;<br/>false表示使用dwarf回栈方式进行回栈。 | fp回栈是利用了x29寄存器保存的fp指针,函数的fp指针始终指向父函数(调用方)的fp指针,调优服务根据这一特点进行回栈,根据ip计算相对PC,然后查找maps对应区间来进行符号化。<br/>由于现在编译期越来越优化,出现寄存器重用或者编译禁用fp,会导致fp方式回不出相应的栈;混合栈情况下,fp不会记录多重混合,于是便需要dwarf回栈方式做更精确的回栈。<br/>dwarf回栈是根据pc寄存器在map表中查找对应的map信息,由于dwarf是逐级解析调用栈,所以其性能会比fp有劣化。<br/>注意:fp回栈暂不支持调优非aarch64架构的设备。 | 166| statistics_interval | int | 统计间隔,表示将一个统计周期内的栈进行汇总,单位:s。 | 为实现长时间轻量化采集,提供统计模式抓栈。如果更关注调优时的性能,只需要知道每个调用栈出现的次数和总大小,不需要知道每一次具体时间,可以使用统计模式。 | 167| startup_mode | bool | 是否抓取进程启动阶段内存。默认不抓取启动阶段内存。 | 记录进程从被appspawn拉起到调优结束这个期间内堆内存分配的信息。如果抓的是一个sa服务,需要在sa对应的cfg文件中找到拉起sa的进程名(如sa_main),将之加到此参数。 | 168| js_stack_report | int | 是否开启跨语言回栈。<br/>0:不抓取js栈。<br/>1:开启抓取js栈。 | 为方舟环境提供跨语言回栈功能。 | 169| malloc_free_matching_interval | int | 匹配间隔,单位:s,指在相应时间间隔内,将malloc和free进行匹配。匹配到的就不进行落盘。 | 在匹配间隔内,分配并释放了的调用栈不被记录,减少了抓栈服务进程的开销。此参数设置的值大于0时,就不能将statistics_interval参数设置为true。 | 170| offline_symbolization | bool | 是否开启离线符号化。<br/>true:使用离线符号化。<br/>false:使用在线符号化。 | 使用离线符号化时,根据IP匹配符号的操作在网页端(smartperf)完成,优化了native daemon的性能,减少了调优时的进程卡顿。但离线符号化会将符号表写入trace文件,导致文件大小比在线符号化时更大。 | 171| sample_interval | int | 采样大小。 | 设置此参数时开启采样模式。采样模式下对于malloc size小于采样大小进行概率性统计。调用栈分配内存大小越大,出现次数越高,被统计的几率越大。 | 172 173结果示例: 174 175开启fp回栈+跨语言回栈(其中绿色部分为js栈): 176 177 178 179开启dwarf回栈和跨语言回栈(可以展示出native -> js ->native的栈): 180 181 182 183开启统计模式,在此模式下,栈数据会周期性展示: 184 185 186 187开启非统计模式,在此模式下,栈数据不会周期性展示: 188 189 190 191**ftrace_plugin**: 192 1931. 参数介绍 194 195 | 参数名字 | 类型 | 参数含义 | 详细介绍 | 196 | -------- | -------- | -------- | -------- | 197 | ftrace_events | string | 抓取的trace event。 | 记录内核打点的trace event。 | 198 | hitrace_categories | string | 抓取的hitrace打点信息。 | 调用hitrace能力,获取数据以proto格式写入文件。 | 199 | hitrace_apps | string | 抓取的hitrace信息的进程。 | 设置此参数时,只有对应进程的trace信息会被记录。添加此参数时, hitrace_categories不支持添加binder,否则会导致trace数据解析异常。| 200 | buffer_size_kb | int | buffer缓存大小,单位:kB。 | hiprofiler_plugins进程读取内核事件所需要的缓存大小。推荐使用默认数值:204800。 | 201 | flush_interval_ms | int | 采集数据频率,单位:ms。 | 推荐使用默认数值:1000。 | 202 | flush_threshold_kb | int | 刷新数据大小。 | 超过threshold刷新一次数据至文件。用smartperf默认数值即可。 | 203 | parse_ksyms | bool | 是否获取内核数据。 | true:获取内核数据;false:不获取内核数据。 | 204 | trace_period_ms | int | 读取内核数据的频率。 | 用smartperf默认数值即可。 | 205 2062. 结果分析 207 208 示例命令: 209 210 ```shell 211 $ hiprofiler_cmd \ 212 -c - \ 213 -o /data/local/tmp/hiprofiler_data.htrace \ 214 -t 10 \ 215 -s \ 216 -k \ 217 <<CONFIG 218 request_id: 1 219 session_config { 220 buffers { 221 pages: 16384 222 } 223 } 224 plugin_configs { 225 plugin_name: "ftrace-plugin" 226 sample_interval: 1000 227 config_data { 228 ftrace_events: "binder/binder_transaction" 229 ftrace_events: "binder/binder_transaction_received" 230 buffer_size_kb: 204800 231 flush_interval_ms: 1000 232 flush_threshold_kb: 4096 233 parse_ksyms: true 234 clock: "boot" 235 trace_period_ms: 200 236 debug_on: false 237 } 238 } 239 CONFIG 240 ``` 241 242 此命令读取的内核binder_transaction和binder_transaction_received数据,这两个字段同时使用,才能完整展示binder两端数据。执行命令后,通过hdc file recv将文件导出,然后拖至smartperf解析。结果示例如下图: 243 244 点击binder transaction右边的箭头,可以跳转到binder对端的进程或线程。 245 246  247 248**memory_plugin**: 249 2501. 参数介绍 251 252 | 参数名字 | 类型 | 参数含义 | 详细介绍 | 253 | -------- | -------- | -------- | -------- | 254 | report_sysmem_vmem_info | bool | 是否读取虚拟内存数据。 | 从/proc/vmstat节点读取内存数据。 | 255 | report_process_mem_info | bool | 是否获取进程详细内存数据,如rss_shmem,rss_file,vm_swap等。 | 从/proc/${pid}/stat节点读取内存数据。 | 256 | report_smaps_mem_info | bool | 是否获取进程smaps内存信息。 | 从/proc/${pid}/smaps节点获取进程smaps内存数据。 | 257 | report_gpu_mem_info | bool | 是否获取进程GPU使用情况。 | 读取/proc/gpu_memory节点数据。 | 258 | parse_smaps_rollup | bool | 是否从smaps_rollup节点读取smaps统计数据 | 读取/proc/{pid}/smaps_rollup节点的smaps统计数据,相比使用report_smaps_mem_info参数调优服务性能会更好(如CPU,内存使用优化)。 | 259 2602. 结果分析 261 262  263 264 通过DevEco->profiler->Allocation工具,选择Memory泳道,可以使用profiler的memory plugin功能。上图展示了框选时间段的进程smaps内存信息。 265 266**xpower_plugin**: 267 2681. 参数介绍 269 270 | 参数名字 | 类型 | 参数含义 | 详细介绍 | 271 | -------- | -------- | -------- | -------- | 272 | bundle_name | string | 需要进行能耗调优的进程名。 | 和/proc/节点下的进程名一致。 | 273 | message_type | XpowerMessageType | 需要获取能耗数据的类型。 | 数据类型包括:REAL_BATTERY、APP_STATISTIC、APP_DETAIL、COMPONENT_TOP、ABNORMAL_EVENTS和THERMAL_REPORT。 | 274 2752. 结果分析 276 277  278 279 通过DevEco->profiler->real time monitor工具,可以获取相关进程能耗数据。 280 281**gpu_plugin**: 282 283获取GPU使用率相关信息的数据。 284 285参数介绍 286 287| 参数名字 | 类型 | 参数含义 | 详细介绍 | 288| -------- | -------- | -------- | -------- | 289| pid | int | 需要进行调优的进程ID,与/proc/节点下的进程ID一致。 | 290| report_gpu_info | bool | 是否展示指定进程的GPU使用率信息 | true: 展示指定进程的GPU数据,需要设置pid。数据从/sys/class/devfreq/gpufreq/gpu_scene_aware/utilisation节点读取。<br/>false: 不展示指定进程的GPU数据。 | 291 292**cpu_plugin**: 293 294获取CPU使用率的相关信息。 295 296参数介绍 297 298| 参数名字 | 类型 | 参数含义 | 详细介绍 | 299| -------- | -------- | -------- | -------- | 300| pid | int | 需要进行调优的进程ID。 | 和/proc/节点下的进程ID一致。 | 301| report_process_info | bool | 是否展示指定进程的CPU使用率信息 | true:展示指定进程的数据,需要设置pid参数;<br/>false:不展示指定进程的数据,仅展示系统级CPU使用率数据。 | 302| skip_thread_cpu_info | bool | 是否跳过线程CPU使用率数据 | true:不展示每个线程CPU使用率的信息,开启此参数时可以降低调优服务的开销;<br/>false:展示每个线程CPU使用率的信息。 | 303 304 305## 常用命令 306 307 308### 堆内存分配调用栈数据采样记录 309 310 311对com.example.insight_test_stage进程的堆内存分配操作进行抓栈,并开启fp回栈、离线符号化和统计模式。 312 313 314```shell 315$ hiprofiler_cmd \ 316 -c - \ 317 -t 30 \ 318 -s \ 319 -k \ 320<<CONFIG 321 request_id: 1 322 session_config { 323 buffers { 324 pages: 16384 325 } 326 } 327 plugin_configs { 328 plugin_name: "nativehook" 329 sample_interval: 5000 330 config_data { 331 save_file: false 332 smb_pages: 16384 333 max_stack_depth: 20 334 process_name: "com.example.insight_test_stage" 335 string_compressed: true 336 fp_unwind: true 337 blocked: true 338 callframe_compress: true 339 record_accurately: true 340 offline_symbolization: true 341 startup_mode: false 342 statistics_interval: 10 343 sample_interval: 256 344 js_stack_report: 1 345 max_js_stack_depth: 10 346 } 347 } 348CONFIG 349``` 350 351 352采集的数据会被保存至/data/local/tmp/hiprofiler_data.htrace文件中,该文件包含了内存泄漏分析所需的函数调用信息、线程和动态库维度内存分配情况,以及调用栈次数和分配大小聚类信息。开启离线符号化,fp回栈,统计模式均可以提升调优服务处理数据速率。 353 354 355 356抓取指定进程CPU使用率。 357 358 359对进程号为1234的进程采集CPU数据,采集时长为30s,采样周期为1000ms,调优数据传输的共享内存大小是16384个内存页,采集的数据会被保存至/data/local/tmp/hiprofiler_data.htrace文件中。 360 361 362```shell 363$ hiprofiler_cmd \ 364 -c - \ 365 -o /data/local/tmp/hiprofiler_data.htrace \ 366 -t 30 \ 367 -s \ 368 -k \ 369<<CONFIG 370 request_id: 1 371 session_config { 372 buffers { 373 pages: 16384 374 } 375 } 376 plugin_configs { 377 plugin_name: "cpu-plugin" 378 sample_interval: 1000 379 config_data { 380 pid: 1234 381 report_process_info: true 382 } 383 } 384CONFIG 385``` 386 387 388 389## 常见问题 390 391调优出现异常。 392 393**现象描述** 394 395使用hiprofiler_cmd命令时,显示Service not started。 396 397 398 399**可能原因&解决方法** 400 401调优服务未能开启,说明正在使用DevEco Studio调优或者上次调优异常退出,需要执行hiprofiler_cmd -k之后再重新执行调优命令。 402 403抓取到的trace文件为空。 404 405**现象描述** 406 407抓取到的trace文件是空的。 408 409**可能原因&解决方法** 410 411需要检查生成文件的路径是否在/data/local/tmp/目录下。如果目标路径是/data/local/tmp下的一个文件夹,则尝试对文件夹执行chmod 777操作。如果是user版本使用nativehook或者network profiler抓取no debug应用,也抓不到数据(参考changelog https://gitcode.com/openharmony/docs/pulls/57419)。 412 413调优数据疑似不准确。 414 415**现象描述** 416 417hiprofiler抓取到的native heap和hidumper查看的native heap有差异。 418 419**可能原因&解决方法** 420 421hidumper抓取的是进程维度内存使用情况,hiprofiler抓取到的是进程用户态通过基础库函数(malloc,mmap,realloc等,operator new也是调用的malloc)分配堆内存的数据。两者之间会有差异,差异存在于线程的内存缓存,堆内存延迟释放,加载器使用内存等。 422