varch/test/test_cpul.c
2024-11-16 13:36:54 +08:00

259 lines
6.3 KiB
C

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <math.h>
#include <pthread.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#if defined(TEST_TARGET_cpul)
#include <varch/command.h>
#include <varch/cpul.h>
#else
#include "init.h"
#include "command.h"
#include "cpul.h"
#endif
#define CORE_NUM_MAX 32
#define LINE_BUFFER_SIZE 1024
/**
* Structure for recording CPU counters in stat
*/
typedef struct {
uint64_t user; /**< Time spent in user mode */
uint64_t nice; /**< Time spent in low-priority user mode */
uint64_t system; /**< Time spent in system mode */
uint64_t idle; /**< Time spent waiting for tasks */
uint64_t iowait; /**< Time spent waiting for I/O to complete */
uint64_t irq; /**< Time spent processing interrupts */
uint64_t softirq; /**< Time spent processing soft interrupts */
uint64_t steal; /**< Time spent by other OS in virtual environment */
uint64_t guest; /**< Time spent running guest OS */
uint64_t guest_nice; /**< Time spent running low priority guest OS */
} cputime_t;
static uint16_t loadTable[CORE_NUM_MAX] = {0};
static cputime_t read_stat(int coreid)
{
cputime_t work;
FILE *file;
char line[LINE_BUFFER_SIZE];
file = fopen("/proc/stat", "rb");
if (file == NULL) {
}
if (fgets(line, sizeof(line), file) == NULL) {
goto error;
}
if (sscanf(line, "cpu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&work.user,
&work.nice,
&work.system,
&work.idle,
&work.iowait,
&work.irq,
&work.softirq,
&work.steal,
&work.guest,
&work.guest_nice) < 4) {
goto error;
}
if (coreid > 0)
{
int i;
for (i = 0; i < coreid; i++)
{
if (fgets(line, sizeof(line), file) == NULL)
{
goto error;
}
if (sscanf(line, "cpu%*u %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
&work.user,
&work.nice,
&work.system,
&work.idle,
&work.iowait,
&work.irq,
&work.softirq,
&work.steal,
&work.guest,
&work.guest_nice) < 4)
{
goto error;
}
}
}
error:
fclose(file);
return work;
}
void *loadupdate_entry(void *ptr)
{
const int coreNum = *(int *)ptr;
cputime_t before[coreNum], after[coreNum], diff[coreNum];
int i = 0;
while(1)
{
/* Calcul real time load */
for (i = 0; i < coreNum; i++) before[i] = read_stat(i);
usleep(1000000);
for (i = 0; i < coreNum; i++) after[i] = read_stat(i);
for (i = 0; i < coreNum; i++)
{
if (after[i].user > before[i].user && after[i].idle > before[i].idle)
{
diff[i].user = after[i].user - before[i].user;
diff[i].idle = after[i].idle - before[i].idle;
loadTable[i] = (uint16_t)(((float)(diff[i].user) / (float)(diff[i].user + diff[i].idle)) * 10000);
}
else
{
loadTable[i] = 0;
}
// printf("[core%d] load %d\r\n", i, loadTable[i]);
}
}
}
uint16_t cpul_raw(uint8_t coreid)
{
if (coreid >= CORE_NUM_MAX) return 0xFFFF;
return (uint16_t)(loadTable[coreid]);
}
void *loadgen_entry(void *ptr)
{
#define PERIOD 10
const int coreid = *(int *)ptr;
CPUL cpul;
int ret = 0;
uint32_t count = 0;
uint16_t load = 0;
cpul.coreid = coreid;
cpul.resolution = 10;
cpul.raw = cpul_raw;
ret = cpul_init(&cpul);
ret = cpul_set(&cpul, 5000);
while(1)
{
count += PERIOD;
if (count >= 25200000) count = 0;
if (count % 1000 == 0)
{
ret = cpul_get(&cpul, &load);
printf("cpul_get<%d> %2d.%02d%%, %d, %d\r\n", coreid, (uint16_t)(load / 100), load % 100, cpul.ctrl.tload, cpul.ctrl.refine);
}
cpul_task(&cpul);
usleep(1000 * PERIOD);
}
}
static void usage(void)
{
printf(
"Usage: cpul [opt] [arg]\n"
"\n"
"options:\n"
" -h Print help\n"
" -v Print version\n"
"\n"
"argument:\n"
" <read> Test default read function\n"
" <write> Test default write function\n"
);
}
static int test(int argc, char *argv[])
{
/* reset getopt */
command_opt_init();
while (1)
{
int opt = command_getopt(argc, argv, "hv");
if (opt == -1) break;
switch (opt)
{
case 'v' :
printf("cpul version %d.%d.%d\r\n", CPUL_V_MAJOR, CPUL_V_MINOR, CPUL_V_PATCH);
return 0;
case '?':
printf("Unknown option `%c`\r\n", command_optopt);
return -1;
case 'h' :
default:
usage();
return 0;
}
}
int num_cpus = sysconf(_SC_NPROCESSORS_CONF);
pthread_t thread_update, thread_gen[num_cpus];
int coreid[num_cpus];
int ret;
printf("Number of CPUs: %d\n", num_cpus);
ret = pthread_create(&thread_update, NULL, &loadupdate_entry, &num_cpus);
if (ret != 0) {
printf("pthread_create failed!\n");
}
for (int i = 0; i < num_cpus; i++)
{
coreid[i] = i;
ret = pthread_create(&thread_gen[i], NULL, &loadgen_entry, &coreid[i]);
if (ret != 0) {
printf("pthread_create failed!\n");
}
cpu_set_t cpuset;
CPU_ZERO(&cpuset);
CPU_SET(i, &cpuset);
sched_setaffinity(thread_gen[i], sizeof(cpu_set_t), &cpuset);
}
pthread_join(thread_update, NULL);
for (int i = 0; i < num_cpus; i++)
{
pthread_join(thread_gen[i], NULL);
}
return 0;
}
#if defined(TEST_TARGET_cpul)
int main(int argc, char *argv[])
{
return test(argc, argv);
}
#else
void test_cpul(void)
{
command_export("cpul", test);
}
init_export_app(test_cpul);
#endif