#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include // #ifdef _WIN32 // #include // #include // #endif #if defined(TEST_TARGET_cpul) #include #include #include #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 Specifies the function to execute, the default is the test\n" " Test base function\n" " Unit test\n" " -h Print help\n" " -v Print version\n" " -u [] 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