Android中獲取CPU負載和進程cpu時間

        android系統中有一個ProcessStats類,咱們可使用它來獲取系統的負載狀況及進程時間。html

        實現原理是讀取/proc目錄下的文件。linux系統運行時,內核會去更新 /proc目錄下的文件,將PID的運行狀況寫入相應的文件中。咱們主要關注如下文件
java

1. /proc/statlinux

該文件包含了從系統啓動開始累積到當前時刻的CPU活動信息。android

看下我手機的狀況,以下shell

cat /proc/stat函數

cpu  14869 5121 19794 156065 3114 0 26 0 0 0 oop

cpu0 10268 4823 15912 84682 2800 0 23 0 0 0ui

intr 8830975 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5926 0 0 0 0 0 0 0 0 0 0 0 0 0 0 84406spa

0 0 0 0 0 0 0 0 0 0 13205 0 2195 0 0 0 0 2 2 0 4304 0 1 0 0 0 0 0 0 0 0 0 0 0 0.net

0 0 0 0 0 0 0 0 0 0 1570 0 321 0 7132798 0 3638 21 0 0 1 0 0 0 134 0 0 0 0 0 0 0

 0 0 0 0 715 835 0 0 168670 0 0 0 0 0 0 0 0 0 0 0 0 0 2124 28527 0 0 200 0 0 0 0

 4823 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

ctxt 15331839

btime 1423869515

processes 2813

procs_running 3

procs_blocked 1

softirq 135522 11 57942 11 3386 11 11 8212 5725 54 60159

cpu的每一列的意思以下

user (14869 ) 從系統啓動開始累計到當前時刻,用戶態的CPU時間(單位:jiffies) ,不包含 nice值爲負進程。1jiffies=0.01秒
nice (5121 ) 從系統啓動開始累計到當前時刻,nice值爲負的進程所佔用的CPU時間(單位:jiffies)
system (19794 ) 從系統啓動開始累計到當前時刻,核心時間(單位:jiffies)
idle (156065 ) 從系統啓動開始累計到當前時刻,除硬盤IO等待時間之外其它等待時間(單位:jiffies)
iowait (3114 ) 從系統啓動開始累計到當前時刻,硬盤IO等待時間(單位:jiffies) ,
irq (0) 從系統啓動開始累計到當前時刻,硬中斷時間(單位:jiffies)
softirq (26) 從系統啓動開始累計到當前時刻,軟中斷時間(單位:jiffies)

後三個android沒有讀取,估計沒用。

手機是單核從,因此只有cup0,含義和上面同樣

其餘的以下:

「intr」這行給出中斷的信息,第一個爲自系統啓動以來,發生的全部的中斷的次數;而後每一個數對應一個特定的中斷自系統啓動以來所發生的次數。
「ctxt」給出了自系統啓動以來CPU發生的上下文交換的次數。
「btime」給出了從系統啓動到如今爲止的時間,單位爲秒。
「processes (total_forks) 自系統啓動以來所建立的任務的個數目。
「procs_running」:當前運行隊列的任務的數目。
「procs_blocked」:當前被阻塞的任務的數目。


2./proc/loadavg

系統平均負載.該文件中的全部值都是從系統啓動開始累計到當前時刻。該文件只給出了全部CPU的集合信息,不能該出每一個CPU的信息。


我手機中以下:

cat /proc/loadavg

10.78 9.55 7.20 5/818 3719


每一個值的含義爲:
參數 解釋
lavg_1 (10.78) 1-分鐘平均負載
lavg_5 (9.55) 5-分鐘平均負載
lavg_15(7.20) 15-分鐘平均負載
nr_running (5) 在採樣時刻,運行隊列的任務的數目,與/proc/stat的procs_running表示相贊成思
nr_threads (818) 在採樣時刻,系統中活躍的任務的個數(不包括運行已經結束的任務)
last_pid(3719) 最大的pid值,包括輕量級進程,即線程。



3.進程信息

以PID做爲文件夾名。

例如進程2411的stat以下

cat /proc/2411/stat

2411 (loop43) S 2 0 0 0 -1 2129984 0 0 0 0 0 150 0 0 0 -20 1 0 7794 0 0 42949672

95 0 0 0 0 0 0 0 2147483647 0 4294967295 0 0 17 2 0 0 0 0 0 0 0 0

每一項的含義能夠看http://www.net527.cn/a/caozuoxitong/Linux/2012/0823/24385.html




有了以上的基礎,咱們就能夠看ProcessStats這個類了。

update()函數讀取上面所提的信息。

    public void update() {
        ......
        // 讀取/proc/stat中的cpu時間
        if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
                null, sysCpu, null)) {
            // Total user time is user + nice time.
            final long usertime = sysCpu[0]+sysCpu[1];
            // Total system time is simply system time.
            final long systemtime = sysCpu[2];
            // Total idle time is simply idle time.
            final long idletime = sysCpu[3];
            // Total irq time is iowait + irq + softirq time.
            final long iowaittime = sysCpu[4];
            final long irqtime = sysCpu[5];
            final long softirqtime = sysCpu[6];
 
            mRelUserTime = (int)(usertime - mBaseUserTime);
            mRelSystemTime = (int)(systemtime - mBaseSystemTime);
            mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
            mRelIrqTime = (int)(irqtime - mBaseIrqTime);
            mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
            mRelIdleTime = (int)(idletime - mBaseIdleTime);
 
            if (DEBUG) {
                Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
                      + " S:" + sysCpu[2] + " I:" + sysCpu[3]
                      + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
                      + " O:" + sysCpu[6]);
                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
            }
 
            mBaseUserTime = usertime;
            mBaseSystemTime = systemtime;
            mBaseIoWaitTime = iowaittime;
            mBaseIrqTime = irqtime;
            mBaseSoftIrqTime = softirqtime;
            mBaseIdleTime = idletime;
        }
         // 讀取全部/proc/[pid]/文件夾中的進行信息
        mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
 
        // 讀取/proc/loadavg中的平均負載
        final float[] loadAverages = mLoadAverageData;
        if (Process.readProcFile("/proc/loadavg", LOAD_AVERAGE_FORMAT,
                null, null, loadAverages)) {
            float load1 = loadAverages[0];
            float load5 = loadAverages[1];
            float load15 = loadAverages[2];
            if (load1 != mLoad1 || load5 != mLoad5 || load15 != mLoad15) {
                mLoad1 = load1;
                mLoad5 = load5;
                mLoad15 = load15;
                onLoadChanged(load1, load5, load15);
            }
        }
 
        if (DEBUG) Slog.i(TAG, "*** TIME TO COLLECT STATS: "
                + (SystemClock.uptimeMillis()-mCurrentSampleTime));
 
        mWorkingProcsSorted = false;
        mFirst = false;
    }




再來看下讀取進行信息的函數

    private int[] collectStats(String statsFile, int parentPid, boolean first,
            int[] curPids, ArrayList<Stats> allProcs) {
        //獲取所有PID
        int[] pids = Process.getPids(statsFile, curPids);
        int NP = (pids == null) ? 0 : pids.length;
        int NS = allProcs.size();
        int curStatsIndex = 0;
        //迭代PID,建立或更新PID對應的Stats對象
        for (int i=0; i<NP; i++) {
            int pid = pids[i];
            if (pid < 0) {
                NP = pid;
                break;
            }
            Stats st = curStatsIndex < NS ? allProcs.get(curStatsIndex) : null;
             // Stats對象已經存在,更新
            if (st != null && st.pid == pid) {
                // Update an existing process...
                st.added = false;
                st.working = false;
                curStatsIndex++;
                if (DEBUG) Slog.v(TAG, "Existing "
                        + (parentPid < 0 ? "process" : "thread")
                        + " pid " + pid + ": " + st);
 
                if (st.interesting) {
                    final long uptime = SystemClock.uptimeMillis();
 
                    final long[] procStats = mProcessStatsData;
                    // 讀取/proc/[pid]/stat文件中的信息至procStats
                    if (!Process.readProcFile(st.statFile.toString(),
                            PROCESS_STATS_FORMAT, null, procStats, null)) {
                        continue;
                    }
                     
                    final long minfaults = procStats[PROCESS_STAT_MINOR_FAULTS];
                    final long majfaults = procStats[PROCESS_STAT_MAJOR_FAULTS];
                    final long utime = procStats[PROCESS_STAT_UTIME];
                    final long stime = procStats[PROCESS_STAT_STIME];
                     // cpu用戶時間系統時間沒變化,設置Stats的active爲false
                    if (utime == st.base_utime && stime == st.base_stime) {
                        st.rel_utime = 0;
                        st.rel_stime = 0;
                        st.rel_minfaults = 0;
                        st.rel_majfaults = 0;
                        if (st.active) {
                            st.active = false;
                        }
                        continue;
                    }
 
                    if (!st.active) {
                        st.active = true;
                    }
 
                    if (parentPid < 0) {
                        // 從/proc/[pid]/cmdline中讀取進程名
                        getName(st, st.cmdlineFile);
                        if (st.threadStats != null) {
                            // 若是須要讀取線程信息,怎從/proc/[pid]/task/中讀取所有線程的信息
                            mCurThreadPids = collectStats(st.threadsDir, pid, false,
                                    mCurThreadPids, st.threadStats);
                        }
                    }
 
                    if (DEBUG) Slog.v("Load", "Stats changed " + st.name + " pid=" + st.pid
                            + " utime=" + utime + "-" + st.base_utime
                            + " stime=" + stime + "-" + st.base_stime
                            + " minfaults=" + minfaults + "-" + st.base_minfaults
                            + " majfaults=" + majfaults + "-" + st.base_majfaults);
                     // 設置Stats的值
                    st.rel_uptime = uptime - st.base_uptime;
                    st.base_uptime = uptime;
                    st.rel_utime = (int)(utime - st.base_utime);
                    st.rel_stime = (int)(stime - st.base_stime);
                    st.base_utime = utime;
                    st.base_stime = stime;
                    st.rel_minfaults = (int)(minfaults - st.base_minfaults);
                    st.rel_majfaults = (int)(majfaults - st.base_majfaults);
                    st.base_minfaults = minfaults;
                    st.base_majfaults = majfaults;
                    st.working = true;
                }
 
                continue;
            }
             // Stats對象不存在,建立
            if (st == null || st.pid > pid) {
                ......
                // 建立的流程和更新差很少
                continue;
            }
                 
            ......
            continue;
        }
         ......
         
        return pids;
    }





咱們能夠很方便的使用這個類,來進行cpu負荷和進程時間的監控。Android系統在SystemUI中有一個服務,就使用了這個類。

咱們看SystemUI的Manifest文件,能夠找到一個叫LoadAverageService的服務,它就是使用了ProcessStats獲取cpu和進程信息,並把他們顯示出來。

最後,在看下如何使用LoadAverageService這個服務

能夠在adb shell中直接運行am startservice -n com.android.systemui/.LoadAverageService

或者用【設置】->【開發者選項】->【顯示cpu使用狀況】打開服務

咱們在開發應用的時候,能夠開啓這個選項,時時跟蹤系統的cpu佔用狀況,真的是很方便啊!!!

相關文章
相關標籤/搜索