(三)获取linux内核的系统信息

这一章,使用qt来获取linux内核的系统信息并显示到界面上。这里的系统信息包括CPU的使用率,CPU的温度,内存信息以及硬盘信息。

 

  • CPU温度

  • NanoPI Fire3的开发团队为系统提供了读取CPU温度的接口,一个设备文件,使用命令查看CPU温度

  • cat /sys/class/thermal/thermal_zone0/temp

  • 文件里面的值为65000,这里的值除1000就是实际的温度值,65000/1000=65。说明现在的CPU温度为65度。

    知道了设备文件,那么就可以开始写程序了。

  • //获取CPU温度
    QString temp_file_name("/sys/class/thermal/thermal_zone0/temp");
    file_info.setFile(temp_file_name);
    if(file_info.isFile())
    {
        QFile temp_file(temp_file_name);
        if(temp_file.open(QFile::ReadOnly))
        {
            QString cpu_temp_str = temp_file.readAll();
            cpu_info_data.temp = static_cast<double>((double)(cpu_temp_str.toDouble()) / 1000.0);
    
            qDebug() << QString("cpu temp : %1°C").arg(QString::number(cpu_info_data.temp,'f',2));
            temp_file.close();
        }
    }
    else
    {
        qDebug() << "No file named : " << temp_file_name;
        cpu_info_data.temp = 0;
    }
    

    先判断文件是否存在,如果不存在那么直接返回。如果存在则使用QFile进行信息读取。然后把信息转换为double型进行存储。

    为了方便的数据处理,我建立了一个结构体

  • // system info struct
    struct CpuInfo_data
    {
        long long total;
        long long usr;
        long long nic;
        long long sys;
        long long idle;
        long long iowait;
        long long irq;
        long long softirq;
        long long steal;
        double rate;
        double temp;
    };
    

    其中temp是温度的值,其他的为CPU使用率所使用

  • CPU使用率

CPU使用率如何获得,我们都知道linux中有一个top命令可以查看CPU的信息

输入top命令,出来的最上面5行便是系统信息,我们关心的是3,4行,CPU使用率和内存信息。

CPU这一行的id属性的意思是剩余的CPU资源,总共是100,所以可以算出已经使用的CPU资源为100-92.5

大家都知道linux中的所有命令都来自于busybox的支持,如果不知道,可以暂停一下,去了解一下busybox是什么。

所以我们可以通过busybox中top命令的实现源码来判断这里的信息时如何读取出来的。

去busybox官网下载源码(如果打不开网站,可以在我的github下载)

https://busybox.net/downloads/

解压后通过source insight软件打开源码(source insight不会用的先去查找一下相关资料)

打开source insight,在右边输入top,打开top.c文件

先打开main函数,这里发现程序将工作目录切换到了/proc目录。

一路跟踪到do_stats函数,进入该函数

再进入get_jiffy_counts函数

这个函数解释了top命令中的cpu信息如何来的

首先看到,打开了stat文件,根据main函数中切换目录,可以判断这个文件名为/proc/stat,到linux系统中查看

ls /proc/stat

有这个文件,那么看看里面有什么

https://blog.csdn.net/ibless/article/details/85177175

关于/proc/stat的解析,可以参考一下这篇文章

有9行CPU开头的数据,其中CPU为总的CPU数据,其他0-7为各个核心的数据(没错,我这块板是8核的)。

现在我需要的是总CPU使用率,所以只关心第一行就行了。

看看busybox如何处理的

首先用fscanf格式化读取文件中的数据,并分别放到结构体保存,这里我们不用关心jif这个结构体是什么,只需要通过%lld知道这里的数据类型是long long就可以了。

接着求了一个总和,可以看到就是把其他的全部加起来。

总和减去剩余的,就是已经使用的。

公式如下

Total CPU time since boot = user+nice+system+idle+iowait+irq+softirq+steal
Total CPU Idle time since boot = idle + iowait
Total CPU usage time since boot = Total CPU time since boot - Total CPU Idle time since boot
Total CPU percentage = Total CPU usage time since boot/Total CPU time since boot * 100%

也就是说,CPU的占用率= (1 - (现在时刻CPU Idle – 前一时刻CPU Idle) /  (现在时刻CPU Total – 前一时刻CPU Total))

过程知道了,那么可以使用QT编写程序了。结构体上面已经展示过了,这里就直接给代码

先在类中声明一个全局的变量,用于保存前一时刻的CPU信息

CpuInfo_Data pre_cpu_info_data;

数据处理过程如下

    // 初始化为0
    struct CpuInfo_Data cpu_info_data;
    cpu_info_data.usr = 0;
    cpu_info_data.nic = 0;
    cpu_info_data.sys = 0;
    cpu_info_data.idle = 0;
    cpu_info_data.iowait = 0;
    cpu_info_data.irq = 0;
    cpu_info_data.softirq = 0;
    cpu_info_data.steal = 0;
    cpu_info_data.temp = 0;
    cpu_info_data.total = 0;
    cpu_info_data.rate = 0;
    cpu_info_data.freq = 0;

    //获得CPU占用信息
    QString info_file_name("/proc/stat");
    QFileInfo file_info(info_file_name);
    //判断文件是否存在
    if(file_info.isFile())
    {
        //提取文件中的数据
        std::FILE *cpu_fd = std::fopen(info_file_name.toLatin1().data(),"r");
        if(std::fscanf(cpu_fd,"cpu  %lld %lld %lld %lld %lld %lld %lld %lld",\
                    &cpu_info_data.usr,&cpu_info_data.nic,&cpu_info_data.sys, \
                    &cpu_info_data.idle,&cpu_info_data.iowait, \
                    &cpu_info_data.irq,&cpu_info_data.softirq, \
                    &cpu_info_data.steal) < 4)
        {
            qDebug() << "failed to read " << info_file_name;
        }
        std::fclose(cpu_fd);

        //计算CPU总资源数
        cpu_info_data.total = cpu_info_data.usr + cpu_info_data.nic + cpu_info_data.sys + cpu_info_data.idle + cpu_info_data.iowait + cpu_info_data.irq + cpu_info_data.softirq + cpu_info_data.steal;

        long long total = cpu_info_data.total;
        long long idle = cpu_info_data.idle + cpu_info_data.iowait;
        long long pre_total = pre_cpu_info_data.total;
        long long pre_idle = pre_cpu_info_data.idle + pre_cpu_info_data.iowait;

        cpu_info_data.rate = static_cast<double>((double)((total-pre_total) - (idle-pre_idle)) / (double)(total-pre_total)) * 100;
        pre_cpu_info_data = cpu_info_data;

        //qDebug() << QString("cpu rate : %1%").arg(cpu_info_data.rate);
    }
    else
    {
        qDebug() << "No file named : " << info_file_name;
    }

因为是C++语言,所以使用std::fscanf代替fscanf,其实参数都是一样的。求使用率的时候,因为是double所以记得使用static_case<double>进行类型转换。最后使用QString::number(cpu_info_data.rate, 'f', 2)方法输出小数点后2位的数据。

  • 内存信息

上面说到的top命令同样也能读取内存数据,那么我们在top.c中找一下是如何实现的。

找到display_generic函数

发现这里使用的文件是meminfo,也就是/proc/meminfo,同样,我们在linux下查看这个文件里面的数据。

cat /proc/meminfo

可以看到是内存的所有信息,但是我们只关注前两行就可以了。

MemTotal是总的内存大小

MemFree是空闲的内存大小

那么可以得出使用的内存大小为MemTotal-MemFree,使用率为(MemTotal-MemFree)/MemTotal * 100

同样使用格式化读取,%lu为long unsigned int类型

那么接下来可以编写QT程序

定义结构体

struct MemInfo_data
{
    long unsigned int total;
    long unsigned int free;
    long unsigned int used;
    double rate;
};

读取文件信息

    QString file_info_name("/proc/meminfo");
    QFileInfo file_info(file_info_name);
    if(file_info.isFile())
    {
        std::FILE *mem_fd = std::fopen(file_info_name.toLatin1().data(),"r");
        std::fscanf(mem_fd,"MemTotal: %lu kB\n",&mem_info_data.total);
        std::fscanf(mem_fd,"MemFree: %lu kB\n",&mem_info_data.free);
        std::fclose(mem_fd);
        mem_info_data.used = mem_info_data.total - mem_info_data.free;
        mem_info_data.rate = static_cast<double>((double)mem_info_data.used / (double)mem_info_data.total) * 100.0;

        mem_info_data.total = mem_info_data.total / 1024;
        mem_info_data.used  = mem_info_data.used  / 1024;
        mem_info_data.free  = mem_info_data.free  / 1024;

        //qDebug() << QString("Mem : %1 / %2 MB    %3%").arg(mem_info_data.used).arg(mem_info_data.total).arg(QString::number(mem_info_data.rate,'f',2));
    }
    else
    {
        qDebug() << "No file named : " << file_info_name;
        return;
}

同样记得注意int-double的类型转换,读取数据的单位是KB,我想用MB所以除1024

  • 硬盘信息

在linux上我们一般使用df命令来查看硬盘信息,这个命令也是由busybox实现,在源码中找到df.c,进入main函数。这里要注意一个结构体struct statfs,这个结构体保存了所有的硬盘信息,是内核实现的,不需要我们另外读取文件得到,不了解的先去查一下这个结构体的使用。

往下看,来到红框这里,这个函数的作用是读取以mount_point为结点的目录在硬盘中的空间使用情况,并放入s结构体,前面我们知道了s就是struct statfs

那么总的空间大小为f_blocks*f_bsize,空闲的空间大小为f_bfree*f_bsize

那么已经使用的空间大小为总的空间大小减去空闲的空间大小

编写QT代码

要使用struct statfs结构体,要先包括两个头文件

#include <sys/statfs.h>
#include <sys/vfs.h>

先定义结构体

struct DiskInfo_data
{
    long long total;
    long long free;
    long long used;
    double rate;
};

读取信息过程

    struct statfs disk_info;
    QString path = "/";

    if (statfs(path.toLatin1().data(), &disk_info) == -1)
    {
        qDebug() << "Failed to get file disk infomation";
        return;
    }

    disk_info_data.total = disk_info.f_blocks * disk_info.f_bsize;
    disk_info_data.free = disk_info.f_bfree * disk_info.f_bsize;
    disk_info_data.used = disk_info_data.total - disk_info_data.free;
    disk_info_data.rate = static_cast<double>((double)disk_info_data.used / (double)disk_info_data.total) * 100.0;

    disk_info_data.total = disk_info_data.total / 1024 / 1024;
    disk_info_data.free  = disk_info_data.free  / 1024 / 1024;
    disk_info_data.used  = disk_info_data.used  / 1024 / 1024;

    //double total = static_cast<double>((double)disk_info_data.total / 1024);
    //double used = static_cast<double>((double)disk_info_data.used / 1024);

    //qDebug() << QString("Disk : %1 / %2 GB    %3%").arg(QString::number(used,'f',2)).arg(QString::number(total,'f',2)).arg(QString::number(disk_info_data.rate,'f',2));

这里我想得到根文件系统的使用信息,所以传入的第一个参数为”/”,同样注意类型转换,以及单位转换,初始数据是字节为单位,我想使用GB为单位,所以要除三次1024

  • 补充说明

4个系统数据都读取完成,于是我将他们整合起来,开一个线程来跑,每秒读取一次信息并返回给界面,使用QLabel显示。

这里遇到了一个问题就是,我使用了QT信号和槽机制来传输我自定义的三个结构体,但是信号和槽并不支持使用自定义的结构作为参数,所以报错

QObject::connect: Cannot queue arguments of type ‘CpuInfo_data’ (Make sure ‘CpuInfo_data’ is registed using qRegisterMetaType().)

解决方法

包含一个头文件

#include <QMetaType>

然后在connect信号槽之前注册自定义的结构体

    //使用自定义结构体在信号槽中传递时需要先注册,否则会报错
    qRegisterMetaType<CpuInfo_data>("CpuInfo_data");
    qRegisterMetaType<MemInfo_data>("MemInfo_data");
    qRegisterMetaType<DiskInfo_data>("DiskInfo_data");

这样就可以解决问题

运行结果在上一章已经展示过了。

 

Qt完整源码放在github上,有需要可以自行下载。 代码名称为190516.zip

https://github.com/ljy980330/opencv_face_sys

 

有任何问题可以在下面给我留言!大家一起学习!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值