Android上oprofile使用說明

來源:互聯網
上載者:User

 

Android上oprofile使用說明

1.     目的
本文介紹了oprofile的功能並基於Android 2.1介紹了使用oprofile的基本方法和步驟。本文的讀者為軟體開發人員和白盒測試人員。

2.     oprofile簡介
Oprofile是用於Linux的若干種評測和效能監控工具中的一種,它可以工作在不同的體繫結構上,包括IA32、IA64、AMD Athlon系列及ARM等。Oprofile包含在Linux 2.5和更高版本的核心中,也包含在大多數較新的Linux發行版本中,在Android中已經整合了Oprofile。

oprofile以很低的開銷對系統中所有啟動並執行代碼(包括kernel、kernel模組、庫、應用程式)進行函數層級的效能分析(function-level profiling),跟蹤佔用CPU高的函數的調用資訊,從而判斷程式中哪些地方存在需要最佳化的效能瓶頸。

oprofile支援兩種採樣(sampling)方式:基於事件的採樣(event based)和基於時間的採樣(time based)。

基於事件的採樣是oprofile只記錄特定事件(比如L2 cache miss)的發生次數,當達到使用者設定的定值時oprofile就記錄一下(采一個樣)。這種方式需要CPU內部有效能計數器(performance counter)。

基於時間的採樣是oprofile藉助OS時鐘中斷的機制,每個時鐘中斷oprofile都會記錄一次(采一次樣),又分為RTC模式(RTC mode,適用於2.2/2.4核心)和定時器中斷模式(timer interrupt mode,適用於2.6以上核心)。引入定時器取樣模式的目的在於,提供對沒有效能計數器的CPU的支援,其精度相對於基於事件的採樣要低,並且因為要藉助OS時鐘中斷的支援,對禁用中斷的代碼oprofile不能對其進行分析。

高通QSD8K處理器具備效能計數器,但當前發布的軟體版本只支援定時器模式。

在Android上,oprofile分為target端和host端兩部分。target端運行在裝置上,主要包括一個核心模組(oprofile.ko)和一個使用者空間的守護進程(oprofiled),前者負責訪問效能計數器或者註冊基於時間採樣的函數(使用register_timer_hook註冊之,使時鐘中斷處理常式最後執行profile_tick時可以訪問之),並採樣置於核心的緩衝區內;後者在後台運行,負責從核心空間收集資料,寫入檔案。host端運行在PC上,包括一組後處理工具用於從原始採樣資料產生可讀的分析報告。

3.     oprofile使用方法
本節基於Android 2.1 (Eclair)介紹oprofile的使用方法,在Android 1.6 (Donut)和Android 2.2 (Froyo)上的使用方法與之相似。

在使用oprofile之前,首先必須確保燒到手機上的系統具有root許可權,否則無法使用oprofile,並確保/data下有足夠的可用空間用於儲存採樣資料(一般幾十MB足夠)。依次按照如下步驟操作。

3.1   步驟一:安裝target端
Android原始碼中已經包含了移植好的oprofile原始碼,kernel預設配置選項也已經enable了對oprofile的支援。在將oprofile的target端安裝到手機之前,請首先在eng模式下編譯原始碼,然後按照如下步驟將所需檔案複製到手機上:

1. 核心模組oprofile.ko:

在PC上運行:

source build/envsetup.sh

choosecombo

adb push $ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ/arch/arm/oprofile/oprofile.ko /data

2. 守護進程oprofiled和控製程序opcontrol:

如果手機上燒的system.img是eng模式編出來的,裡面已經包含了oprofiled和opcontrol(在/system/xbin/),這一步可以跳過;如果是user模式編出來的system.img則不包含這兩個檔案,請運行:

adb push $ANDROID_PRODUCT_OUT/system/xbin/oprofiled /system/xbin

adb push $ANDROID_PRODUCT_OUT/system/xbin/opcontrol /system/xbin

3. elf核心映像檔案:

如果要對核心進行profiling,需要將壓縮的elf核心映像檔案vmlinux複製到手機上,運行:

adb push $ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ/arch/arm/boot/compressed/vmlinux /data

該vmlinux必須與手機上實際啟動並執行核心一致。

3.2   步驟二:計算核心虛擬位址範圍
要對核心進行profiling,需要計算核心開始和結束位址:

運行:

adb pull /proc/kallsyms .

在檔案kallsyms中尋找_text,其數值即為kernel start地址;尋找_etext,其數值即為kernel end地址。

3.3   步驟三:將CPU設定在保持最高頻率運行
為確保oprofile採樣結果的準確性和一致性,在採樣開始之前需將CPU設定在保持最高頻率運行,為此在adb shell中運行:

mkdir /data/debug

mount -t debugfs debugfs /data/debug

echo 1 > /data/debug/nohlt

echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor

3.4    步驟四:配置oprofile
在adb shell中運行:

insmod /data/oprofile.ko timer=1

opcontrol --setup

oprofiled --session-dir=/data/oprofile --vmlinux=/data/vmlinux --kernel-range=start,end --events=CPU_CYCLES:255:0:50000:0:1:1 --separate-lib=1 --separate-kernel=1

說明:

其中--kernel-range中的start和end即為上述步驟二中獲得的kernel start地址和kernel end地址。

3.5   步驟五:開始採樣
運行需要進行profiling的應用程式或情境,然後在adb shell中運行:

opcontrol --start

此時oprofile已開始採樣,可在adb shell中運行:

opcontrol --status

隨時查看oprofile運行狀態和已採集的樣本數。

3.6   步驟六:停止採樣
當採集的樣本數足夠多的時候(根據經驗一般數千即可),在adb shell中運行:

opcontrol --stop

3.7   步驟七:上傳資料和產生分析結果
在PC上運行:

source build/envsetup.sh

choosecombo

cp $ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ/vmlinux $ANDROID_PRODUCT_OUT/symbols

python $ANDROID_BUILD_TOP/external/oprofile/opimport_pull ~/oprofile-result

此時手機上的採樣資料經轉換後存在PC上~/oprofile-result中,運行以下命令顯示分析結果報告:

cd ~/oprofile-result

$OPROFILE_EVENTS_DIR/bin/opreport --session-dir=. -p $ANDROID_PRODUCT_OUT/symbols -d -l

(註:在Android 2.1 (Eclair)中執行上面的命令出錯,需將opreport換成自己編譯的 0.9.4版本的opreport,編譯步驟參見本文附錄。)

注意:執行以上步驟時若遇到如下出錯資訊:

opreport: error while loading shared libraries: libbfd-2.18.0.20080103.so: cannot open shared object file: No such file or directory

可運行如下命令予以解決:

ln -s /usr/lib/libbfd.so /usr/lib/libbfd-2.18.0.20080103.so

3.8   重新運行oprofile
上述步驟一至七完成了一次完整的oprofile採樣和分析過程,若要再次運行oprofile,需複位oprofile並清理上一次的採樣資料,在adb shell中運行:

opcontrol --shutdown

rm /data/oprofile

umount /data/debug

rm -rf /data/debug

然後重新執行上述步驟三至七進行下一次的採集和分析。

4.     簡化oprofile使用步驟的指令碼
從上文的介紹可以看到oprofile的使用比較複雜,為簡化使用步驟,特編寫若干指令碼,只需按照如下步驟運行這些指令碼即完成oprofile的各項操作:

1.     工作環境準備:①在eng模式下編譯原始碼;②為使用oprofile建立一個工作目錄(例如~/oprofile),將下面附的壓縮包oprofile_cmd.zip解開到該目錄下,並進入到該目錄下;③按照前文3.2節的方法擷取kernel start地址和end地址填入op.sh;④確保燒到手機上的系統具有root許可權,且所編譯的核心原始碼與手機上實際啟動並執行核心一致;⑤確保運行過choosecombo;

2.     安裝target端:用資料線串連手機和PC,在PC上的oprofile工作目錄下運行:

./prepare.sh

(註:若系統是Android 1.6 (Donut),則運行./prepare.sh donut)

3.     採樣:運行需要進行profiling的應用程式或情境,然後在adb shell中運行:

cd /data

sh op.sh

此時可運行opcontrol --status查看oprofile運行狀態和已採集的樣本數,當採集的樣本數足夠多的時候(根據經驗一般數千即可),在adb shell中運行:

opcontrol --stop

4.     上傳資料:在PC上的oprofile工作目錄下運行:

./import.sh

5.     顯示分析結果:在PC上的oprofile工作目錄下運行:

./report.sh

6.     重新運行oprofile:在adb shell中運行:

cd /data

sh opclean.sh

然後重新執行上述步驟3至5。

5.     oprofile分析結果執行個體
下面是在Android 2.1 (Eclair)上對一個運行alpha animation的應用程式進行oprofile分析的結果:

CPU: CPU with timer interrupt, speed 0 MHz (estimated)

Profiling through timer interrupt

          TIMER:0|

  samples|      %|

------------------

     1769 98.4418 app_process

              TIMER:0|

      samples|      %|

    ------------------

         1299 73.4313 libskia.so

          386 21.8202 vmlinux

           39  2.2046 libdvm.so

           17  0.9610 libc.so

            9  0.5088 libui.so

            4  0.2261 libbinder.so

            4  0.2261 libsurfaceflinger.so

            4  0.2261 libutils.so

            3  0.1696 libandroid_runtime.so

            1  0.0565 libGLES_android.so

            1  0.0565 gralloc.qsd8k.so

            1  0.0565 libm.so

            1  0.0565 libstdc++.so

       13  0.7234 rild

              TIMER:0|

      samples|      %|

    ------------------

            9 69.2308 vmlinux

            4 30.7692 linker

        6  0.3339 vmlinux

        4  0.2226 cnd

              TIMER:0|

      samples|      %|

    ------------------

            2 50.0000 linker

            1 25.0000 cnd

            1 25.0000 vmlinux

        2  0.1113 adbd

              TIMER:0|

      samples|      %|

    ------------------

            2 100.000 vmlinux

        1  0.0556 init

              TIMER:0|

      samples|      %|

    ------------------

            1 100.000 vmlinux

        1  0.0556 port-bridge

              TIMER:0|

      samples|      %|

    ------------------

            1 100.000 vmlinux

        1  0.0556 opcontrol

              TIMER:0|

      samples|      %|

    ------------------

            1 100.000 vmlinux

 

samples  %        image name               app name                 symbol name

554      30.8292  libskia.so               app_process              S32A_Opaque_BlitRow32_neon

456      25.3756  libskia.so               app_process              S32A_D565_Blend_neon(unsigned short*, unsigned int const*, int, unsigned int, int, int)

128       7.1230  vmlinux                  app_process              __memzero

113       6.2883  libskia.so               app_process              memset_128_loop

78        4.3406  libskia.so               app_process              memset_128_loop

65        3.6171  vmlinux                  app_process              _spin_unlock_irqrestore

20        1.1130  vmlinux                  app_process              get_page_from_freelist

18        1.0017  libskia.so               app_process              Sprite_D32_S32::blitRect(int, int, int, int)

17        0.9460  vmlinux                  app_process              v7wbi_flush_user_tlb_range

16        0.8904  vmlinux                  app_process              free_hot_cold_page

15        0.8347  libskia.so               app_process              Sprite_D16_S32_BlitRowProc::blitRect(int, int, int, int)

13        0.7234  vmlinux                  app_process              _spin_unlock_irq

12        0.6678  libdvm.so                app_process              dalvik_inst

12        0.6678  libskia.so               app_process              SkDraw::drawPaint(SkPaint const&) const

11        0.6121  vmlinux                  app_process              __dabt_usr

11        0.6121  vmlinux                  app_process              v7_dma_flush_range

10        0.5565  libskia.so               app_process              S32A_D565_Opaque_Dither(unsigned short*, unsigned int const*, int, unsigned int, int, int)

...

從以上結果可以看出,在運行alpha animation的過程中,在oprofile採樣資料中2D圖形庫libskia.so佔了最高的比例,達73.4313%,具體是libskia.so中的函數S32A_Opaque_BlitRow32_neon和S32A_D565_Blend_neon分別佔了最高的前二名,說明在這一過程中最影響效能的瓶頸是在skia庫中的這幾個函數。

附錄  關於在Android 1.6 (Donut)上使用oprofile的注意事項
Android 1.6 (Donut)中內建的opimport和opreport(位於$OPROFILE_EVENTS_DIR/bin/)是64位的,只能在安裝了64位Linux系統的PC上運行,要在32位系統的PC上運行,解決方案是自己編譯0.9.4版本的opimport和opreport(因Android 1.6 (Donut)中內建的oprofile是0.9.4版本的)。0.9.4版本oprofile原始碼附在下面:(略)

 

編譯步驟如下:

source build/envsetup.sh

choosecombo

tar -zxvf oprofile-0.9.4.tar.gz

cd oprofile-0.9.4

./configure --with-linux=$ANDROID_PRODUCT_OUT/obj/KERNEL_OBJ

make

make install

或者採用Android 2.1 (Eclair)以上版本中內建的opimport和opreport(版本為0.9.5)也可以。

此外Android 1.6 (Donut)中的指令碼$ANDROID_BUILD_TOP/external/oprofile/opimport_pull有問題,可替換成Android 2.1 (Eclair)以上版本中的此檔案。
作者:迷糊

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.