mirror of
https://gitee.com/Lamdonn/varch.git
synced 2025-12-08 01:36:42 +08:00
259 lines
6.3 KiB
C
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
|