Fork me on GitHub

6/20/2012

[Android] oprofile 使用步驟

This post records the basic flow to use oprofile tool on Android

OProfile consists of a Kernel driver and a daemon for collecting data. It makes use of the hardware performance counters provided on Intel, AMD, and other processors. OProfile is capable of profiling all code including the Kernel, Kernel modules, Kernel interrupt handlers, system shared libraries, and other applications.

Modern processors support profiling through the hardware by performance counters. Depending on the processor, there can be many counters and each of these can be programmed with an event to count. Each counter has a value which determines how often a sample is taken. The lower the value, the more often it is used.

During the post-processing step, all information is collected and instruction addresses are mapped to a function name.

Here we go ~

  1. Add config, re-build kernel then flash into device

    CONFIG_OPROFILE_ARMV7=y
    CONFIG_OPROFILE=y
    CONFIG_PROFILING=y
    CONFIG_HAVE_OPROFILE=y
    CONFIG_TRACEPOINTS=y
    
  2. Build oprofile tool

    $ source setbuildenv
    $ cd {root}/external/oprofile
    $ mm
    
    The output will be at "out/host/linux-x86/bin/"
    
  3. Copy needed file

    $ cp {root}/external/oprofile/events/arm/* /usr/local/share/oprofile/arm
    
  4. Copy vmlinux into device (Optional, if you want to profile kernel)

    $ adb push ${OUT}/obj/KERNEL/arch/arm/boot/compressed/vmlinux data/
    
  5. Setup oprofile

    opcontrol --setup --event=CPU_CYCLES:1500000
    opcontrol --setup --vmlinux=/data/vmlinux --kernel-range=0xc00xxxxx,0xc0xxxxxx --event=CPU_CYCLES:1500000 (profile kernel)
    
    The option --kernel-range can be obtained from /proc/kallsyms.
    $ (adb shell cat /proc/kallsyms) | grep " _text" 
    $ (adb shell cat /proc/kallsyms) | grep " _etext" 
    
    or you could query System.map file
    $ grep " _text" System.map
    
  6. Check status

    opcontrol --status
    
  7. Start profiling

    opcontrol --start
    
  8. Stop profiling

    opcontrol --stop
    
  9. Get profiling result

    $ cd {root}/external/oprofile
    $ ./opimport_pull <result path>
    
  10. Get a simple report

    $ cd {root}/out/host/linux-x86/bin/
    $ ./opreport --session-dir <result-path> -m all
    $ ./opreport -g -l -p <path-to-symbols> --session-dir <result-path>
    
  11. Get annotated report

    $ ./opannotate -p <path-to-symbols> -s -d <path-to-source-files-e.g.-mydroid> --session-dir <result-path>
    
  12. Profiling based on thread

    opcontrol --setup --event=CPU_CYCLES:1500000 --separate=thread // profiling based on thread
    $ ./opimport_pull <result-path>
    $ ./opreport --session-dir <result-path> -l tgid:[pid you want]
    

References

  1. OProfile manual
  2. Profiling the Android kernel and native applications using OProfile
  3. Profiling Tools - ftrace, perf, and oprofile
  4. how-to to oprofile 0xdroid
  5. oprofile 使用步驟 測試程序中各函數運行時間
  6. OProfile—System-Wide Profiler

--EOF--

6/14/2012

[Linux] Unbalanced irq

中斷算是 kernel 開發過程中經常遇到問題的部份,最近在 log 當中經常看到 Unbalanced irq 的訊息,雖然只是 Warning,還是想研究一下怎麼把它弄掉!

搜尋後整理一些網路上關於 irq 使用的資訊摘要如下:

  1. enable_irq unbalanced messages 是無害的

     unbalanced 這個問題只會發生在 enalbe_irq 函數中,這裡要提到一個變量disable_depth,這是一個標志中斷禁止與否的變量,如果調用 disabled,這個變量會 ++,成正數,表示禁止中斷; 如果是 enable,這個變量會 --,表示允許。
    
     而如果這個變量本身就是 0,再去 enable 它的時候,表示你這個中斷本來就是打開的,你現在再去打開沒有必要,這就是 unbalanced 了
    
  2. request_irq 的調用應該放到所有的准備工作都完成後再進行

     我們應該確保只有在有能力處理中斷的時候在去註冊中斷!因為只要 request_irq 正確返回就意味著可以響應中斷了。
    
     想要在該註冊函數返回後立刻調用 disable_irq 來暫時屏蔽中斷,然後在後面的某個時刻在 enable 中斷是不對的。因為在你 disable_irq 之前可能中斷已經發生並且調用了中斷處理函數!
    
     一般對中斷的注冊都放在 probe 的最後一步來做!這樣可以避免一些中斷過早被調用的問題!
    
     一般我們會在中斷處理函數進去的時候 disable 一個 irq,並在中斷處理函數退出的時候 enable 這個 irq。這樣做當然能讓 disable 和enable 匹配的很好。
    
     但有的時候你可能想把 disable 放到中斷當中,而把 enable 放到下半部去完成。這就要慎重了,需要仔細檢查下半部的代碼是否一定會在你需要的時候被執行,稍有不慎你可能就會造成下半部的 enable 未被執行。導致缺少一次匹配的 enable,進而導致中斷失效。
    
  3. 中斷有可能在不那麼容易被注意到的時機被觸發

     引述 Reference 中的例子:
    
     在設計這個電容屏的驅動時,我的設計為在其 suspend 函數中直接切斷電容屏的電源以省電,然後在 resume 函數中再從新上電。中斷觸發方式為下降沿觸發方式。測試發現,當在 suspend 中調用斷電操作後總會導致一個 I2C 讀取動作發生,而這個讀取動作是我在中斷處理函數的底半部中實現的動作。僅僅是電容屏的一個斷電動作怎麼會導致這個動作發生呢?
    
     降沿觸發嘛~~  當電容屏斷電後當然沒有誰去保持那個中斷引腳為高電平了,它當然會恢復為默認的低電平了(該平台的中斷默認為電平)。顯然這個過程會導致一個下降沿發生,這便會引起中斷處理函數被調用,從而引起底半部的工作隊列被執行,然後 I2C 讀取動作便發生了。可是這時候電容屏都斷電了,讀取當然要出錯了!
    
     現在的問題就是如何讓這個下降沿不要發生,那就只能想辦法讓系統不要理會這個下降沿。簡單,斷電前先 disable 中斷,resume 完成後重新 enable 這個中斷就好了
    
  4. request_irq 之後沒有 disable 過的 irq 如果 enable_irq 都會造成 Unbalanced irq 的 warning

References

  1. linux中斷的unbalanced問題
  2. request_irq的執行時機 關鍵字: irq INT 底半部 unbalanced 工作隊列
  3. unbalanced enable irq 問題的解決 以及共享的gpio中斷引起的問題
  4. Linux 中斷學習之小試牛刀篇

6/07/2012

[Android] wake lock

"wake lock" was a set of patches to the Linux kernel to allow a caller to prevent the system from going to low power state.

所以,在 kernel 下,可以運用這種機制,讓系統不要進入 suspend。

  1. 加入必要 header

    #include <linux/wakelock.h>
    
  2. 初始化 wake lock

    wake_lock_init(&wlock, WAKE_LOCK_SUSPEND, "hdmi_active");
    
    
    通常在 module init 函數或是 probe 函數當中進行這個動作。第二個參數可設定為 WAKE_LOCK_IDLE / WAKE_LOCK_SUSPEND
    
  3. 鎖住 wake lock

    wake_lock(&wlock);
    
  4. 釋放 wake lock

    wake_unlock(&wlock);
    
  5. 註銷 wake lock

    wake_lock_destroy(&wlock);
    

在程式碼中完成後,如何驗證 wake lock 是否正確的被 lock/unlock 呢?可以利用不斷 cat proc/wakelocks 這個 node,觀察其變化。如果已經被 unlock 了,那麼 time 的欄位就會停止變動。

watch -n 1 'adb shell "cat proc/wakelocks" | grep usb_udc_lock' 

Ref.

  1. Android Power Management
  2. Android wakelock的申請和釋放