OpenHarmony子系統開發 - DFX(三)
五、HiTraceMeter開發指導
HiTraceMeter概述
簡介
HiTraceMeter在OpenHarmony中,為開發者提供業務流程調用鏈跟蹤的維測接口。通過使用該接口所提供的功能,可以幫助開發者迅速獲取指定業務流程調用鏈的運行日志、定位跨設備/跨進程/跨線程的故障問題。HiTraceMeter用來支持用戶態的打點,采集用戶態和內核態的trace數據,從而進行性能跟蹤與分析的系統。
基本概念
HiTraceMeter系統主要分為三部分:
- JS/C++應用打點API;
- Trace數據采集命令行工具;
- Trace數據圖形分析工具。
其中,前兩者運行在設備端側,圖形工具運行在PC主機側。打點API部分提供了C++和JS接口,供開發過程中打點使用,打點用于產生Trace數據流,是抓Trace數據的基礎條件。
命令行工具用于采集Trace數據,用來抓取Trace數據流并保存到文本文件。
Trace數據分析可以在圖形工具中人工分析,也可以使用分析腳本自動化分析,Trace分析工具以Trace命令行工具的采集結果數據文件為輸入。
HiTraceMeter跟蹤數據使用類別分類,類別分類稱作Trace Tag或Trace Category,一般一個端側軟件子系統對應一個Tag。該Tag在打點API中以類別Tag參數傳入。Trace命令行工具采集跟蹤數據時,只采集Tag類別選項指定的跟蹤數據。應用程序跟蹤數據標簽都是屬于APP Tag,從而JS接口不需要輸入tag參數。目前HiTraceMeter支持的Trace Tag表如下(可在hitrace_meter.h?hitrace_meter.h?中查看):
constexpr uint64_t HITRACE_TAG_NEVER = 0; // This tag is never enabled.
constexpr uint64_t HITRACE_TAG_ALWAYS = (1ULL << 0); // This tag is always enabled.
constexpr uint64_t HITRACE_TAG_DLP_CREDENTIAL = (1ULL << 21); // This tag is dlp credential service.
constexpr uint64_t HITRACE_TAG_ACCESS_CONTROL = (1ULL << 22); // This tag is access control tag.
constexpr uint64_t HITRACE_TAG_NET = (1ULL << 23); // Net tag.
constexpr uint64_t HITRACE_TAG_NWEB = (1ULL << 24); // NWeb tag.
constexpr uint64_t HITRACE_TAG_HUKS = (1ULL << 25); // This tag is huks.
constexpr uint64_t HITRACE_TAG_USERIAM = (1ULL << 26); // This tag is useriam.
constexpr uint64_t HITRACE_TAG_DISTRIBUTED_AUDIO = (1ULL << 27); // Distributed audio tag.
constexpr uint64_t HITRACE_TAG_DLSM = (1ULL << 28); // device security level tag.
constexpr uint64_t HITRACE_TAG_FILEMANAGEMENT = (1ULL << 29); // filemanagement tag.
constexpr uint64_t HITRACE_TAG_OHOS = (1ULL << 30); // OHOS generic tag.
constexpr uint64_t HITRACE_TAG_ABILITY_MANAGER = (1ULL << 31); // Ability Manager tag.
constexpr uint64_t HITRACE_TAG_ZCAMERA = (1ULL << 32); // Camera module tag.
constexpr uint64_t HITRACE_TAG_ZMEDIA = (1ULL << 33); // Media module tag.
constexpr uint64_t HITRACE_TAG_ZIMAGE = (1ULL << 34); // Image module tag.
constexpr uint64_t HITRACE_TAG_ZAUDIO = (1ULL << 35); // Audio module tag.
constexpr uint64_t HITRACE_TAG_DISTRIBUTEDDATA = (1ULL << 36); // Distributeddata manager module tag.
constexpr uint64_t HITRACE_TAG_MDFS = (1ULL << 37); // Mobile distributed file system tag.
constexpr uint64_t HITRACE_TAG_GRAPHIC_AGP = (1ULL << 38); // Graphic module tag.
constexpr uint64_t HITRACE_TAG_ACE = (1ULL << 39); // ACE development framework tag.
constexpr uint64_t HITRACE_TAG_NOTIFICATION = (1ULL << 40); // Notification module tag.
constexpr uint64_t HITRACE_TAG_MISC = (1ULL << 41); // Notification module tag.
constexpr uint64_t HITRACE_TAG_MULTIMODALINPUT = (1ULL << 42); // Multi modal module tag.
constexpr uint64_t HITRACE_TAG_SENSORS = (1ULL << 43); // Sensors mudule tag.
constexpr uint64_t HITRACE_TAG_MSDP = (1ULL << 44); // Multimodal Sensor Data Platform module tag.
constexpr uint64_t HITRACE_TAG_DSOFTBUS = (1ULL << 45); // Distributed Softbus tag.
constexpr uint64_t HITRACE_TAG_RPC = (1ULL << 46); // RPC and IPC tag.
constexpr uint64_t HITRACE_TAG_ARK = (1ULL << 47); // ARK tag.
constexpr uint64_t HITRACE_TAG_WINDOW_MANAGER = (1ULL << 48); // window manager tag.
constexpr uint64_t HITRACE_TAG_ACCOUNT_MANAGER = (1ULL << 49); // account manager tag.
constexpr uint64_t HITRACE_TAG_DISTRIBUTED_SCREEN = (1ULL << 50); // Distributed screen tag.
constexpr uint64_t HITRACE_TAG_DISTRIBUTED_CAMERA = (1ULL << 51); // Distributed camera tag.
constexpr uint64_t HITRACE_TAG_DISTRIBUTED_HARDWARE_FWK = (1ULL << 52); // Distributed hardware fwk tag.
constexpr uint64_t HITRACE_TAG_GLOBAL_RESMGR = (1ULL << 53); // Global resource manager tag.
constexpr uint64_t HITRACE_TAG_DEVICE_MANAGER = (1ULL << 54); // Distributed hardware devicemanager tag.
constexpr uint64_t HITRACE_TAG_SAMGR = (1ULL << 55); // SA tag.
constexpr uint64_t HITRACE_TAG_POWER = (1ULL << 56); // power manager tag.
constexpr uint64_t HITRACE_TAG_DISTRIBUTED_SCHEDULE = (1ULL << 57); // Distributed schedule tag.
constexpr uint64_t HITRACE_TAG_DEVICE_PROFILE = (1ULL << 58); // device profile tag.
constexpr uint64_t HITRACE_TAG_DISTRIBUTED_INPUT = (1ULL << 59); // Distributed input tag.
constexpr uint64_t HITRACE_TAG_BLUETOOTH = (1ULL << 60); // bluetooth tag.
constexpr uint64_t HITRACE_TAG_ACCESSIBILITY_MANAGER = (1ULL << 61); // accessibility manager tag.
constexpr uint64_t HITRACE_TAG_APP = (1ULL << 62); // App tag.constexpr uint64_t HITRACE_TAG_LAST = HITRACE_TAG_APP;
constexpr uint64_t HITRACE_TAG_NOT_READY = (1ULL << 63); // Reserved for initialization.
constexpr uint64_t HITRACE_TAG_VALID_MASK = ((HITRACE_TAG_LAST - 1) | HITRACE_TAG_LAST);
實現原理
HiTraceMeter主要提供抓取用戶態和內核態Trace數據的命令行工具,提供用戶態打點的innerkits接口(c++)和kits接口(js),HiTraceMeter基于內核ftrace提供的用戶態打點的擴展,利用ftrace的trace_marker節點,將用戶空間通過打點接口寫入的數據寫進內核循環buffer緩沖區。其基本架構圖如下:
約束與限制
- HiTraceMeter所有功能與接口的實現都依賴于內核提供的ftrace功能,ftrace 是內核提供的一個 framework,采用 plugin 的方式支持開發人員添加更多種類的 trace 功能,因此使用HiTraceMeter之前要使能 ftrace,否則HiTraceMeter的功能無法使用(目前大部分Linux內核默認使能了ftrace,關于ftrace的詳細介紹可查看內核ftrace相關資料?ftrace相關資料?)。
- HiTraceMeter僅限小型系統、標準系統下使用。
HiTraceMeter開發指導
HiTraceMeter分為JS/C++應用打點API與數據采集命令行工具hitrace,下面分別介紹接口和命令行工具。
場景介紹
在實際開發過程中,開發者可能會遇到app卡頓或者在代碼調試過程中需要查看代碼調用流程,HiTraceMeter接口提供了相應的接口來跟蹤程序延時和代碼調用流程,分析性能問題。
接口說明
C++接口僅系統開發者使用,JS(目前暫未開放js接口)應用開發者可以略過本節。標準系統上接口描述如下(hitrace_meter.h?hitrace_meter.h?):
表 1?同步接口
Sync trace | 功能描述 | 參數說明 |
---|---|---|
void StartTrace(uint64_t label, const std::string& value, float limit = -1); | 啟動同步trace | label: Trace category。 value: Trace攜帶的信息,表明當前的某種狀態,例如內存大小,隊列長短等。 |
void FinishTrace(uint64_t label); | 關閉同步trace | label: Trace category。 |
同步接口StartTrace和FinishTrace必須配對使用,FinishTrace和前面最近的StartTrace進行匹配。StartTrace和FinishTrace函數對可以嵌套模式使用,跟蹤數據解析時使用棧式數據結構進行匹配。接口中的limit參數用于限流,使用默認值即可。
表 2?異步接口
Async trace | 功能描述 | 參數說明 |
---|---|---|
void StartAsyncTrace(uint64_t label, const std::string& value, int32_t taskId, float limit = -1); | 開啟異步trace | label: Trace category。 value: Trace攜帶的信息,表明當前的某種狀態,例如內存大小,隊列長短等。 taskId:異步Trace中用來表示關聯的ID。 |
void FinishAsyncTrace(uint64_t label, const std::string& value, int32_t taskId); | 關閉異步trace | label: Trace category。 value: Trace攜帶的信息,表明當前的某種狀態,例如內存大小,隊列長短等。 taskId:異步Trace中用來表示關聯的ID。 |
異步接口StartAsyncTrace和FinishAsyncTrace的跟蹤數據匹配時,使用參數中的value和taskId配對匹配,可以不按順序使用,主要用于異步場景。在C++程序中,使用異步跟蹤的場景很少。
表 3?計數器接口
Counter Trace | 功能描述 | 參數說明 |
---|---|---|
void CountTrace(uint64_t label, const std::string& name, int64_t); | 計數trace | label: Trace category。 name: Trace的名稱,IDE中會以此字段展示這段Trace。 |
開發步驟
-
編譯依賴添加,需要修改的編譯配置文件base\hiviewdfx\hitrace\cmd\BUILD.gn 。
external_deps = [ "hitrace:hitrace_meter"]
-
頭文件依賴添加。
#include "hitrace_meter.h"//接口函數定義頭文件
-
接口調用,將需要跟蹤的Trace value傳入參數,目前HiTraceMeter支持的Trace Tag在基本概念hitrace_meter.h中都已列出,我們以OHOS這個Tag為例,假設我們需要獲取func1,func2函數的Trace數據,參考下面實例,在shell中執行hitrace命令后會自動抓取Trace數據,抓到的Trace數據中包括了函數調用過程以及調用過程消耗的內存和時間,可用于分析代碼調用流程,代碼性能問題。
#include "hitrace_meter.h" // 包含hitrace_meter.h using namespace std;int main() {uint64_t label = BYTRACE_TAG_OHOS;sleep(1);CountTrace(label, "count number", 2000); // 整數跟蹤StartTrace(label, "func1Trace", -1); // func1Start的跟蹤起始點sleep(1);StartTrace(label, "func2Trace", -1); // func2Start的跟蹤起始點sleep(2);FinishTrace(label); // func2Trace的結束點sleep(1);FinishTrace(label); // func1Trace的結束點StartAsyncTrace(label, "asyncTrace1", 1234); // 異步asyncTrace1的開始點 FinishAsyncTrace(label, "asyncTrace1", 1234); // 異步asyncTrace1的結束點return 0; }
-
使用方法,打點編譯部署完成后,運行下面命令行來抓取Trace。然后在端側shell里運行應用,可以抓取到Trace數據。
hdc_std shell hitrace -t 10 ohos > .\myapp_demo.ftrace
抓取之后的數據可以在smartperf中"Open trace file"或者直接拖入圖形區打開,關于smartperf的詳細介紹可查看?smartperf?。
調測驗證
以下為一個demo調試過程,該demo使用了同步接口中的StartTrace和FinishTrace。
-
編寫測試代碼hitrace_example.cpp(?hitrace_example.cpp?),將使用到的接口加入代碼:
int main() {thread t1(ThreadFunc1);t1.join();StartTrace(LABEL, "testStart");sleep(SLEEP_ONE_SECOND);StartTrace(LABEL, "funcAStart", SLEEP_ONE_SECOND); // 打印起始點FuncA();FinishTrace(LABEL);sleep(SLEEP_TWO_SECOND);thread t2(ThreadFunc2);t2.join();StartTrace(LABEL, "funcBStart", SLEEP_TWO_SECOND);FuncB();FinishTrace(LABEL);// 打印結束點sleep(SLEEP_TWO_SECOND);sleep(SLEEP_ONE_SECOND);FinishTrace(LABEL);FuncC();return 0; }
-
修改gn編譯文件并編譯,編譯配置文件路徑base\hiviewdfx\hitrace\cmd\BUILD.gn 。
ohos_executable("hitrace_example") {sources = [ "example/hitrace_example.cpp" ]external_deps = [ "hitrace:hitrace_meter" ]subsystem_name = "hiviewdfx"part_name = "hitrace_native" }group("hitrace_target") {deps = [":hitrace",":hitrace_example",] }
-
將編譯出來的hitrace_example可執行文件放到設備中的/system/bin目錄下,在shell中執行依次執行如下命令:
hitrace --trace_begin ohos hitrace_exampe hitrace --trace_dump
當我們看到Trace數據中有我們需要的Trace value時,說明成功抓取Trace,成功的數據如下所示:
<...>-1651 (-------) [002] .... 327.194136: tracing_mark_write: S|1650|H:testAsync 111 <...>-1650 (-------) [001] .... 332.197640: tracing_mark_write: B|1650|H:testStart <...>-1650 (-------) [001] .... 333.198018: tracing_mark_write: B|1650|H:funcAStart <...>-1650 (-------) [001] .... 334.198507: tracing_mark_write: E|1650| <...>-1654 (-------) [003] .... 341.201673: tracing_mark_write: F|1650|H:testAsync 111 <...>-1650 (-------) [001] .... 341.202168: tracing_mark_write: B|1650|H:funcBStart <...>-1650 (-------) [001] .... 343.202557: tracing_mark_write: E|1650| <...>-1650 (-------) [001] .... 346.203178: tracing_mark_write: E|1650| <...>-1650 (-------) [001] .... 346.203457: tracing_mark_write: C|1650|H:count number 1 <...>-1650 (-------) [001] .... 347.203818: tracing_mark_write: C|1650|H:count number 2 <...>-1650 (-------) [001] .... 348.204207: tracing_mark_write: C|1650|H:count number 3 <...>-1650 (-------) [001] .... 349.204473: tracing_mark_write: C|1650|H:count number 4 <...>-1650 (-------) [001] .... 350.204851: tracing_mark_write: C|1650|H:count number 5 <...>-1655 (-------) [001] .... 365.944658: tracing_mark_write: trace_event_clock_sync: realtime_ts=1502021460925 <...>-1655 (-------) [001] .... 365.944686: tracing_mark_write: trace_event_clock_sync: parent_ts=365.944641
HiTraceMeter命令行工具使用指導
HiTraceMeter提供了可執行的二進制程序hitrace,設備刷openharmony后直接在shell中運行以下命令,抓取內核運行的數據,當前支持的操作如下:
表 4?命令行列表
Option | Description |
---|---|
-h,--help | 查看option幫助 |
-b n,--buffer_size n | 指定n(KB)內存大小用于存取trace日志,默認2048KB |
-t n,--time n | 用來指定trace運行的時間(單位:s),取決于需要分析過程的時間 |
--trace_clock clock | trace輸出的時鐘類型,一般設備支持boot、global、mono、uptime、perf等,默認為boot |
--trace_begin | 啟動抓trace |
--trace_dump | 將數據輸出到指定位置(默認控制臺) |
--trace_finish | 停止抓trace,并將數據輸出到指定位置(默認控制臺) |
--trace_finish_nodump | 停止抓trace,不輸出trace信息 |
-l,--list_categories | 輸出手機能支持的trace模塊 |
--overwrite | 當緩沖區滿的時候,將丟棄最新的信息(默認丟棄最老的日志) |
-o filename,--output filename | 指定輸出的目標文件名稱 |
-z | 抓取trace后進行壓縮 |
以下是常用hitrace命令示例,供開發者參考:
-
查詢支持的label。
hitrace -l
或者
hitrace --list_categories
-
設置4M緩存,抓取10秒,抓取label為ability的trace信息。
hitrace -b 4096 -t 10 --overwrite ability > /data/log/mytrace.ftrace
-
設置trace的輸出時鐘為mono。
hitrace --trace_clock mono -b 4096 -t 10 --overwrite ability > /data/log/mytrace.ftrace
-
抓取trace后進行壓縮。
hitrace -z -b 4096 -t 10 --overwrite ability > /data/log/mytrace.ftrace
常見問題
hitrace抓數據不全或者沒抓到數據
現象描述
執行hitrace命令抓數據不全或者沒抓到數據。
根因分析
參數-t 時間設置過小或者-b緩沖區buffer設置過小導致數據丟失。
解決方法
可設置-t 60,-b 204800擴大抓trace時間和緩沖區buffer解決。
參考
更多關于HiTraceMeter的詳細內容請參考:輕量級的分布式調用鏈跟蹤?。