计算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; }