您的位置:首页 > 产品设计 > UI/UE

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

2016-07-06 13:49 543 查看
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的原因。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: