diff --git a/Makefile b/Makefile index 40f307a..1d5278b 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS = -g -Wall -Werror -fPIC -std=gnu99 -DEPS = resource.h resource_impl.h resmem.h resnet.h resproc.h resvm.h rescpu.h resfs.h -OBJ = resource.o resmem.o resnet.o resproc.o reskern.o resvm.o rescpu.o resfs.o net_if.o net_route.o net_arp.o +DEPS = resource.h resource_impl.h resmem.h resnet.h resproc.h resvm.h rescpu.h resfs.h stat.h +OBJ = resource.o resmem.o resnet.o resproc.o reskern.o resvm.o rescpu.o resfs.o net_if.o net_route.o net_arp.o stat.o TEST = test RM = rm -rf CP = cp diff --git a/resource.c b/resource.c index 6762a47..a3f22fe 100644 --- a/resource.c +++ b/resource.c @@ -31,6 +31,7 @@ #include "resnet.h" #include "resproc.h" #include "resvm.h" +#include "stat.h" #include "rescpu.h" #include "resfs.h" @@ -212,6 +213,9 @@ int res_read(int res_id, void *out, size_t out_sz, void **hint, int pid, int fla if (res_id >= DEV_MIN && res_id < DEV_MAX) return getdevinfo(res_id, out, out_sz, hint, flags); + if (res_id >= STAT_MIN && res_id < STAT_MAX) + return getstatinfo(res_id, out, out_sz, hint, flags); + if (res_id >= FS_MIN && res_id < FS_MAX) return getfsinfo(res_id, out, out_sz, hint, flags); diff --git a/resource.h b/resource.h index ecd6aa0..9d5304d 100644 --- a/resource.h +++ b/resource.h @@ -157,6 +157,10 @@ typedef struct res_blk { #define RES_CPU_CORECOUNT 6002 #define CPU_MAX 6010 +#define STAT_MIN 7000 +#define RES_STAT_INFO 7001 +#define STAT_MAX 7002 + #define FS_MIN 8000 #define FS_AIONR 8001 #define FS_AIOMAXNR 8002 @@ -549,6 +553,32 @@ struct vmstat { unsigned long nr_unstable; }; +struct cpu_stat { + unsigned long long user; + unsigned long long nice; + unsigned long long system; + unsigned long long idle; + unsigned long long iowait; + unsigned long long irq; + unsigned long long softirq; + unsigned long long steal; + unsigned long long guest; + unsigned long long guest_nice; +}; + +struct stat_info { + struct cpu_stat cpu; + struct cpu_stat *all_cpu; /* Array of len cpu_num */ + int cpu_num; + char intr[9000]; // total of all interrupts serviced(since boot) + unsigned long long ctxt; + unsigned long long btime; + unsigned long long processes; + unsigned long long procs_running; + unsigned long long procs_blocked; + char softirq[9000]; /* Number of softirq for all CPUs. */ +}; + /* Allocating memory and building a res_blk structure to return bulk * resource information. */ diff --git a/stat.c b/stat.c new file mode 100644 index 0000000..831cfeb --- /dev/null +++ b/stat.c @@ -0,0 +1,164 @@ +/* Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved + * + * This file is part of libresource. + * + * libresource is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libresource is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libresource. If not, see . + */ + +#ifndef _RESOURCE_H +#include "resource.h" +#endif +#include +#include +#include +#include +#include "resvm.h" +#include "resource_impl.h" +#include +#include +#include "stat.h" + +static char buffer[20000]; + +static int populate_statcpu(struct cpu_stat *all_cpu, int cpu_num) +{ + char buf[36]; + const char *cstr; + + if (!all_cpu) { + return -1; + } + for (int i = 0; i < cpu_num; i++) { + snprintf(buf, 36, "cpu%d", i); + cstr = strstr(buffer, buf); + if (cstr) { + cstr += strlen(buf)+1; + sscanf(cstr, "%Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", + &all_cpu->user, + &all_cpu->nice, + &all_cpu->system, + &all_cpu->idle, + &all_cpu->iowait, + &all_cpu->irq, + &all_cpu->softirq, + &all_cpu->steal, + &all_cpu->guest, + &all_cpu->guest_nice); + } + all_cpu++; + } + return 0; +} + +static int populate_statinfo(void *out, int test) +{ + char *cstr; + struct stat_info *st; + int cpu_num; + + st = (struct stat_info *) out; + cstr = strstr(buffer, "cpu "); + if (cstr) { + sscanf(cstr, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", + &st->cpu.user, + &st->cpu.nice, + &st->cpu.system, + &st->cpu.idle, + &st->cpu.iowait, + &st->cpu.irq, + &st->cpu.softirq, + &st->cpu.steal, + &st->cpu.guest, + &st->cpu.guest_nice); + } + cstr = strstr(buffer, "intr "); + memset(&st->intr, '\0', sizeof(st->intr)); + if (cstr) { + unsigned int bytes = 0; + char *cstr1 = cstr + 5; + while (*cstr1 != '\n' && bytes < 8999) { + cstr1++; + bytes++; + } + strncpy(st->intr, cstr+5, bytes); + } + cstr = strstr(buffer, "ctxt "); + if (cstr) + sscanf(cstr, "ctxt %Lu", &st->ctxt); + cstr = strstr(buffer, "btime "); + if (cstr) + sscanf(cstr, "btime %Lu", &st->btime); + cstr = strstr(buffer, "processes "); + if (cstr) + sscanf(cstr, "processes %Lu", &st->processes); + cstr = strstr(buffer, "procs_running "); + if (cstr) + sscanf(cstr, "procs_running %Lu", &st->procs_running); + cstr = strstr(buffer, "procs_blocked "); + if (cstr) + sscanf(cstr, "procs_blocked %Lu", &st->procs_blocked); + cstr = strstr(buffer, "softirq "); + memset(&st->softirq, '\0', sizeof(st->softirq)); + if (cstr) { + unsigned int bytes = 0; + char *cstr1 = cstr + 8; + while (*cstr1 != '\n' && bytes < 8999) { + cstr1++; + bytes++; + } + strncpy(st->softirq, cstr+8, bytes); + } + + cpu_num = sysconf(_SC_NPROCESSORS_ONLN); + populate_statcpu(st->all_cpu, cpu_num); + return 0; +} + +int getstatexist(int res_id, void *exist, size_t sz, void *hint, int flags) +{ + int ret; + ret = file_to_buf("./stat_info.orig", buffer, sizeof(buffer)); + if (ret == -1) + return -1; + ret = populate_statinfo(exist, 1); + return ret; +} + +int getstatinfo(int res_id, void *out, size_t sz, void **hint, int flags) +{ + int ret, cpu_num, cpu_size; + +#ifdef TESTING + ret = file_to_buf("./stat_info.orig", buffer, sizeof(buffer)); +#else + ret = file_to_buf(STAT_FILE, buffer, sizeof(buffer)); +#endif + if (ret == -1) + return -1; + + switch (res_id) { + case RES_STAT_INFO: + cpu_num = sysconf(_SC_NPROCESSORS_ONLN); + cpu_size = sizeof(struct cpu_stat) * cpu_num; + CHECK_SIZE(sz, (sizeof(struct stat_info) + cpu_size)); + ret = populate_statinfo(out, 0); + break; + default: + eprintf("Resource Id is invalid"); + errno = EINVAL; + return -1; + + } + return ret; +} diff --git a/stat.h b/stat.h new file mode 100644 index 0000000..471f9e9 --- /dev/null +++ b/stat.h @@ -0,0 +1,26 @@ +/* Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved + * + * This file is part of libresource. + * + * libresource is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libresource is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libresource. If not, see . + */ + +#ifndef _STAT_H +#define _STAT_H + +#define STAT_FILE "/proc/stat" + +extern int getstatinfo(int res_id, void *out, size_t sz, void **hint, + int flags); +#endif /* _STAT_H */ diff --git a/tests/MEM/mem_test.c b/tests/MEM/mem_test.c index 718f19b..536b6e5 100644 --- a/tests/MEM/mem_test.c +++ b/tests/MEM/mem_test.c @@ -40,7 +40,10 @@ int main(int argc, char **argv) exit(1); } fp = fopen ("./mem_info.txt", "w"); - + if (fp == NULL) { + printf("mem_info.txt does not exist!\n"); + exit(1); + } if (exist.memtotal) fprintf(fp, "MemTotal: %lu kB\n", mem.memtotal); if (exist.memfree) diff --git a/tests/STAT/stat.sh b/tests/STAT/stat.sh new file mode 100755 index 0000000..efb2f3a --- /dev/null +++ b/tests/STAT/stat.sh @@ -0,0 +1,10 @@ +export LD_LIBRARY_PATH=`git rev-parse --show-toplevel` +cd $LD_LIBRARY_PATH +cd tests/STAT +rm -f stat_info.orig +rm -f stat_info.txt +cc -I $LD_LIBRARY_PATH -std=gnu99 -o stat_test stat_test.c -L $LD_LIBRARY_PATH -lresource +cat /proc/stat > stat_info.orig +./stat_test +diff stat_info.orig stat_info.txt + diff --git a/tests/STAT/stat_test.c b/tests/STAT/stat_test.c new file mode 100644 index 0000000..cc54b05 --- /dev/null +++ b/tests/STAT/stat_test.c @@ -0,0 +1,81 @@ +/* Copyright (C) 2023, Oracle and/or its affiliates. All rights reserved + * + * This file is part of libresource. + * + * libresource is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * libresource is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with libresource. If not, see . + */ + +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + struct stat_info stats, *st; + int cpu_num, size, err = 0; + FILE *fp; + char buf[36]; + struct cpu_stat *all_cpu; + + cpu_num = sysconf(_SC_NPROCESSORS_ONLN); + size = sizeof(struct cpu_stat) * cpu_num; + stats.all_cpu = (struct cpu_stat *) malloc(size); + err = res_read(RES_STAT_INFO, &stats, sizeof(stats)+size, NULL, 0, 0); + if (err != 0) + printf("err is %d\n",err); + st = &stats; + fp = fopen ("./stat_info.txt", "w"); + if (fp == NULL) { + printf("stat_info.txt does not exist!\n"); + exit(1); + } + fprintf(fp, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu\n", + st->cpu.user, + st->cpu.nice, + st->cpu.system, + st->cpu.idle, + st->cpu.iowait, + st->cpu.irq, + st->cpu.softirq, + st->cpu.steal, + st->cpu.guest, + st->cpu.guest_nice); + all_cpu = st->all_cpu; + for (int i = 0; i < cpu_num; i++) { + sprintf(buf, "cpu%d", i); + fprintf(fp, "%s %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu\n", + buf, + all_cpu->user, + all_cpu->nice, + all_cpu->system, + all_cpu->idle, + all_cpu->iowait, + all_cpu->irq, + all_cpu->softirq, + all_cpu->steal, + all_cpu->guest, + all_cpu->guest_nice); + all_cpu++; + } + fprintf(fp, "intr %s\n", st->intr); + fprintf(fp, "ctxt %Lu\n",st->ctxt); + fprintf(fp, "btime %Lu\n", st->btime); + fprintf(fp, "processes %Lu\n", st->processes); + fprintf(fp, "procs_running %Lu\n", st->procs_running); + fprintf(fp, "procs_blocked %Lu\n", st->procs_blocked); + fprintf(fp, "softirq %s\n", st->softirq); + fclose(fp); +}