varch/test/test_cpul.c

388 lines
9.9 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>
// #ifdef _WIN32
// #include <Windows.h>
// #include <windows.h>
// #endif
#if defined(TEST_TARGET_cpul)
#include <varch/command.h>
#include <varch/unitt.h>
#include <varch/cpul.h>
#else
#include "init.h"
#include "command.h"
#include "unitt.h"
#include "kern.h"
#include "cpul.h"
#endif
/************************************************************************************/
/************************************* Unit Test ************************************/
/************************************************************************************/
// #define EXIT_TEST
extern uint64_t unitt_clock(void);
static int test_0(void)
{
for (int i = 0; i < 100; i++)
{
if (0)
{
#if defined (EXIT_TEST)
exit(0);
#endif
return UNITT_E_FAIL;
}
}
return UNITT_E_OK;
}
static void unitt_task(void)
{
static UNITT_TCASE rand_tests[] = {
UNITT_TCASE(test_0),
// UNITT_TCASE(test_1),
// UNITT_TCASE(test_2),
};
static UNITT suites[] = {
{ "xxx suite", rand_tests, sizeof(rand_tests) / sizeof(rand_tests[0]) , unitt_clock },
};
UNITT_EXE(suites);
}
/************************************************************************************/
/************************************* Base Test ************************************/
/************************************************************************************/
#ifdef _WIN32
uint16_t cpul_raw(uint8_t coreid)
{
FILETIME idleTime, kernelTime, userTime;
if (GetSystemTimes(&idleTime, &kernelTime, &userTime) == 0) {
printf("Failed to get system times\n");
return 1;
}
ULARGE_INTEGER idle, kernel, user;
idle.LowPart = idleTime.dwLowDateTime;
idle.HighPart = idleTime.dwHighDateTime;
kernel.LowPart = kernelTime.dwLowDateTime;
kernel.HighPart = kernelTime.dwHighDateTime;
user.LowPart = userTime.dwLowDateTime;
user.HighPart = userTime.dwHighDateTime;
ULONGLONG totalSystemTime = kernel.QuadPart + user.QuadPart;
ULONGLONG totalIdleTime = idle.QuadPart;
// Calculate CPU usage percentage
double cpuUsage = (double)(totalSystemTime - totalIdleTime) * 10000.0 / totalSystemTime;
return (uint16_t)cpuUsage;
}
#else
#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);
}
}
#endif
static void test_base(void)
{
#ifdef _WIN32
printf("cpul %u\r\n", cpul_raw(0));
#else
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);
}
#endif
}
/************************************************************************************/
/************************************* Command ************************************/
/************************************************************************************/
static void usage(void)
{
printf(
"Usage: cpul [opt] [arg] ...\n"
"\n"
"options:\n"
" -e <execute> Specifies the function to execute, the default is the <base> test\n"
" <base> Test base function\n"
" <ut> Unit test\n"
" -h Print help\n"
" -v Print version\n"
" -u [<period>] Unit test period, unit ms, the default is 1000ms\n"
"\n"
);
}
static int test(int argc, char *argv[])
{
char *execute = NULL;
int ut_period = 1000;
/* reset getopt */
command_opt_init();
while (1)
{
int opt = command_getopt(argc, argv, "e:hvu::");
if (opt == -1) break;
switch (opt)
{
case 'u' :
if (command_optarg) ut_period = atoi(command_optarg);
break;
case 'e' :
execute = command_optarg;
break;
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;
}
}
if (execute)
{
if (!strcmp(execute, "base"))
{
test_base();
}
else if (!strcmp(execute, "ut"))
{
#if defined(TEST_TARGET_cpul)
while (1)
{
unitt_task();
usleep(1000 * ut_period);
}
#else
printf("create task %d\r\n", task_create(ut_period, unitt_task));
#endif
}
}
else
{
test_base();
}
return 0;
}
/************************************************************************************/
/************************************ Test entry ************************************/
/************************************************************************************/
#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