安卓性能測試之cpu占用率統(tǒng)計方法總結

安卓性能測試的重要方面是對各項性能指標的采集和分析,如常見性能指標內存、cpu、電量、流量等,本文整理了cpu占有率統(tǒng)計方法和基本原理。

安卓性能指標cpu主要關注兩點:
(1)cpu總體使用率(2)應用程序cpu占用率。

cpu指標的查看方式有多種,最直接的就是android自帶的DDMS可視化工具,也可以在IDE(Android Studio)的Monitor中實時查看。另外就是通過linux系統(tǒng)/proc/stat和/proc/<pid>/stat文件進行占用率的計算,也可以利用top命令或者dumpsys cupinfo等命令實時查看當前cpu情況。我們接下來詳細看下每一種方法是如何查看和獲得cpu占用率數(shù)據(jù)。

一、DDMS等可視化工具

我們可以通過安卓SDK自帶的DDMS工具查看當前安卓應用程序的CPU和內存使用情況:



另外也可以通過Android Studio自帶的cpu Monitor來實時查看CPU使用情況:

二、/proc/stat及/proc/<pid>/stat文件計算

/proc文件系統(tǒng)是一個偽文件系統(tǒng),它只存在內存當中,而不占用外存空間。它以文件系統(tǒng)的方式為內核與進程提供通信的接口。用戶和應用程序可以通過/proc得到系統(tǒng)的信息,并可以改變內核的某些參數(shù)。由于系統(tǒng)的信息,如進程,是動態(tài)改變的,所以用戶或應用程序讀取/proc目錄中的文件時,/proc文件系統(tǒng)是動態(tài)從系統(tǒng)內核讀出所需信息并提交的。

我們關注的安卓性能指標cpu關注的cpu總體使用率和應用程序cpu占用率主要與兩個proc文件相關,分別是/proc/stat和/proc/<pid>/stat文件(pid是該應用程序的進程號)。

1./proc/stat與cpu總體使用率的計算

/proc/stat文件包含了所有CPU活動的信息,該文件中的所有值都是從系統(tǒng)啟動開始累計到當前時刻的統(tǒng)計值。不同內核版本中該文件的格式可能不大一致,以下通過實例來說明數(shù)據(jù)該文件中各字段的含義。
不管是mac還是windows,我們是無法直接看到/proc/stat文件的,我們可以使用adb shell命令進入Android shell命令模式(可以理解成進入當前設備的Linux Shell系統(tǒng))進行查看,這時候模擬器或者手機要啟用并且正確接通。


進入目標設備的Linux Shell環(huán)境, 在該環(huán)境中可以執(zhí)行一些Linux命令。如在Linux Shell環(huán)境中執(zhí)行ps可以查看android設備中運行的所有進程。在Linux Shell環(huán)境中執(zhí)行exit可以退出Linux Shell環(huán)境。

1.1 /proc/stat文件分析

我們在Linux Shell環(huán)境中使用cat命令查看/proc/stat文件。


該文件顯示的第一行就是cpu總體的使用情況,每列數(shù)值是后面幾行邏輯處理器每列數(shù)據(jù)的相加值,可見該cpu共有4個邏輯處理器(Processor),我們也可以通過/proc/cpuinfo文件去查看該Linux內核的cpu具體情況。我們依據(jù)Linux用戶手冊詳細看下第一行cpu數(shù)據(jù)的每列數(shù)據(jù)代表的含義。
1)這些數(shù)值的單位都是 jiffies,jiffies 是內核中的一個全局變量,用來記錄系統(tǒng)啟動以來產(chǎn)生的節(jié)拍數(shù),在 Linux 中,一個節(jié)拍大致可以理解為操作系統(tǒng)進程調度的最小時間片,不同的 Linux 系統(tǒng)內核這個值可能不同,通常在 1ms 到 10ms 之間。
2)cpu 552 56 1496 266573 652 0 224 0 0 0

**user(552) ** Time spent in user mode.
從系統(tǒng)啟動開始累積到當前時刻,處于用戶態(tài)的運行時間,不包含 nice 值為負的進程。
nice(56) Time spent in user mode with low priority(nice).
系統(tǒng)啟動開始累積到當前時刻,nice 值為負的進程所占用的 CPU 時間。Nice值是類UNIX操作系統(tǒng)中表示靜態(tài)優(yōu)先級的數(shù)值。 每個進程都有自己的靜態(tài)優(yōu)先級,優(yōu)先級高的進程得以優(yōu)先運行。
system(1496) Time spent in system mode.
從系統(tǒng)啟動開始累積到當前時刻,處于核心態(tài)的運行時間。
idle(266573) Time spent in the idle task.
從系統(tǒng)啟動開始累積到當前時刻,除 IO 等待時間以外的其他等待時間。
**iowait(652) ** Time waiting for I/O to complete.
從系統(tǒng)啟動開始累積到當前時刻,IO 等待時間。(since 2.5.41,內核版本,下同)
**irq(0) ** Time servicing interrupts.
從系統(tǒng)啟動開始累積到當前時刻,服務中斷時間。(since 2.6.0-test4)
softirq(224) Time servicing softirqs.
從系統(tǒng)啟動開始累積到當前時刻,軟中斷時間。(since 2.6.0-test4)
**stealstolen(0) ** Stolen time, which is the time spent in other operating systems when running in a virtualized environment.
從系統(tǒng)啟動開始累積到當前時刻,在虛擬環(huán)境運行時花費在其他操作系統(tǒng)的時間。(since 2.6.11)
**guest(0) ** Which is the time spent running a virtual CPU for guest operating systems under the control of the Linux kernel.
從系統(tǒng)啟動開始累積到當前時刻,在Linux內核控制下的操作系統(tǒng)虛擬cpu花費的時間。(since 2.6.24)
guest_nice Time spent running a niced guest (virtual CPU for guest operating systems under the control of the Linux kernel).
從系統(tǒng)啟動開始累積到當前時刻,在Linux內核控制下的操作系統(tǒng)虛擬cpu花費在nice進程上的時間。(since Linux 2.6.33)

PS:這里涉及到Linux內核的版本情況,我們可以通過uname -a和/proc/version來查看自己Android設備的Linux內核情況。下圖為我的Android設備(genymotion模擬器)的Linux內核情況,可見我的內核版本是3.10版本,所以我查看到的/proc/stat文件里首行會顯示所有的列數(shù)據(jù)。


其他行數(shù)據(jù)可以通過繼續(xù)Linux用戶手冊來查看。

1.2 cpu總體使用率的計算

cpu總的使用時間計算如下:

totalCPUTime = user + nice + system + idle + iowait + irq + softirq + stealstolen + guest + guest_nice

也就是/proc/stat的首行所有列數(shù)據(jù)的加和值。我們的目標是計算總體cpu使用率。

通常我們都會選擇較短的時間進行取樣兩次cpu數(shù)據(jù)1和2。
常用cpu占用率方法可描述為:
totalCPUrate = (非空閑cpu時間2-非空閑cpu時間1)/(cpu總時間2-cpu總時間1)x100%
換成變量描述為:
totalCPUrate =( (totalCPUTime2-idle2)-(totalCPUTime1-idle1))/(totalCPUTime2-totalCPUTime1)x100%

那么根據(jù)/proc/stat文件可以得到cpu總體使用率的計算方法:

  1. 采樣兩個足夠短的時間間隔的cpu數(shù)據(jù),分別記作t1、t2,其中t1、t2的結構均為:
    (user、nice、system、idle、iowait、irq、softirq、stealstolen、guest、guest_nice)的10元組;(當然這里依據(jù)Linux內核的不同有些數(shù)據(jù)可能沒有,就不必計入)
  2. 計算t1、t2總的cpu時間片totalCPUTime
    a) 把第一次的所有cpu10元組數(shù)據(jù)求和,得到totalCPUTime1;
    b) 把第二次的所有cpu10元組數(shù)據(jù)求和,得到totalCPUTime2;
  3. 計算空閑時間idle
    cpu空閑時間對應第四列的數(shù)據(jù)
    a)獲得第一次的idle數(shù)據(jù),記為idle1
    b)獲得第二次的idle數(shù)據(jù),記為idle2
  4. 計算cpu使用率
    totalCPUrate = ((totalCPUTime2-idle2)-(totalCPUTime1-idle1))/(totalCPUTime2-totalCPUTime1)x100%

了解了整體的計算方法后,我們可以使用java代碼進行簡要實現(xiàn)。

1.3 cpu總體使用率計算的java實現(xiàn)

核心的計算方法抽取出來如下:(參考了騰訊GT的CPU數(shù)據(jù)實現(xiàn)方法)

public String getCpuUsage() {
        double usage = 0.0;
        boolean initCpu = true;
        if (initCpu) {
            initCpu = false;
            RandomAccessFile reader = null;
                reader = new RandomAccessFile("/proc/stat","r");
                String load = reader.readLine();
                String[] toks = load.split(" ");
                o_idle = Double.parseDouble(toks[5]);
                o_cpu = Double.parseDouble(toks[2])
                        + Double.parseDouble(toks[3])
                        + Double.parseDouble(toks[4])
                        + Double.parseDouble(toks[6])
                        + Double.parseDouble(toks[7])
                        + Double.parseDouble(toks[8])
                        + Double.parseDouble(toks[9]);
                FileUtil.closeRandomAccessFile(reader);
        } else {
            RandomAccessFile reader = null;
                reader = new RandomAccessFile("/proc/stat", "r");
                String load;
                load = reader.readLine();
                String[] toks = load.split(" ");
                double c_idle = Double.parseDouble(toks[5]);
                double c_cpu = Double.parseDouble(toks[2])
                        + Double.parseDouble(toks[3])
                        + Double.parseDouble(toks[4])
                        + Double.parseDouble(toks[6])
                        + Double.parseDouble(toks[7])
                        + Double.parseDouble(toks[8]);
                        + Double.parseDouble(toks[9]);
                if (0 != ((c_cpu + c_idle) - (o_cpu + o_idle))) {
                     usage = DoubleUtils.div((100.00 * ((c_cpu - o_cpu))),
                            ((c_cpu + c_idle) - (o_cpu + o_idle)), 2);
                }
                o_cpu = c_cpu;
                o_idle = c_idle;
                FileUtil.closeRandomAccessFile(reader);
         }
        return String.valueOf(usage) + "%";
    }```
需要注意的是,上述代碼只是一個核心算法的示例,真正實現(xiàn)的話還需要考慮Linux內核的不同導致取值范圍的不同,另外計算出usage值為負或者為大于100的特殊情況處理。
#### 2./proc/<pid>/stat與應用程序cpu占有率的計算
/proc/<pid>/stat文件包含了某一進程所有的活動的信息,該文件中的所有值都是從系統(tǒng)啟動開始累計到當前時刻的統(tǒng)計值。以下通過實例數(shù)據(jù)來說明該文件中各字段的含義。
##### 2.1 /proc/<pid>/stat文件分析
我們在Linux Shell環(huán)境中使用cat命令查看/proc/<pid>/stat文件。我們可以先通過top命令獲得目標應用的進程id。
![](http://upload-images.jianshu.io/upload_images/1430132-283d098b3127289e.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
這里我們的目標進程id是1378。這時候我們去內存中查看/proc/1378/stat文件:

![](http://upload-images.jianshu.io/upload_images/1430132-27d83e139a70bb10.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
根據(jù)[Linux用戶手冊](http://man7.org/linux/man-pages/man5/proc.5.html)我們可以看到/proc/1387/stat文件中各個字段代表的含義,其中與我們計算應用程序cpu占用率相關的數(shù)據(jù)主要有如下幾個:
>pid=1378                          進程號
utime=1286                       該任務在用戶態(tài)運行的時間,單位為jiffies
stime=1854                      該任務在核心態(tài)運行的時間,單位為jiffies
cutime=6                            所有已死線程在用戶態(tài)運行的時間,單位為jiffies
cstime=2                            所有已死在核心態(tài)運行的時間,單位為jiffies

##### 2.2 cpu總體使用率的計算
應用程序cpu的使用時間計算如下:
>processCPUTime = utime + stime,該值包括其所有線程的cpu時間。

通常我們都會選擇較短的時間進行取樣兩次總體cpu數(shù)據(jù)和應用程序cpu數(shù)據(jù),分別記為1和2。常用應用程序cpu占用率方法可描述為:
>processCPUrate = ( processCPUTime2 – processCPUTime1) / (totalCPUTime2 – totalCPUTime1) x100%

那么根據(jù)/proc/stat文件和/proc/<pid>/stat文件可以得到某應用程序cpu占用率的計算方法:
1.   **采樣兩個足夠短的時間間隔的cpu數(shù)據(jù)和進程cpu數(shù)據(jù),分別記作t1、t2,其中t1、t2的cpu數(shù)據(jù)結構均為:
(user、nice、system、idle、iowait、irq、softirq、stealstolen、guest、guest_nice)的10元組;t1、t2的進程cpu數(shù)據(jù)結構為(utime、stime)的2元組。**
2.  **計算t1、t2總的cpu時間totalCPUTime和進程cpu時間processCPUTime
a)         把第一次的所有cpu10元組數(shù)據(jù)求和,得到totalCPUTime1;
b)         把第二次的所有cpu10元組數(shù)據(jù)求和,得到totalCPUTime2;
c) 把第一次的所有進程cpu4元組數(shù)據(jù)求和,得到processCPUTime1;
d) 把第二次的所有進程cpu4元組數(shù)據(jù)求和,得到processCPUTime2**
3. **計算應用程序cpu使用率
processCPUrate = ( processCPUTime2 – processCPUTime1) / (totalCPUTime2 – totalCPUTime1) x100%**

了解了整體的計算方法后,我們可以使用java代碼進行簡要實現(xiàn)。
##### 2.3 cpu總體使用率計算的java實現(xiàn)
核心的計算方法抽取出來如下:(參考了騰訊GT的CPU數(shù)據(jù)實現(xiàn)方法)

public String getProcessCpuUsage(int pid) {

    String result = "";
    String[] result1 = null ;
    String[] result2 = null;
    if (pid >= 0) {
        result1 = getProcessCpuAction(pid);
        if (null != result1) {
            pCpu = Double.parseDouble(result1[1])
                    + Double.parseDouble(result1[2]);
        }
        result2 = getCpuAction();
        if (null != result2) {
            aCpu = 0.0;
            for (int i = 2; i < result2.length; i++) {
                aCpu += Double.parseDouble(result2[i]);
            }
        }
        double usage = 0.0;
        if ((aCpu - o_aCpu) != 0) {
            usage = DoubleUtils.div(((pCpu - o_pCpu) * 100.00),
                    (aCpu - o_aCpu), 2);
        }
        o_pCpu = pCpu;
        o_aCpu = aCpu;
        result = String.valueOf(usage) + "%";
    }
    p_jif = pCpu;
    return result;
}```

這里getProcessCpuAction(pid)和getCpuAction()分別處理/proc/<pid>/stat文件和/proc/stat文件,將應用程序的cpu和總體cpu數(shù)據(jù)分別保存在result1和result2變量中,然后進行計算。由于篇幅有限,處理文件的方法具體實現(xiàn)就不展開了。

三、基本命令獲取cpu使用情況

除了可以從/proc文件系統(tǒng)中計算出cpu使用率外,我們也可以采用直觀簡單的命令來拿到cpu使用情況。當然了,不管是Linux還是Android系統(tǒng)提供的命令行查看,都是基于proc文件系統(tǒng)計算得到的,不同命令方法獲得的數(shù)據(jù)可能會有差異,甚至與自己計算的也有不同,這是因為采用不同的計算方法和計算精度得到的,誤差可接受。

1.top命令

top命令是Linux下常用的性能分析工具,能夠實時顯示系統(tǒng)中各個進程的資源占用狀況,類似于Windows的任務管理器。top是一個動態(tài)顯示過程,即可以通過用戶按鍵來不斷刷新當前狀態(tài)。如果在前臺執(zhí)行該命令,它將獨占前臺,直到用戶終止該程序為止。top命令提供了實時的對系統(tǒng)處理器的狀態(tài)監(jiān)視。它將顯示系統(tǒng)中CPU最“敏感”的任務列表。該命令可以按CPU使用、內存使用和執(zhí)行時間對任務進行排序。


使用top命令,可以讓我們一眼直觀地看到應用程序cpu占用率的情況。
PID是進程的ID,是唯一的
CPU不用說了,就是CPU占用比率
VSS(Virtual Set Size)虛擬耗用內存(包含共享庫占用的內存)
PSS(Proportional Set Size)實際使用的物理內存(比例分配共享庫占用的內存)
RSS(Resident Set Size)實際耗用的物理內存(包含共享庫占用的內存)
USS(Unique Set Size)進程獨自占用的物理內存(不包含共享庫占用的內存)
使用此方法的優(yōu)點就是獲取信息簡單容易。使用次方法的缺點也一目了然,就是精確度不是很高。另外一些較為常用的top命令:

可查看占用cpu最高的前10個程序(-t 顯示進程名稱,-s 按指定行排序,-n 在退出前刷新幾次,-d 刷新間隔,-m 顯示最大數(shù)量):
top -m 10 -s cpu
如果你想篩選出你自己的應用的話可以用下面這一命令:
adb shell top -n 1| grep PackageName

2.dumpsys cpuinfo命令

Android提供的dumpsys工具可以用于查看感興趣的系統(tǒng)服務信息與狀態(tài),dumpsys cpuinfo可以用來查看安卓系統(tǒng)當前的cpu使用情況。

這個能夠統(tǒng)計到所有應用的CPU占用信息,要比top -n 1獲得的信息更加詳細一些。
缺點就是這種方法會有權限問題,ROOT了之后才能使用。

以上便是安卓端統(tǒng)計cpu占用率的主要方法,拿到數(shù)據(jù)比較簡單,難的是如何分析拿到的cpu數(shù)據(jù),找到性能瓶頸點和優(yōu)化點,這也是做安卓性能測試的重要方向。

參考文章:
http://www.blogjava.net/fjzag/articles/317773.html
http://liandongyang.coding.me/post/%E5%85%B3%E4%BA%8EAndroid%E7%9A%84CPU%E5%86%85%E5%AD%98%E7%9B%91%E6%8E%A7/http://blog.csdn.net/q838197181/article/details/50622498

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容