From f71966d629faab8fa49510a5ad0ec5020f045edc Mon Sep 17 00:00:00 2001 From: nimelehin Date: Wed, 18 Nov 2020 16:33:05 +0300 Subject: [PATCH] Add api to get per cpu usage Updated /proc/stat to be compatible with Linux's implementation. --- fs/proc/root.c | 26 ++++++++++++++++++++++++-- platform/darwin.c | 37 ++++++++++++++++++++++++++++++++++++- platform/linux.c | 28 +++++++++++++++++++++++++++- platform/platform.h | 3 ++- 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/fs/proc/root.c b/fs/proc/root.c index 928d78e5f8..88b76fd8d8 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -15,8 +15,30 @@ static int proc_show_version(struct proc_entry *UNUSED(entry), struct proc_data } static int proc_show_stat(struct proc_entry *UNUSED(entry), struct proc_data *buf) { - struct cpu_usage usage = get_cpu_usage(); - proc_printf(buf, "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64"\n", usage.user_ticks, usage.nice_ticks, usage.system_ticks, usage.idle_ticks); + int ncpus = get_cpu_count(); + struct cpu_usage total_usage = get_total_cpu_usage(); + struct cpu_usage* per_cpu_usage = 0; + struct uptime_info uptime_info = get_uptime(); + unsigned uptime = uptime_info.uptime_ticks; + + proc_printf(buf, "cpu %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" 0 0 0 0\n", total_usage.user_ticks, total_usage.nice_ticks, total_usage.system_ticks, total_usage.idle_ticks); + + int err = get_per_cpu_usage(&per_cpu_usage); + if (!err) { + for (int i = 0; i < ncpus; i++) { + proc_printf(buf, "cpu%d %"PRIu64" %"PRIu64" %"PRIu64" %"PRIu64" 0 0 0 0\n", i, per_cpu_usage[i].user_ticks, per_cpu_usage[i].nice_ticks, per_cpu_usage[i].system_ticks, per_cpu_usage[i].idle_ticks); + } + free(per_cpu_usage); + } + + int blocked_task_count = get_count_of_blocked_tasks(); + int alive_task_count = get_count_of_alive_tasks(); + proc_printf(buf, "ctxt 0\n"); + proc_printf(buf, "btime %u\n", uptime); + proc_printf(buf, "processes %d\n", alive_task_count); + proc_printf(buf, "procs_running %d\n", alive_task_count - blocked_task_count); + proc_printf(buf, "procs_blocked %d\n", blocked_task_count); + return 0; } diff --git a/platform/darwin.c b/platform/darwin.c index 168e90a983..a3b91f04f0 100644 --- a/platform/darwin.c +++ b/platform/darwin.c @@ -1,9 +1,12 @@ +#include #include #include #include +#include #include "platform/platform.h" +#include "debug.h" -struct cpu_usage get_cpu_usage() { +struct cpu_usage get_total_cpu_usage() { host_cpu_load_info_data_t load; mach_msg_type_number_t fuck = HOST_CPU_LOAD_INFO_COUNT; host_statistics(mach_host_self(), HOST_CPU_LOAD_INFO, (host_info_t) &load, &fuck); @@ -68,3 +71,35 @@ int get_cpu_count() { sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0); return ncpu; } + +int get_per_cpu_usage(struct cpu_usage** cpus_usage) { + mach_msg_type_number_t info_size = sizeof(processor_cpu_load_info_t); + processor_cpu_load_info_t sys_load_data = 0; + natural_t ncpu; + + int err = host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &ncpu, (processor_info_array_t*)&sys_load_data, &info_size); + if (err) { + STRACE("Unable to get per cpu usage"); + return err; + } + + struct cpu_usage* cpus_load_data = (struct cpu_usage*)calloc(ncpu, sizeof(struct cpu_usage)); + if (!cpus_load_data) { + return -ENOMEM; + } + + for (natural_t i = 0; i < ncpu; i++) { + cpus_load_data[i].user_ticks = sys_load_data[i].cpu_ticks[CPU_STATE_USER]; + cpus_load_data[i].system_ticks = sys_load_data[i].cpu_ticks[CPU_STATE_SYSTEM]; + cpus_load_data[i].idle_ticks = sys_load_data[i].cpu_ticks[CPU_STATE_IDLE]; + cpus_load_data[i].nice_ticks = sys_load_data[i].cpu_ticks[CPU_STATE_NICE]; + } + *cpus_usage = cpus_load_data; + + // Freeing cpu load information + if (sys_load_data) { + munmap(sys_load_data, vm_page_size); + } + + return 0; +} diff --git a/platform/linux.c b/platform/linux.c index 40eb916fcb..6da83a0302 100644 --- a/platform/linux.c +++ b/platform/linux.c @@ -1,6 +1,8 @@ +#include #include #include #include +#include #include #include "platform/platform.h" #include "debug.h" @@ -16,7 +18,7 @@ static void read_proc_line(const char *file, const char *name, char *buf) { fclose(f); } -struct cpu_usage get_cpu_usage() { +struct cpu_usage get_total_cpu_usage() { struct cpu_usage usage = {}; char buf[1234]; read_proc_line("/proc/stat", "cpu", buf); @@ -55,3 +57,27 @@ struct uptime_info get_uptime() { int get_cpu_count() { return get_nprocs(); } + +int get_per_cpu_usage(struct cpu_usage** cpus_usage) { + char buf[1234]; + char cpu_title[8]; + int ncpu = get_cpu_count(); + struct cpu_usage* cpus_load_data = (struct cpu_usage*)calloc(ncpu, sizeof(struct cpu_usage)); + if (!cpus_load_data) { + return -ENOMEM; + } + + for (int i = 0; i < ncpu; i++) { + int cpu_num; + int title_len = snprintf(cpu_title, 8, "cpu%d", i); + if (title_len > 8 || title_len < 0) { + STRACE("Can't load info of cpu %d (>10000)", i); + free(cpus_load_data); + return -ENOMEM; + } + read_proc_line("/proc/stat", cpu_title, buf); + sscanf(buf, "cpu%d %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64"\n", &cpu_num, &cpus_load_data[i].user_ticks, &cpus_load_data[i].system_ticks, &cpus_load_data[i].idle_ticks, &cpus_load_data[i].nice_ticks); + } + *cpus_usage = cpus_load_data; + return 0; +} diff --git a/platform/platform.h b/platform/platform.h index 5d1f0f464b..af9db99d54 100644 --- a/platform/platform.h +++ b/platform/platform.h @@ -9,7 +9,8 @@ struct cpu_usage { uint64_t idle_ticks; uint64_t nice_ticks; }; -struct cpu_usage get_cpu_usage(void); +struct cpu_usage get_total_cpu_usage(void); +int get_per_cpu_usage(struct cpu_usage** cpus_usage); struct mem_usage { uint64_t total;