99% CPU Usage!Why ?

前陣子接到一個新任務,就是要把 B2G 移植到新的 Samsung Galaxy S2 手機上。雖然這支手機也是 Galaxy S2,不過,他的 model name 是 GT-I9100G ,跟台灣市售的 GT-I9100 是完全不同的平台,有興趣的朋友可以參考這裡。移植的過程中碰到了不少問題,在看到 B2G 成功的在新手機上跑起來,內心說真的還蠻感動的。移植成功後,當然要測試一下各個功能是否正常囉!嗯,看起來 Touch 功能是正常的,滑來滑去,還蠻順的。接著,再來放個電影看看, 哈哈!聲音和影像都正常呢!WiFi 連線也沒有問題,終於成功了。正當得意之際,突然發現怎麽 Touch 功能不會動了呢?當滑動螢幕時,系統一直把滑動 event 誤判為 Do you want to uninstall your <app>,難道是 input event 的偵測出了問題?

Input event 實作的進入點目前是在 gecko/widget/gonk 這個目錄下的 nsAppShell.cpp,而 input event 的處理則是透過 Android framework 下的 libui 函式庫來實作,並且透過 widget/gonk/nsWindow.cpp 的 DispatchInputEvent () 函式將從 input device 所接收到的 event 傳到對應的 component 作處理。Input device 的 device nodes 目前是位於 /dev/input,有興趣的朋友可以 Trace 一下相關的程式碼。利用 logcat,我們可以得到 input event 的 debug 訊息,但是要先打開 gecko/widget/gonk/libui/InputReader.cpp 的 debug flag。

打開 debug flag 再重新 編輯後,我們可以得到 InputReader 相關的 log,經過我們的分析後,我們發現 input event 的偵測部分是正常運作的,那問題到底出在什麽地方呢 ?

好吧,用 top 來看一下有沒有什麽線索好了。哇!B2G process 的 CPU usage 居然是 99%耶,由於目前 B2G 這個 project 是 multi-threads 的架構,因此,首先我們必需知道每個 threads 的 CPU usage:

我們可以利用 toolbox 所提供的 top 指令來獲得 Thread level 的 CPU usage 資訊。除了 top 指令外,B2G project 也支援了 perf 及 oprofile 這兩個常見的工具,對於 performance profiling 有興趣的朋友可以參考這裡

利用 toolbox 所提供的 top 指令,我們可以知道 TID = 14241 , 14166 及 TID = 14235 這幾個 Threads 佔用了最多的 CPU 資源,因此,我們可以透過 GDB 這個工具來看看到底這幾個 Threads 發生了什麽事情。

GDB 是「 The GNU Project Debugger」 的縮寫,對 GDB 這個工具不熟悉的朋友,可以參考 GNU 的網站。為了簡化 GDB 的設定, B2G project 提供了 簡單的 make 指令來設定 GDB,我們可以用 make run-gdb 這個指令來啟動 GDB。在執行了make run-gdb 指令後,應該會看到 gdb 的命令提示符號,這時,我們就可以利用 gdb 所支援的功能繼續 debug 了。

我這裏先介紹幾個常用的 GDB 指令:

設定好 GDB 後,我們可以利用 top 指令所得到的 Thread ID 及 GDB 來確定是那一個 Threads 發生問題。首先,我們利用 info threads 得到 Id - Thread id 的對應關係:

接著利用 thread id 指令來切換目前的 Thread ,最後再利用 bt 指令來看這個 Thread 目前 stack 的 backtrace。利用 stack 的 backtrace 資訊,我們就可以知道目前這個 Thread 正在執行的函式了,有了這些資訊,再配合原始碼,就可以幫助我們判斷問題發生的原因了。

在這個例子裡,我們利用 GDB 及 top 指令來幫忙解決將 B2G 移植到新手機時 input event 判斷錯誤的問題,以這些工具所收集到的資訊並加以分析之後,我們發現是 Timer Thread 進入了無窮迴圈。每隔幾個微秒 Timer Thread 就會傳送 timeout event 給其它的 Threads ,因而造成整個系統非常的忙碌,而無法正確處理 input event。雖然說 GDB 及 top 這兩個工具可以加速我們找到問題點,但是,問題真正發生的原因,還是需要透過追蹤原始碼才有辦法得知。原來,Timer Thread 為了更準確的處理 timeout event ,所以,當下一次 timeout event 的發生時間小於某個特定值時,Timer thread 會直接把 timeout event 取出並傳送給對應的 Thread,這樣可以避免因為排程所造成的時間誤差。但是,當我們將 B2G 移植到不同的手機上時,因為系統不同,所以誤判發生 timeout event 的時間,而造成整個系統都在處理 timeout event ,使得CPU 非常忙碌。

您可能也會喜歡

目前找不到相關文章

共 1 則讀者回應

  1. 你好,我想請教一下,B2G里是不是每開一個應用程序,就開始一個新的線程?

    這點我認為跟Firefox是一樣的,每開一個Tab頁或者新窗口,就開始一個新的線程。

    您看是這樣的嗎?

對此文章發表回應

你的電子郵件位址並不會被公開。 必要欄位標記為 *