mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-06 16:56:42 +08:00
388 lines
9.9 KiB
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
|