The Performance Blind Spot: Why Doesn't Your Process Know How Much It's Consuming?
\n\nImagine: you've written a complex C++ application, it's running, but it starts to slow down. You launch top, htop, or Task Manager — and you see your process devouring 90% CPU or gigabytes of memory. But how do you make the process itself aware of this and, for example, dynamically reduce the load or clear the cache?
This isn't just an academic interest. In a production environment, on servers without a GUI, you can't rely on external utilities. The program needs to monitor itself. This is exactly the problem solved by the popular Stack Overflow question: "How to determine CPU and memory consumption from inside a process". Let's break it down with real C++ examples.
\n\nThe Cross-Platform Dilemma: Linux vs Windows
\n\nOperating systems provide access to process statistics in different ways. Under the hood, Linux uses the virtual filesystem /proc, while Windows uses the Win32 API. We'll write a universal class that works on both platforms.
The main metrics we'll extract:
\n- \n
- CPU usage (as a percentage or fraction of a core) \n
- Physical memory (RSS) — actual RAM used \n
- Virtual memory (VSZ) — total address space size \n
Reading CPU on Linux: The Magic of /proc/self/stat
\n\nTo get the process CPU time, we read the file /proc/self/stat. It contains dozens of fields; we are interested in fields 13-16 (utime, stime, cutime, cstime) — time in jiffies. To convert to percentages, we need to know the tick rate (sysconf(_SC_CLK_TCK)) and the total system uptime.
#ifdef __linux__\n#include <unistd.h>\n#include <fstream>\n#include <sstream>\n#include <string>\n#include <vector>\n\ndouble getCpuUsageLinux() {\n static unsigned long long prevTotal = 0, prevIdle = 0;\n static double prevProcessTicks = 0;\n static bool first = true;\n\n // Process time\n std::ifstream procStat("/proc/self/stat");\n std::string line;\n std::getline(procStat, line);\n std::istringstream iss(line);\n std::vector<std::string> fields;\n std::string field;\n while (iss >> field) fields.push_back(field);\n\n unsigned long utime = std::stoul(fields[13]);\n unsigned long stime = std::stoul(fields[14]);\n unsigned long cutime = std::stoul(fields[15]);\n unsigned long cstime = std::stoul(fields[16]);\n double processTicks = utime + stime + cutime + cstime;\n\n // System time\n std::ifstream statFile("/proc/stat");\n std::getline(statFile, line);\n statFile.close();\n std::istringstream iss2(line);\n std::string cpuLabel;\n iss2 >> cpuLabel;\n unsigned long long user, nice, system, idle, iowait, irq, softirq, steal;\n iss2 >> user >> nice >> system >> idle >> iowait >> irq >> softirq >> steal;\n unsigned long long total = user + nice + system + idle + iowait + irq + softirq + steal;\n\n if (first) {\n prevTotal = total;\n prevIdle = idle;\n prevProcessTicks = processTicks;\n first = false;\n return 0.0;\n }\n\n unsigned long long totalDelta = total - prevTotal;\n double processDelta = processTicks - prevProcessTicks;\n double cpuPercent = (processDelta / totalDelta) * 100.0;\n\n prevTotal = total;\n prevIdle = idle;\n prevProcessTicks = processTicks;\n\n return cpuPercent;\n}\n#endif\n\n\nThis code calculates the CPU percentage used by the process since the first call. Note: we take the difference between two measurements — this is the standard approach for accuracy.
\n\nMemory on Linux: RSS and VSZ
\n\nFor memory, we read /proc/self/status. We are interested in the lines