我想知道如何计算进程的总CPU使用率。
如果我执行命令 cat /proc/pid/stat
,我认为相关字段是(来自lindevdoc.org):
- 在Jiffies中测量的用户代码CPU时间
- 在Jiffies中测量的内核代码CPU时间
- 包括子级的用户代码CPU时间
- 包括子级的内核代码CPU时间
所以,总时间是字段14到17的总和吗?
我想知道如何计算进程的总CPU使用率。
如果我执行命令 cat /proc/pid/stat
,我认为相关字段是(来自lindevdoc.org):
所以,总时间是字段14到17的总和吗?
要计算特定进程的CPU使用率,您需要以下内容:
/proc/uptime
#1
系统的运行时间(秒)/proc/[PID]/stat
#14
utime
- 用户代码中使用的CPU时间,以时钟滴答为单位#15
stime
- 内核代码中使用的CPU时间,以时钟滴答为单位#16
cutime
- 等待子进程在用户代码中使用的CPU时间(以时钟滴答为单位)#17
cstime
- 等待子进程在内核代码中使用的CPU时间(以时钟滴答为单位)#22
starttime
- 进程启动时的时间,以时钟滴答为单位getconf CLK_TCK
返回时钟滴答数。sysconf(_SC_CLK_TCK)
C函数调用返回赫兹值。首先我们确定了进程的总时间:
total_time = utime + stime
我们还需要决定是否要包括子进程的时间。如果要包括,那么我们将这些值添加到 total_time
中:
total_time = total_time + cutime + cstime
接下来我们获取自进程启动以来经过的总时间,以秒为单位:
seconds = uptime - (starttime / Hertz)
最后,我们计算CPU使用率百分比:
cpu_usage = 100 * ((total_time / Hertz) / seconds)
是的,你可以这么说。你可以使用以下公式将这些值转换为秒:
sec = jiffies / HZ ; here - HZ = number of ticks per second
HZ值是可配置的 - 在内核配置时间完成。
这是一个我用BASH编写的简单解决方案。它是一个基于procfs的Linux/Unix系统监视器和进程管理器,类似于"top"或"ps"。有两个版本,一个是简单的单色版(快速),另一个是彩色版(略慢,但特别适合监控进程状态)。我按CPU使用率排序。
https://github.com/AraKhachatryan/top
获取CPU使用率的utime、stime、cutime、cstime、starttime参数从/proc/[pid]/stat文件中获取。
state、ppid、priority、nice、num_threads参数也从/proc/[pid]/stat文件中获取。
获取内存使用率的resident和data_and_stack参数从/proc/[pid]/statm文件中获取。
function my_ps
{
pid_array=`ls /proc | grep -E '^[0-9]+$'`
clock_ticks=$(getconf CLK_TCK)
total_memory=$( grep -Po '(?<=MemTotal:\s{8})(\d+)' /proc/meminfo )
cat /dev/null > .data.ps
for pid in $pid_array
do
if [ -r /proc/$pid/stat ]
then
stat_array=( `sed -E 's/(\([^\s)]+)\s([^)]+\))/\1_\2/g' /proc/$pid/stat` )
uptime_array=( `cat /proc/uptime` )
statm_array=( `cat /proc/$pid/statm` )
comm=( `grep -Po '^[^\s\/]+' /proc/$pid/comm` )
user_id=$( grep -Po '(?<=Uid:\s)(\d+)' /proc/$pid/status )
user=$( id -nu $user_id )
uptime=${uptime_array[0]}
state=${stat_array[2]}
ppid=${stat_array[3]}
priority=${stat_array[17]}
nice=${stat_array[18]}
utime=${stat_array[13]}
stime=${stat_array[14]}
cutime=${stat_array[15]}
cstime=${stat_array[16]}
num_threads=${stat_array[19]}
starttime=${stat_array[21]}
total_time=$(( $utime + $stime ))
#add $cstime - CPU time spent in user and kernel code ( can olso add $cutime - CPU time spent in user code )
total_time=$(( $total_time + $cstime ))
seconds=$( awk 'BEGIN {print ( '$uptime' - ('$starttime' / '$clock_ticks') )}' )
cpu_usage=$( awk 'BEGIN {print ( 100 * (('$total_time' / '$clock_ticks') / '$seconds') )}' )
resident=${statm_array[1]}
data_and_stack=${statm_array[5]}
memory_usage=$( awk 'BEGIN {print( (('$resident' + '$data_and_stack' ) * 100) / '$total_memory' )}' )
printf "%-6d %-6d %-10s %-4d %-5d %-4s %-4u %-7.2f %-7.2f %-18s\n" $pid $ppid $user $priority $nice $state $num_threads $memory_usage $cpu_usage $comm >> .data.ps
fi
done
clear
printf "\e[30;107m%-6s %-6s %-10s %-4s %-3s %-6s %-4s %-7s %-7s %-18s\e[0m\n" "PID" "PPID" "USER" "PR" "NI" "STATE" "THR" "%MEM" "%CPU" "COMMAND"
sort -nr -k9 .data.ps | head -$1
read_options
}
这里是我获取应用程序CPU使用率的另一种方法。我在Android上完成了这个操作,它会进行内核顶部调用,并使用top返回的内容获取您的应用程序PID的CPU使用率。
public void myWonderfulApp()
{
// Some wonderfully written code here
Integer lMyProcessID = android.os.Process.myPid();
int lMyCPUUsage = getAppCPUUsage( lMyProcessID );
// More magic
}
// Alternate way that I switched to. I found the first version was slower
// this version only returns a single line for the app, so far less parsing
// and processing.
public static float getTotalCPUUsage2()
{
try
{
// read global stats file for total CPU
BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"));
String[] sa = reader.readLine().split("[ ]+", 9);
long work = Long.parseLong(sa[1]) + Long.parseLong(sa[2]) + Long.parseLong(sa[3]);
long total = work + Long.parseLong(sa[4]) + Long.parseLong(sa[5]) + Long.parseLong(sa[6]) + Long.parseLong(sa[7]);
reader.close();
// calculate and convert to percentage
return restrictPercentage(work * 100 / (float) total);
}
catch (Exception ex)
{
Logger.e(Constants.TAG, "Unable to get Total CPU usage");
}
// if there was an issue, just return 0
return 0;
}
// This is an alternate way, but it takes the entire output of
// top, so there is a fair bit of parsing.
public static int getAppCPUUsage( Integer aAppPID)
{
int lReturn = 0;
// make sure a valid pid was passed
if ( null == aAppPID && aAppPID > 0)
{
return lReturn;
}
try
{
// Make a call to top so we have all the processes CPU
Process lTopProcess = Runtime.getRuntime().exec("top");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(lTopProcess.getInputStream()));
String lLine;
// While we have stuff to read and we have not found our PID, process the lines
while ( (lLine = bufferedReader.readLine()) != null )
{
// Split on 4, the CPU % is the 3rd field .
// NOTE: We trim because sometimes we had the first field in the split be a "".
String[] lSplit = lLine.trim().split("[ ]+", 4);
// Don't even bother if we don't have at least the 4
if ( lSplit.length > 3 )
{
// Make sure we can handle if we can't parse the int
try
{
// On the line that is our process, field 0 is a PID
Integer lCurrentPID = Integer.parseInt(lSplit[0]);
// Did we find our process?
if (aAppPID.equals(lCurrentPID))
{
// This is us, strip off the % and return it
String lCPU = lSplit[2].replace("%", "");
lReturn = Integer.parseInt(lCPU);
break;
}
}
catch( NumberFormatException e )
{
// No op. We expect this when it's not a PID line
}
}
}
bufferedReader.close();
lTopProcess.destroy(); // Cleanup the process, otherwise you make a nice hand warmer out of your device
}
catch( IOException ex )
{
// Log bad stuff happened
}
catch (Exception ex)
{
// Log bad stuff happened
}
// if there was an issue, just return 0
return lReturn;
}
starttime(22)
,那么 s2 和 s1 将是相同的。 starttime
是进程启动时刻,因此该值在进程生命周期中保持不变。 - Vilhelm Gray这就是你要找的内容:
//USER_HZ detection, from openssl code
#ifndef HZ
# if defined(_SC_CLK_TCK) \
&& (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000)
# define HZ ((double)sysconf(_SC_CLK_TCK))
# else
# ifndef CLK_TCK
# ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
# define HZ 100.0
# else /* _BSD_CLK_TCK_ */
# define HZ ((double)_BSD_CLK_TCK_)
# endif
# else /* CLK_TCK */
# define HZ ((double)CLK_TCK)
# endif
# endif
#endif
这段代码实际上来自于 cpulimit,但使用了 OpenSSL 的片段。
HZ
值,但在这种特殊情况下,你实际上需要的是USER_HZ
值。 - Vilhelm Gray/proc/self/stat
的utime参数是0
。我怀疑你的困惑来自于/proc/self/stat
的行为,它是指当前运行的进程的链接——即执行cat /proc/self/stat
,但是它还不存在足够长的时间,使得utime大于0
。 - Vilhelm Grayuptime
是/proc/uptime
的第一个参数。我提到/proc/uptime
的第二个参数是为了说明如何计算整个系统的总 CPU 使用率,而不是单个进程;由于我们只关心单个进程的 CPU 使用率,因此在方程式中未使用第二个参数。 - Vilhelm Gray