Android CPU使用率:top和dump cpuinfo的不同

CPU是系统非常重要的资源,在Android中,查看CPU使用情况,可以使用top命令和dump cpuinfo。我记得很久以前,就发现这两者存在不同,初步猜测应该是算法上存在差异。最近需要采集应用CPU的使用率,看了一下两种CPU的计算方法。

1、top

top是比较经典的CPU计算方法,top的代码在androidm/system/core/toolbox/top.c下面,输出process的cpu使用率在print_procs里面:

<code class="hljs haskell has-numbering"><span class="hljs-title">static</span> void print_procs(void) {
...
    for (i = <span class="hljs-number">0</span>; i < num_new_procs; i++) {
        <span class="hljs-keyword">if</span> (new_procs[i]) {
            old_proc = find_old_proc(new_procs[i]->pid, new_procs[i]->tid);
            <span class="hljs-keyword">if</span> (old_proc) {
                new_procs[i]->delta_utime = new_procs[i]->utime - old_proc->utime;
                new_procs[i]->delta_stime = new_procs[i]->stime - old_proc->stime;
            } <span class="hljs-keyword">else</span> {
                new_procs[i]->delta_utime = <span class="hljs-number">0</span>;
                new_procs[i]->delta_stime = <span class="hljs-number">0</span>;
            }
            new_procs[i]->delta_time = new_procs[i]->delta_utime + new_procs[i]->delta_stime;
        }
    }

    total_delta_time = (new_cpu.utime + new_cpu.ntime + new_cpu.stime + new_cpu.itime
                        + new_cpu.iowtime + new_cpu.irqtime + new_cpu.sirqtime)
                     - (old_cpu.utime + old_cpu.ntime + old_cpu.stime + old_cpu.itime
                        + old_cpu.iowtime + old_cpu.irqtime + old_cpu.sirqtime);

 ...

<span class="hljs-title">if</span> (!threads) {
            printf(<span class="hljs-string">"%5d %2d %3"</span> <span class="hljs-type">PRIu64</span> <span class="hljs-string">"%% %c %5d %6"</span> <span class="hljs-type">PRIu64</span> <span class="hljs-string">"K %6"</span> <span class="hljs-type">PRIu64</span> <span class="hljs-string">"K %3s %-8.8s %s\n"</span>,
                   <span class="hljs-keyword">proc</span>->pid, <span class="hljs-keyword">proc</span>->prs, <span class="hljs-keyword">proc</span>->delta_time * <span class="hljs-number">100</span> / total_delta_time, <span class="hljs-keyword">proc</span>->state, <span class="hljs-keyword">proc</span>->num_threads,
                   <span class="hljs-keyword">proc</span>->vss / <span class="hljs-number">1024</span>, <span class="hljs-keyword">proc</span>->rss * getpagesize() / <span class="hljs-number">1024</span>, <span class="hljs-keyword">proc</span>->policy, user_str, <span class="hljs-keyword">proc</span>->name[<span class="hljs-number">0</span>] != <span class="hljs-number">0</span> ? <span class="hljs-keyword">proc</span>->name : <span class="hljs-keyword">proc</span>->tname);
        } <span class="hljs-keyword">else</span> {
            printf(<span class="hljs-string">"%5d %5d %2d %3"</span> <span class="hljs-type">PRIu64</span> <span class="hljs-string">"%% %c %6"</span> <span class="hljs-type">PRIu64</span> <span class="hljs-string">"K %6"</span> <span class="hljs-type">PRIu64</span> <span class="hljs-string">"K %3s %-8.8s %-15s %s\n"</span>,
                   <span class="hljs-keyword">proc</span>->pid, <span class="hljs-keyword">proc</span>->tid, <span class="hljs-keyword">proc</span>->prs, <span class="hljs-keyword">proc</span>->delta_time * <span class="hljs-number">100</span> / total_delta_time, <span class="hljs-keyword">proc</span>->state,
                   <span class="hljs-keyword">proc</span>->vss / <span class="hljs-number">1024</span>, <span class="hljs-keyword">proc</span>->rss * getpagesize() / <span class="hljs-number">1024</span>, <span class="hljs-keyword">proc</span>->policy, user_str, <span class="hljs-keyword">proc</span>->tname, <span class="hljs-keyword">proc</span>->name);
        }
...
}
</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li><li>33</li><li>34</li><li>35</li></ul>

CPU的计算是proc->delta_time * 100 / total_delta_time。

先看total_delta_time由:

<code class="hljs avrasm has-numbering">    total_delta_time = (new_cpu<span class="hljs-preprocessor">.utime</span> + new_cpu<span class="hljs-preprocessor">.ntime</span> + new_cpu<span class="hljs-preprocessor">.stime</span> + new_cpu<span class="hljs-preprocessor">.itime</span>
                        + new_cpu<span class="hljs-preprocessor">.iowtime</span> + new_cpu<span class="hljs-preprocessor">.irqtime</span> + new_cpu<span class="hljs-preprocessor">.sirqtime</span>)
                     - (old_cpu<span class="hljs-preprocessor">.utime</span> + old_cpu<span class="hljs-preprocessor">.ntime</span> + old_cpu<span class="hljs-preprocessor">.stime</span> + old_cpu<span class="hljs-preprocessor">.itime</span>
                        + old_cpu<span class="hljs-preprocessor">.iowtime</span> + old_cpu<span class="hljs-preprocessor">.irqtime</span> + old_cpu<span class="hljs-preprocessor">.sirqtime</span>)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

而这些变量的值,是在read_procs通过读取/proc/stat的jiffies得到:

<code class="hljs perl has-numbering">static void read_procs(void) {
...
    proc_dir = <span class="hljs-keyword">opendir</span>(<span class="hljs-string">"/proc"</span>);
    <span class="hljs-keyword">if</span> (!proc_dir) <span class="hljs-keyword">die</span>(<span class="hljs-string">"Could not open /proc.\n"</span>);

    new_procs = calloc(INIT_PROCS * (threads ? THREAD_MULT : <span class="hljs-number">1</span>), sizeof(struct proc_info <span class="hljs-variable">*)</span>);
    num_new_procs = INIT_PROCS * (threads ? THREAD_MULT : <span class="hljs-number">1</span>);

    file = fopen(<span class="hljs-string">"/proc/stat"</span>, <span class="hljs-string">"r"</span>);
    <span class="hljs-keyword">if</span> (!file) <span class="hljs-keyword">die</span>(<span class="hljs-string">"Could not open /proc/stat.\n"</span>);
    fscanf(file, <span class="hljs-string">"cpu  <span class="hljs-variable">%lu</span> <span class="hljs-variable">%lu</span> <span class="hljs-variable">%lu</span> <span class="hljs-variable">%lu</span> <span class="hljs-variable">%lu</span> <span class="hljs-variable">%lu</span> <span class="hljs-variable">%lu</span>"</span>, &new_cpu.<span class="hljs-keyword">utime</span>, &new_cpu.ntime, &new_cpu.stime,
            &new_cpu.itime, &new_cpu.iowtime, &new_cpu.irqtime, &new_cpu.sirqtime);
    fclose(file);</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li></ul>

而proc->delta_time是两次读取/proc/pid/stat相减得到:

<code class="hljs haskell has-numbering"><span class="hljs-title">static</span> int read_stat(char *filename, struct proc_info *<span class="hljs-keyword">proc</span>) {
...
  /* <span class="hljs-type">Scan</span> rest <span class="hljs-keyword">of</span> string. */
    sscanf(close_paren + <span class="hljs-number">1</span>,
           <span class="hljs-string">" %c "</span> <span class="hljs-string">"%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "</span>
           <span class="hljs-string">"%"</span> <span class="hljs-type">SCNu64</span>
           <span class="hljs-string">"%"</span> <span class="hljs-type">SCNu64</span> <span class="hljs-string">"%*d %*d %*d %*d %*d %*d %*d "</span>
           <span class="hljs-string">"%"</span> <span class="hljs-type">SCNu64</span>
           <span class="hljs-string">"%"</span> <span class="hljs-type">SCNu64</span> <span class="hljs-string">"%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d "</span>
           <span class="hljs-string">"%d"</span>,
           &<span class="hljs-keyword">proc</span>->state,
           &<span class="hljs-keyword">proc</span>->utime,
           &<span class="hljs-keyword">proc</span>->stime,
           &<span class="hljs-keyword">proc</span>->vss,
           &<span class="hljs-keyword">proc</span>->rss,
           &<span class="hljs-keyword">proc</span>->prs);

    return <span class="hljs-number">0</span>;
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li></ul>

可见,top是一段时间内,计算process的cpu jiffies与总的cpu jiffies差值得到。

2、dump cpuinfo

dump cpuinfo是Android特有的命令(我一直都android的各种dump、trace非常感兴趣,快玩物丧志了。。。)。dump cpuinfo命令的实现在androidm/frameworks/base/core/java/com/android/internal/os/ProcessCpuTracker.java类里面,方法是printCurrentState:

<code class="hljs avrasm has-numbering">final public String printCurrentState(long now) {
...
        int N = mWorkingProcs<span class="hljs-preprocessor">.size</span>()<span class="hljs-comment">;</span>
        for (int i=<span class="hljs-number">0</span><span class="hljs-comment">; i<N; i++) {</span>
            Stats <span class="hljs-keyword">st</span> = mWorkingProcs<span class="hljs-preprocessor">.get</span>(i)<span class="hljs-comment">;</span>
            printProcessCPU(pw, <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.added</span> ? <span class="hljs-string">" +"</span> : (<span class="hljs-keyword">st</span><span class="hljs-preprocessor">.removed</span> ? <span class="hljs-string">" -"</span>: <span class="hljs-string">"  "</span>),
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.pid</span>, <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.name</span>, (int)<span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_uptime,
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_utime, <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_stime, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_minfaults, <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_majfaults)<span class="hljs-comment">;</span>
            if (!<span class="hljs-keyword">st</span><span class="hljs-preprocessor">.removed</span> && <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.workingThreads</span> != null) {
                int M = <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.workingThreads</span><span class="hljs-preprocessor">.size</span>()<span class="hljs-comment">;</span>
                for (int j=<span class="hljs-number">0</span><span class="hljs-comment">; j<M; j++) {</span>
                    Stats <span class="hljs-keyword">tst</span> = <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.workingThreads</span><span class="hljs-preprocessor">.get</span>(j)<span class="hljs-comment">;</span>
                    printProcessCPU(pw,
                            <span class="hljs-keyword">tst</span><span class="hljs-preprocessor">.added</span> ? <span class="hljs-string">"   +"</span> : (<span class="hljs-keyword">tst</span><span class="hljs-preprocessor">.removed</span> ? <span class="hljs-string">"   -"</span>: <span class="hljs-string">"    "</span>),
                            <span class="hljs-keyword">tst</span><span class="hljs-preprocessor">.pid</span>, <span class="hljs-keyword">tst</span><span class="hljs-preprocessor">.name</span>, (int)<span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_uptime,
                            <span class="hljs-keyword">tst</span><span class="hljs-preprocessor">.rel</span>_utime, <span class="hljs-keyword">tst</span><span class="hljs-preprocessor">.rel</span>_stime, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>)<span class="hljs-comment">;</span>
                }
            }
        }

...
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li></ul>

而printProcessCPU输出process CPU的使用情况:

<code class="hljs cs has-numbering"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">printProcessCPU</span>(PrintWriter pw, String prefix, <span class="hljs-keyword">int</span> pid, String label,
            <span class="hljs-keyword">int</span> totalTime, <span class="hljs-keyword">int</span> user, <span class="hljs-keyword">int</span> system, <span class="hljs-keyword">int</span> iowait, <span class="hljs-keyword">int</span> irq, <span class="hljs-keyword">int</span> softIrq,
            <span class="hljs-keyword">int</span> minFaults, <span class="hljs-keyword">int</span> majFaults) {
        pw.print(prefix);
        <span class="hljs-keyword">if</span> (totalTime == <span class="hljs-number">0</span>) totalTime = <span class="hljs-number">1</span>;
        printRatio(pw, user+system+iowait+irq+softIrq, totalTime);
...
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li></ul>

user+system+iowait+irq+softIrq 比totalTime。
看下st个变量的赋值,在collectStats里面:

<code class="hljs avrasm has-numbering">private int[] collectStats(String statsFile, int parentPid, boolean first,
            int[] curPids, ArrayList<Stats> allProcs) {

        int[] pids = Process<span class="hljs-preprocessor">.getPids</span>(statsFile, curPids)<span class="hljs-comment">;</span>
...
 final long uptime = SystemClock<span class="hljs-preprocessor">.uptimeMillis</span>()<span class="hljs-comment">;</span>
   final long[] procStats = mProcessStatsData<span class="hljs-comment">;</span>
                    if (!Process<span class="hljs-preprocessor">.readProcFile</span>(<span class="hljs-keyword">st</span><span class="hljs-preprocessor">.statFile</span><span class="hljs-preprocessor">.toString</span>(),
                            PROCESS_STATS_FORMAT, null, procStats, null)) {
                        continue<span class="hljs-comment">;</span>
                    }

...
                    if (DEBUG) Slog<span class="hljs-preprocessor">.v</span>(<span class="hljs-string">"Load"</span>, <span class="hljs-string">"Stats changed "</span> + <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.name</span> + <span class="hljs-string">" pid="</span> + <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.pid</span>
                            + <span class="hljs-string">" utime="</span> + utime + <span class="hljs-string">"-"</span> + <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_utime
                            + <span class="hljs-string">" stime="</span> + stime + <span class="hljs-string">"-"</span> + <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_stime
                            + <span class="hljs-string">" minfaults="</span> + minfaults + <span class="hljs-string">"-"</span> + <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_minfaults
                            + <span class="hljs-string">" majfaults="</span> + majfaults + <span class="hljs-string">"-"</span> + <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_majfaults)<span class="hljs-comment">;</span>

                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_uptime = uptime - <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_uptime<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_uptime = uptime<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_utime = (int)(utime - <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_utime)<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_stime = (int)(stime - <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_stime)<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_utime = utime<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_stime = stime<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_minfaults = (int)(minfaults - <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_minfaults)<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.rel</span>_majfaults = (int)(majfaults - <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_majfaults)<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_minfaults = minfaults<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.base</span>_majfaults = majfaults<span class="hljs-comment">;</span>
                    <span class="hljs-keyword">st</span><span class="hljs-preprocessor">.working</span> = true<span class="hljs-comment">;</span>
...
}</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li><li>15</li><li>16</li><li>17</li><li>18</li><li>19</li><li>20</li><li>21</li><li>22</li><li>23</li><li>24</li><li>25</li><li>26</li><li>27</li><li>28</li><li>29</li><li>30</li><li>31</li><li>32</li></ul>

st.rel_utime 和 st.rel_stime还是通过读/proc/pid/stat相减得到,而st.rel_uptime却是通过 SystemClock.uptimeMillis()差值,并不是跟top一样,通过得到总CPU jiffies。

看到这,也就能明白,top跟dump cpuinfo的区别在于:top分母有的是总测CPU jiffies,而dump cpuinfo是uptime,是时间,而并非jiffies,也能解释为什么top出来的cpu,大部分时间会比dump cpuinfo的原因。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值