Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions include/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ extern "C" {
#endif /* __cplusplus */

#include <stdint.h>
#include <stdbool.h>
#include <cJSON.h>

typedef struct {
Expand All @@ -15,6 +16,7 @@ typedef struct {
float max_MHz;
float min_MHz;
float curr_temp;
float curr_usage;
uint16_t cpu_family;
uint16_t model;
uint16_t stepping;
Expand All @@ -23,8 +25,21 @@ typedef struct {
uint16_t online_cores;
} CPU;

typedef struct {
uint64_t user;
uint64_t nice;
uint64_t system;
uint64_t idle;
uint64_t iowait;
uint64_t irq;
uint64_t softirq;
uint64_t steal;
} CPUTimes;

cJSON *cpu_to_json_obj(const CPU *cpu);

CPU *cpu_get_info(void);

void free_cpu(CPU *cpu);

#ifdef __cplusplus
Expand Down
8 changes: 8 additions & 0 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ display_cpu(const CPU *cpu)
print_field("Vendor", "%s", STR_OR_UNK(cpu->vendor_id));
print_field("Model", "%s", STR_OR_UNK(cpu->model_name));
print_field("Arch", "%s", STR_OR_UNK(cpu->arch));


if (cpu->curr_usage >= 0.0f) {
print_field("Usage", "%.1f %%", cpu->curr_usage);
} else {
print_field("Usage", "--");
}

print_field("Cores", "%u Physical / %u Logical", cpu->total_cores, cpu->total_threads);
print_field("Frequency", "%.2f MHz - %.2f MHz", cpu->min_MHz, cpu->max_MHz);

Expand Down
72 changes: 71 additions & 1 deletion src/linux/hardware/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,76 @@
#include "file.h"
#include "io.h"
#include <string.h>
#include <inttypes.h>
#include <time.h>
#include "cpu.h"

static bool
cpu_read_times(CPUTimes *out)
{
char *stat = file_read_stripped("/proc/stat", NULL, false);
if (stat == NULL) {
return false;
}

int n = sscanf(stat,
"cpu %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64
" %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64,
&out->user, &out->nice, &out->system, &out->idle,
&out->iowait, &out->irq, &out->softirq, &out->steal
);


free(stat);

return n == 8;
}

static float
cpu_usage_percent(const CPUTimes *a, const CPUTimes *b)
{
uint64_t idle_a = a->idle + a->iowait;
uint64_t idle_b = b->idle + b->iowait;
uint64_t busy_a = a->user + a->nice + a->system + a->irq + a->softirq + a->steal;
uint64_t busy_b = b->user + b->nice + b->system + b->irq + b->softirq + b->steal;

uint64_t total_d = (busy_b + idle_b) - (busy_a + idle_a);
uint64_t busy_d = busy_b - busy_a;

if (total_d == 0) {
return -1.0f;
}

return 100.0f * (float)busy_d / (float)total_d;
}

static float
cpu_get_usage(void)
{
static CPUTimes prev;
static bool have_prev = false;
CPUTimes curr;

if (!cpu_read_times(&curr)) {
return -1.0f;
}

if (!have_prev) {
prev = curr;
struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 }; /* 200ms */
nanosleep(&ts, NULL);
if (!cpu_read_times(&curr)) {
return -1.0f;
}
}

float pct = cpu_usage_percent(&prev, &curr);
prev = curr;
have_prev = true;

return pct;
}

static int16_t
cpu_get_total_cores(void)
{
Expand Down Expand Up @@ -87,6 +155,7 @@ cpu_get_info(void)
cpu->model_name = str_find_value(cpu_info, "model name", "\n");
cpu->flags = str_find_value(cpu_info, "flags", "\n");
cpu->arch = cpu_get_arch(cpu->flags);
cpu->curr_usage = cpu_get_usage();

cpu->online_cores = cpu_get_total_cores();
if (cpu->online_cores > 0) {
Expand All @@ -104,6 +173,7 @@ cpu_get_info(void)
cpu->total_threads = str_parse_value(cpu_info, "siblings", "\n");

free(cpu_info);

return cpu;
}

Expand All @@ -115,7 +185,7 @@ free_cpu(CPU *cpu)
}
free(cpu->vendor_id);
free(cpu->model_name);
free(cpu->flags);
free(cpu->flags);
free(cpu);
}

Expand Down
Loading