java得到机器cpu使用率的计算方法深入理解

文章目录


之前写熔断功能,需要获取机器的cpu使用率
从/proc文件系统获取cpu使用情况: cat /proc/stat
输出解释:

idle (422145968) 从系统启动开始累计到当前时刻,除硬盘IO等待时间以外其它等待时间(单位:jiffies)

得到:
CPU利用率 = 1- (idle2-idle1)/(cpu2-cpu1)

这里的idle1、idle2是从 开机到现在 的cpu空闲时间,cpu1、cpu2是从开机到现在的总的时间

一个同事说,这样违背了需求,不是瞬时的cpu的值

举个栗子
java得到机器cpu使用率的计算方法深入理解_第1张图片

假如我凌晨0点开始,现在是24小时后的凌晨0点,在这一天中,0点到1点我都开吭哧吭哧的干活,早早干完了,1点到24点,坐着嗑瓜子,如果算瞬时的cpu使用率,岂不是要 1/24 ,可是这能表示我当前的cpu吗?

注意cpu的单位是时间

所以就出现了上面的公式

CPU利用率 = 1- (idle2-idle1)/(cpu2-cpu1)

而我们两次采集的时间间隔尽可能的小,就确保了尽可能的求瞬时的值,但是不能到达真正的瞬时。
其实按照正常的思维,用开始到现在使用的时间除以开始到现在总的时间,看似是瞬时的,实际上可以吧开始那个瞬间看做是一次采集,当前时间是一次采集,即相当于将上面的公式的采集时间拉长了,本质上没什么区别,反而精度下降了不是一点点。
通过将时间间隔缩小确实能够达到目的,但是不能小于Jiffies,什么是Jiffies,看下面我摘录的一段话:

在Linux的内核中,有一个全 局变量:Jiffies。
Jiffies代表时间。它的单位随硬件平台的不同而不同。系统里定义了一个常数HZ,代表每秒种最小时间间隔的数目。这样jiffies的单位就是
1/HZ。Intel平台jiffies的单位是1/100秒,这就是系统所能分辨的最小时间间隔了。每个CPU时间片,Jiffies都要加1。
CPU的利用率就是用执行用户态+系统态的Jiffies除以总的Jifffies来表示。

在Linux内核中,每个进程都会被分配一个固定的时间片,默认为10ms,在这10ms中,该进程享有cpu的所有权。10ms看上去很短,但以2.6GHz的Intel处理器为例,10ms能够处理5000w条指令,对于绝大多数的应用这已经足够长了。如果该进程用完了10ms,或者有其他优先级高的进程发出请求,系统会触发一个中断,内核重新接管cpu,内核分配cpu给其他进程。10ms的分片让用户,也就是我们觉得我们的系统运转非常流畅,尽管我们可能同时开了很多的应用。

Jiffies
我们或许会对10ms的分片感到疑惑,为什么是10ms?可不可以是其他值?答案是肯定的,但无论它被设定为多少,它只是指示了内核以一个怎样的时间间隔重新接管cpu。内核接管了cpu后,可能会干一些琐碎的事,其中有一件就是累加一个变量,也就是Jiffies。这样一来,每隔10ms,Jiffies就要加1,Jiffies指示了从开机以来经过了多少个10ms.HZ
和我们平常所知的Hz不一样,这里的HZ是Linux系统定义的一个常数,代表了每秒钟最小时间间隔的数目,它有默认值为100。这样Jiffies的单位就是1/HZ,即1/100秒,这是系统所能分辨的最小时间间隔了。

参考:https://www.2cto.com/kf/201708/666530.html

当然还有很多java代码获取机器cpu使用率的方式,没必要纠结于这一种。

java代码

/**
 * 采集CPU使用率
 */
public class CpuUsage extends ResourceUsage {

    private static Logger log = Logger.getLogger(CpuUsage.class);
    private static CpuUsage INSTANCE = new CpuUsage();
    
    private CpuUsage(){
    
    }
    
    public static CpuUsage getInstance(){
        return INSTANCE;
    }
    
    /**
     * Purpose:采集CPU使用率
     * @param args
     * @return float,CPU使用率,小于1
     */
    @Override
    public float get() {
        log.info("开始收集cpu使用率");
        float cpuUsage = 0;
        Process pro1,pro2;
        Runtime r = Runtime.getRuntime();
        try {
            String command = "cat /proc/stat";
            //第一次采集CPU时间
            long startTime = System.currentTimeMillis();
            pro1 = r.exec(command);
            BufferedReader in1 = new BufferedReader(new InputStreamReader(pro1.getInputStream()));
            String line = null;
            long idleCpuTime1 = 0, totalCpuTime1 = 0;    //分别为系统启动后空闲的CPU时间和总的CPU时间
            while((line=in1.readLine()) != null){    
                if(line.startsWith("cpu")){
                    line = line.trim();
                    log.info(line);
                    String[] temp = line.split("\\s+"); 
                    idleCpuTime1 = Long.parseLong(temp[4]);
                    for(String s : temp){
                        if(!s.equals("cpu")){
                            totalCpuTime1 += Long.parseLong(s);
                        }
                    }    
                    log.info("IdleCpuTime: " + idleCpuTime1 + ", " + "TotalCpuTime" + totalCpuTime1);
                    break;
                }                        
            }    
            in1.close();
            pro1.destroy();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                StringWriter sw = new StringWriter();
                e.printStackTrace(new PrintWriter(sw));
                log.error("CpuUsage休眠时发生InterruptedException. " + e.getMessage());
                log.error(sw.toString());
            }
            //第二次采集CPU时间
            long endTime = System.currentTimeMillis();
            pro2 = r.exec(command);
            BufferedReader in2 = new BufferedReader(new InputStreamReader(pro2.getInputStream()));
            long idleCpuTime2 = 0, totalCpuTime2 = 0;    //分别为系统启动后空闲的CPU时间和总的CPU时间
            while((line=in2.readLine()) != null){    
                if(line.startsWith("cpu")){
                    line = line.trim();
                    log.info(line);
                    String[] temp = line.split("\\s+"); 
                    idleCpuTime2 = Long.parseLong(temp[4]);
                    for(String s : temp){
                        if(!s.equals("cpu")){
                            totalCpuTime2 += Long.parseLong(s);
                        }
                    }
                    log.info("IdleCpuTime: " + idleCpuTime2 + ", " + "TotalCpuTime" + totalCpuTime2);
                    break;    
                }                                
            }
            if(idleCpuTime1 != 0 && totalCpuTime1 !=0 && idleCpuTime2 != 0 && totalCpuTime2 !=0){
                cpuUsage = 1 - (float)(idleCpuTime2 - idleCpuTime1)/(float)(totalCpuTime2 - totalCpuTime1);
                log.info("本节点CPU使用率为: " + cpuUsage);
            }                
            in2.close();
            pro2.destroy();
        } catch (IOException e) {
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            log.error("CpuUsage发生InstantiationException. " + e.getMessage());
            log.error(sw.toString());
        }    
        return cpuUsage;
    }

    /**
     * @param args
     * @throws InterruptedException 
     */
    public static void main(String[] args) throws InterruptedException {
        while(true){
            System.out.println(CpuUsage.getInstance().get());
            Thread.sleep(5000);        
        }
    }
}</span>

转载过一篇文章:https://blog.csdn.net/dataiyangu/article/details/83988775

你可能感兴趣的:(JAVA❤️,Work,problems❤️,Basis❤️)