iOS instruments trace文件解析方案

前言html

    已不多寫文章,不過此次感受有必要寫一下。由於:git

    1. 這個方案經過debug逆向得來,頗有參考意義。github

    2. iOS這方面資料很是少,作這塊時,不管國內外,翻遍了google,baidu都沒太多合適的資料。sql

    故此,我以爲把整個流程記錄下來,你能夠認爲這是一次iOS instruments的debug之旅。xcode

 

問題原由網絡

    最近作iOS性能測試,要監控一段時間內App的CPU佔用和網絡流量。遺憾的是,iOS instruments提供的Activity Monitor和Network模板並不知足個人需求。在UI工具中,Activity Monitor只提供了CPU瞬時值,Network也只提供了總流量,它們均不提供採集樣本值。數據結構

 

    因爲iOS閉源,放出的資料又少,故解決此問題的方案屈指可數:app

    (1). 設備越獄,經過後臺守護進程採集數據。工具

        - 缺陷:新設備沒法越獄。源碼分析

    (2). 在產品中嵌入性能數據採集模塊。

        - 缺陷:我不傾向在產品中嵌入測試模塊;另外,該方案對第三方產品也失效。

    (3). 從instruments結果文件(.trace)中嘗試獲取樣本值。

        - 缺陷:能不能作都不知道…

    因方案1,2有硬傷,故選方案3嘗試。

 

    其實,我開始時也並不肯定trace文件包含樣本數據,但instruments可經過trace文件恢復監控過程的柱狀圖,它給了我繼續這個方向的信心。

    3KYW

 

     而從trace文件獲取樣本值,有2個方向:

     (1)分析trace結構,獲取明文數據

          - trace實際上是文件夾,但裏面文件內容均爲二進制,遂放棄......

     (2)經過Undocumented API解析trace文件

          - 因爲instruments能夠解析trace文件,那麼(2)方法是必定可行的,問題是怎麼找到相關的Undocumented API。

 

Undocumented API可行性確認

     Lucky,我同事發現了這玩意:TraceUtility,它一個是獲取Time Profiler樣本值的工具(那做者也和我同樣遇到這種蛋疼問題......),而且Readme中找到重要線索:

     (1)所需的Undocumented API在/Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/Frameworks:

          DVTInstrumentsFoundation.framework

          InstrumentsPlugIn.framework

     (2)Instruments模板以PlugIns形式存在於

          /Applications/Xcode.app/Contents/Applications/Instruments.app/Contents/PlugIns

 

TraceUtility源碼分析

    項目就2個文件:

        InstrumentsPrivateHeader.h: Undocumented API和Undocumented數據結構聲明。

        main.m:樣本數據提取主流程。

2016-03-28_114938

 

深刻Debug分析

     然而TraceUtility僅用於獲取Time Profiler樣本數據,並不能知足我獲取CPU和網絡流量樣本的要求。

     我須要解決的問題是:

     (1)肯定instruments處理類。

     (2)從處理類中讀出樣本數據。

 

     1. 肯定instruments處理類

     方式很簡單,在loadDocument後,debug變量trace._baseInstruments

     E7I](3$)BP$K`K_XIIH6J77

     QQ圖片20160328115512

    對比圖一、2,XRSamplerInstrument=>XRSamplerRun,XRActivityInstrument=>XRActivityRun?,XRNetworkingInstrument=>XRNetworkingRun?;

    在另外一個github項目class-dump-o-tron, 搜到了相關信息:XRSamplerRun.h,然而在ActivityPlugin.xrplugin下卻沒找到XRActivityRun.h,而是XRActivityInstrumentRun.h(大Apple的命名能統一點嘛……);在XRNetworkingPlugIn.xrplugin下,找到了XRNetworkingRun.h

 

     2. 讀取trace樣本數據

    (1)CPU樣本結果

        debug變量run._data,發現了樣本數據

        N6ZL_F0OBPF9`4SHJH3G~)6

        TraceUtility使用了Undocumented API獲取數據,而我在XRActivityInstrumentRun.h沒找到相關API,直接經過反射獲取吧。

        C59E220C-72B7-4C37-BE9A-C694A3025E66

        至此,CPU樣本數據獲取完成。

 

    (2)網絡流量樣本結果

    Y3GL1%)C3@72RR]E]00`Z52

    XRNetworkRun和XRActivityInstrumentRun對象屬性不同,沒有_data,但_saveActivityQueries中有段sql,初步預估這玩意用了localdb,但db類型未明。另外,估計_saveInstrumentUUID應該db文件。

    而後cat 2A183EAD-5B9C-45DD-B2BA-D63DCD1165D4看下,由於文件可能會在頭部加註類型信息,cat結果以下:

    X{2N8}OH$%VCG$F)`FBS9{6

    捕獲SQLite文件一個……接下來的事情就是分析表結構了,沒什麼難度,不做詳述了。至此,網絡流量樣本數據獲取完成。

 

--------------------我是一條的分割線--------------------

 

補充部分-20160424

  關於以上代碼,個人實施是在xcode7.2上,但到了xcode7.3,出現些坑爹問題:

  在調用PFTLoadPlugins時候,出現crash,以下:

  意思是,在xcode7.3後,PFTLoadPlugins()調用了applicationDirectoryName,但在調用applicationDirectoryName前,必須先調用initializeApplicationDirectoryName。而PFTLoadPlugins沒有幫咱們作init,因此呢,crash了!!!

  解決方案:本身動手調用.....

  (1)加載DVTFramework。

    位置:/Applications/Xcode.app/Contents/SharedFrameworks

    緣由:initializeApplicationDirectoryName在該庫中...

  (2)在.h文件增長

    @interface DVTDeveloperPaths : NSObject
      + (void)initializeApplicationDirectoryName:(id)arg1;
    @end

  (3)在main.m中,PFTLoadPlugins()前增長:

    id test = @"../../../../../../../Applications/Xcode.app/";
    [DVTDeveloperPaths initializeApplicationDirectoryName:test];

  完成以上步驟後,PFTLoadPlugins()能夠正常執行!

相關文章
相關標籤/搜索