Search code examples
clinuxcpucpu-usage

Current CPU core utilization via /proc/stat


I want to calculate the current CPU core utilization on Linux from or .
Load average (getloadavg()) doesn't fit my purpose because it show only the whole CPU load with specific calculation.

Based on common sense I understand that the literally current CPU core load is either 0 or 100 percents. But I can calculate it in delta time.

From /proc/stat description I see the following metrics:

user: normal processes executing in user mode
nice: niced processes executing in user mode
system: processes executing in kernel mode
idle: twiddling thumbs
iowait: waiting for I/O to complete
irq: servicing interrupts
softirq: servicing softirqs

But I sill can't figure out how exactly to calculate CPU core load per second for example..
Sorry if obvious.

Related post: How can I determine the current CPU utilization from the shell?


Solution

  • The following program:

    #include <assert.h>
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    #include <sys/stat.h>
    #include <unistd.h>
    
    struct cpuusage {
        char name[20];
        // Absolute values since last reboot.
        unsigned long long idletime;
        unsigned long long workingtime;
    };
    
    struct cpustat {
        char name[20];
        unsigned long long user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice;
    };
    
    struct cpuusage cpuusage_from_cpustat(struct cpustat s) {
        struct cpuusage r;
        strncpy(r.name, s.name, sizeof(r.name));
        r.name[sizeof(r.name) - 1] = '\0';
        r.idletime = s.idle + s.iowait;
        r.workingtime = s.user + s.nice + s.system + s.irq + s.softirq;
        return r;
    }
    
    void cpuusage_show_diff(struct cpuusage now, struct cpuusage prev) {
        // the number of ticks that passed by since the last measurement
        const unsigned long long workingtime = now.workingtime - prev.workingtime;
        const unsigned long long alltime = workingtime + (now.idletime - prev.idletime);
        // they are divided by themselves - so the unit does not matter.
        printf("Usage: %.0Lf%%\n", (long double)workingtime / alltime * 100.0L);
    }
    
    int main() {
        struct cpuusage prev = {0};
        //
        const int stat = open("/proc/stat", O_RDONLY);
        assert(stat != -1);
        fcntl(stat, F_SETFL, O_NONBLOCK);
        while (1) {
            // let's read everything in one call so it's nicely synced.
            int r = lseek(stat, SEEK_SET, 0);
            assert(r != -1);
            char buffer[10001];
            const ssize_t readed = read(stat, buffer, sizeof(buffer) - 1);
            assert(readed != -1);
            buffer[readed] = '\0';
            // Read the values from the readed buffer/
            FILE *f = fmemopen(buffer, readed, "r");
            // Uch, so much borign typing.
            struct cpustat c = {0};
            while (fscanf(f, "%19s %llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", c.name, &c.user, &c.nice,
                      &c.system, &c.idle, &c.iowait, &c.irq, &c.softirq, &c.steal, &c.guest,
                      &c.guest_nice) == 11) {
                // Just an example for first cpu core.
                if (strcmp(c.name, "cpu0") == 0) {
                    struct cpuusage now = cpuusage_from_cpustat(c);
                    cpuusage_show_diff(now, prev);
                    prev = now;
                    break;
                }
            }
            fclose(f);
            //
            sleep(1);
        }
    }
    

    Outputs the usage of the first core each second. I may be off with the calculations - consult this forum on which fields exactly to use from /dev/stat.