計算linux磁盤空間,cpu,內存的例子

注意:

 

cpu使用率計算的時候,需要sleep,這會造成當前計算線程的阻塞,因此 這裏在單例裏面單獨開了一個線程來處理計算邏輯;

 

另外一個線程,是模擬外部 的多線程訪問。 

 

//singleton_template.h

#pragma once

#include <iostream>

template <typename T>
class Singleton {
public:
    static T& getInstance() {
        static T instance;
        return instance;
    }

private:
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

protected:
    Singleton() {}
};
// calc_resource.h

#pragma once

#include "singleton_template.h"
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include <vector>

struct  DISK_INFO{
    unsigned long long diskTotal;
    unsigned long long diskUsed;
};  

struct BASE_INFO{
    int cpuCount;  //cpu總數
    float cpuUsed; //cpu使用數...通過使用率反向計算出來
    float cpuPercent; //cpu使用率

    unsigned long long MemTotalMb; //總的物理內存
    unsigned long long MemUsedMb;  //已使用的物理內存
    float memPercent;//物理內存使用率

    unsigned long long SwapTotalMb;//總的虛擬內存
    unsigned long long SwapUsedMb;//已使用的虛擬內存
    float swapPercent;//虛擬內存使用率


    unsigned long long  DiskTotalMb;//硬盤總大小
    unsigned long long  DiskUsedMb;//硬盤已使用大小
    float diskPercent; //硬盤使用率
};

class MyClass : public Singleton<MyClass> {
    // 可以在這裏添加自定義代碼
public:
    void doSomething();
    void doSomething2();
    void updateBaseInfo();//定時去更新
    BASE_INFO getBaseInfo();//外部獲取,這裏有Old值作爲臨時緩存,儘量減少阻塞

    MyClass();
    ~MyClass();

private:
    void cpuCount(BASE_INFO& oneInfo);
    void cpuPercent(BASE_INFO& oneInfo);
    void memoryInfo(BASE_INFO& oneInfo);
    void diskInfo(BASE_INFO& oneInfo);
    void checkDiskForMountPoint(const std::string& mountPoint, std::map<std::string, DISK_INFO> &mapDiskInfo);
    std::vector<float> readCpuStat();
    float calculateCpuUsage(const std::vector<float>& prev, const std::vector<float>& curr);


private :
    std::shared_ptr<std::thread> m_threadPtr;
    std::thread m_thread2;
    std::mutex m_mux;
    std::condition_variable m_cond;
    bool m_running=false;
    bool m_infoAvailable = false;;
    BASE_INFO m_baseInfo; //最新計算出來的信息
    BASE_INFO m_OldBaseInfo;//上一次計算出來的信息
};
// calc_resource.cpp

#include <iostream>
#include <fstream>  
#include <sstream>  
#include <string>  
#include <map>
#include "calc_resource.h"
#include <sys/statvfs.h>  

MyClass::MyClass(){
    m_running = true;
    m_baseInfo = {0};
    m_OldBaseInfo = {0};
    m_threadPtr = std::make_shared<std::thread>(&MyClass::doSomething,this);
    m_thread2 = std::thread(&MyClass::doSomething2,this);
}

MyClass::~MyClass(){
    m_running = false;
    m_cond.notify_all();
    if(m_threadPtr->joinable()){
        m_threadPtr->join();
    }
}

// 可以在這裏添加自定義代碼
void MyClass::doSomething() {
    while(m_running){
        {
            std::cout << "Doing something...------------------------>>>>>" << std::endl;
            //std::this_thread::sleep_for(std::chrono::seconds(1));
            memoryInfo(m_baseInfo);
            diskInfo(m_baseInfo);
            cpuCount(m_baseInfo);
            cpuPercent(m_baseInfo);
            m_infoAvailable = true;
        }
        m_cond.notify_all();//通知等待的線程
        std::this_thread::sleep_for(std::chrono::seconds(3));
    }
}

// 可以在這裏添加自定義代碼
void MyClass::doSomething2() {
    while(m_running){
        {
            std::cout << "thread2 ----------------->>>>>" << std::endl;
            auto oneInfo = getBaseInfo();//        
            std::cout <<"cpu Count:"<<oneInfo.cpuCount<<std::endl;
            std::cout <<"cpu cpuUsed:"<<oneInfo.cpuUsed<<std::endl;
            std::cout <<"cpu cpuPercent:"<<oneInfo.cpuPercent<<std::endl;

            std::cout <<"MemTotalMb:"<<oneInfo.MemTotalMb<<std::endl;
            std::cout <<"MemUsedMb:"<<oneInfo.MemUsedMb<<std::endl;

            std::cout <<"SwapTotalMb:"<<oneInfo.SwapTotalMb<<std::endl;
            std::cout <<"SwapUsedMb:"<<oneInfo.SwapUsedMb<<std::endl;

            std::cout <<"DiskTotalMb:"<<oneInfo.DiskTotalMb<<std::endl;
            std::cout <<"DiskUsedMb:"<<oneInfo.DiskUsedMb<<std::endl;

        }
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

// 更新 oldBaseInfo
void MyClass::updateBaseInfo(){
    std::unique_lock<std::mutex> lock(m_mux);
    m_cond.wait(lock,[this]{return m_infoAvailable;});
    m_infoAvailable = false;//重置標誌
    m_OldBaseInfo = m_baseInfo;
}


BASE_INFO MyClass::getBaseInfo(){
    std::unique_lock<std::mutex> lock(m_mux);
    return m_OldBaseInfo;//上一次計算出來的信息
}


// cat /proc/meminfo
void MyClass::memoryInfo(BASE_INFO& oneInfo){
    std::map<std::string, std::string> meminfo;  
    std::ifstream file("/proc/meminfo");  
    std::string line;    
    if (file.is_open()) {  
        while (std::getline(file, line)) {  
            std::istringstream iss(line);  
            std::string key, value;  
            if (!(iss >> key >> value)) continue;  
            meminfo[key] = value;  
        }  
        file.close();  
    } else {  
        std::cerr << "Error: Could not open /proc/meminfo" << std::endl;  
    }  
    // 打印全部內存信息
    // std::cout<<"========================================================="<<std::endl;
    // for(auto it = meminfo.begin(); it != meminfo.end(); ++it){
    //     std::cout << it->first << ": " << it->second << std::endl;
    // }
    // std::cout<<"========================================================="<<std::endl;
    {
        std::lock_guard<std::mutex> lock(m_mux);
        oneInfo.MemTotalMb = std::stoll(meminfo["MemTotal:"]) / 1;
        oneInfo.MemUsedMb = (std::stoll(meminfo["MemTotal:"]) - std::stoll(meminfo["MemFree:"]) - std::stoll(meminfo["Buffers:"]) - std::stoll(meminfo["Cached:"])) / 1;

        oneInfo.SwapTotalMb = std::stoll(meminfo["SwapTotal:"]) / 1;
        oneInfo.SwapUsedMb = (std::stoll(meminfo["SwapTotal:"]) - std::stoll(meminfo["SwapFree:"])) / 1;
    }
}

void MyClass::checkDiskForMountPoint(const std::string& mountPoint, std::map<std::string, DISK_INFO> &mapDiskInfo) {  
    struct statvfs stats;  
    if (statvfs(mountPoint.c_str(), &stats) != 0) {  
        std::cerr << "Error getting disk usage for " << mountPoint << std::endl;  
        return;  
    }  
  
    unsigned long long totalBytes = static_cast<unsigned long long>(stats.f_blocks) * static_cast<unsigned long long>(stats.f_bsize);  
    unsigned long long usedBytes = (static_cast<unsigned long long>(stats.f_blocks - stats.f_bfree) * static_cast<unsigned long long>(stats.f_bsize));  
    mapDiskInfo[mountPoint].diskTotal = totalBytes/(1024 * 1024);
    mapDiskInfo[mountPoint].diskUsed = usedBytes/(1024 * 1024);
}  

void MyClass::diskInfo(BASE_INFO& oneInfo){
    std::ifstream mountsFile("/proc/mounts");  
    std::string line;  

    std::map<std::string, DISK_INFO> mapDiskInfo;
  
    while (std::getline(mountsFile, line)) {  
        std::istringstream iss(line);  
        std::string fsType, mountPoint, options;  
        if (!(iss >> fsType >> mountPoint >> options)) {  
            continue; // Skip invalid lines  
        }  
        //todo: 還要考慮 docker 的那種掛在情況
        //todo: 需要在 網關盒子上真實的跑一下 
        // Filter out entries that are not real file systems or are not mounted to a directory  
        if (fsType == "none" || fsType == "tmpfs" || "devtmpfs"== fsType || mountPoint.find('/') == std::string::npos) {  
            continue;  
        }  
        checkDiskForMountPoint(mountPoint,mapDiskInfo);  //檢查一個掛在目錄,一般有多個掛在目錄
    }  

    {
        std::lock_guard<std::mutex> lock(m_mux);
        oneInfo.DiskTotalMb =0;
        oneInfo.DiskUsedMb =0;
        for(auto it=mapDiskInfo.begin(); it!= mapDiskInfo.end(); ++it){
            if(it->second.diskTotal>0){
                //std::cout<<"Mount Point:"<<it->first<<",diskTotal:"<<it->second.diskTotal<<"Mb,diskUsed:"<<it->second.diskUsed<<"Mb"<<std::endl;
                oneInfo.DiskTotalMb += it->second.diskTotal;
                oneInfo.DiskUsedMb += it->second.diskUsed;
            }
        }
    }
}


void MyClass::cpuCount(BASE_INFO& oneInfo){
    std::ifstream file("/proc/cpuinfo");  
    std::string line;  
    int count = 0;  
  
    while (std::getline(file, line)) {  
        if (line.find("processor") != std::string::npos) {  
            ++count;  
        }  
    }  
    {
        std::lock_guard<std::mutex> lock(m_mux);
        oneInfo.cpuCount = count;
    }
}

std::vector<float> MyClass::readCpuStat() {  
    std::ifstream file("/proc/stat");  
    std::string line;  
    std::getline(file, line); // 讀取第一行,它包含cpu的總時間  
  
    std::istringstream iss(line);  
    std::string token;  
    std::vector<float> cpuValues;  
  
    // 讀取cpu的各個時間值  
    while (iss >> token) {  
        if (token == "cpu") {  
            // 跳過"cpu"標記  
            continue;  
        }  
        cpuValues.push_back(std::stoull(token));  
    }  
  
    return cpuValues;  
}  

float MyClass::calculateCpuUsage(const std::vector<float>& prev, const std::vector<float>& curr) {  
    float prevIdle = prev[3] + prev[4]; // idle + iowait  
    float currIdle = curr[3] + curr[4];  
    float prevTotal = 0;  
    float currTotal = 0;  
  
    // 計算總時間(不包括idle和iowait)  
    for (size_t i = 0; i < prev.size(); ++i) {  
        if (i != 3 && i != 4) { // 跳過idle和iowait  
            prevTotal += prev[i];  
            currTotal += curr[i];  
        }  
    }  
  
    // 計算CPU使用率  
    float usage = 100.0f * (currTotal - prevTotal) / (currTotal + currIdle - prevTotal - prevIdle);  
    return usage;  
}  

// 計算2次時間間隔內的 cpu使用信息
void MyClass::cpuPercent(BASE_INFO& oneInfo){
    std::vector<float> prevCpuValues = readCpuStat();
    std::this_thread::sleep_for(std::chrono::milliseconds(100)); //! 等待一段時間  
    std::vector<float> currCpuValues = readCpuStat();
    float cpuUsage = calculateCpuUsage(prevCpuValues, currCpuValues);  
    {
        std::lock_guard<std::mutex> lock(m_mux);
        oneInfo.cpuPercent = cpuUsage / 100.0f;
        oneInfo.cpuUsed = oneInfo.cpuPercent * oneInfo.cpuCount;
    }
}


int main() {
    MyClass& instance = MyClass::getInstance();

    std::cout <<"================= 早睡早起 ==============="<<std::endl;
    while(1){
        std::this_thread::sleep_for(std::chrono::seconds(1));
        instance.updateBaseInfo();
    }
    getchar();
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章