GPUSuitabilityEst/code/kernel_module/container_worker.c
2026-07-20 12:30:11 +01:00

262 lines
8.0 KiB
C

#define _GNU_SOURCE
#include "container_worker.h"
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
return syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags);
}
int open_perf_for_thread(thread_perf_list *t)
{
struct perf_event_attr pe[PERF_COUNT];
memset(pe, 0, sizeof(pe));
pe[PERF_TOTAL].type = PERF_TYPE_HARDWARE;
pe[PERF_TOTAL].size = sizeof(struct perf_event_attr);
pe[PERF_TOTAL].config = PERF_COUNT_HW_INSTRUCTIONS;
pe[PERF_SCALAR].type = PERF_TYPE_RAW;
pe[PERF_SCALAR].size = sizeof(struct perf_event_attr);
pe[PERF_SCALAR].config = 0x08 | (0x04 << 8);
pe[PERF_SCALAR_MAC].type = PERF_TYPE_RAW;
pe[PERF_SCALAR_MAC].size = sizeof(struct perf_event_attr);
pe[PERF_SCALAR_MAC].config = 0x0a | (0x04 << 8);
pe[PERF_PACK_128].type = PERF_TYPE_RAW;
pe[PERF_PACK_128].size = sizeof(struct perf_event_attr);
pe[PERF_PACK_128].config = 0x08 | (0x08 << 8);
pe[PERF_PACK_256].type = PERF_TYPE_RAW;
pe[PERF_PACK_256].size = sizeof(struct perf_event_attr);
pe[PERF_PACK_256].config = 0x08 | (0x10 << 8);
pe[PERF_PACK_512].type = PERF_TYPE_RAW;
pe[PERF_PACK_512].size = sizeof(struct perf_event_attr);
pe[PERF_PACK_512].config = 0x08 | (0x20 << 8);
pe[PERF_VECTOR_MAC].type = PERF_TYPE_RAW;
pe[PERF_VECTOR_MAC].size = sizeof(struct perf_event_attr);
pe[PERF_VECTOR_MAC].config = 0x0a | (0x40 << 8);
pe[PERF_INT_ALL].type = PERF_TYPE_RAW;
pe[PERF_INT_ALL].size = sizeof(struct perf_event_attr);
pe[PERF_INT_ALL].config = 0x0d | (0xff << 8);
pe[PERF_INT_128].type = PERF_TYPE_RAW;
pe[PERF_INT_128].size = sizeof(struct perf_event_attr);
pe[PERF_INT_128].config = 0x0d | (0x0f << 8);
pe[PERF_INT_256].type = PERF_TYPE_RAW;
pe[PERF_INT_256].size = sizeof(struct perf_event_attr);
pe[PERF_INT_256].config = 0x0d | (0xf0 << 8);
pe[PERF_EX_RET_BRN].type = PERF_TYPE_RAW;
pe[PERF_EX_RET_BRN].size = sizeof(struct perf_event_attr);
pe[PERF_EX_RET_BRN].config = 0xc2;
pe[PERF_EX_RET_BRN_MISP].type = PERF_TYPE_RAW;
pe[PERF_EX_RET_BRN_MISP].size = sizeof(struct perf_event_attr);
pe[PERF_EX_RET_BRN_MISP].config = 0xc3;
int failed = 0;
for (int i = 0; i < PERF_COUNT; i++)
{
t->fds[i] = perf_event_open(&pe[i], t->tid, -1, -1, 0);
if (t->fds[i] == -1)
failed = 1;
}
if (failed)
{
for (int i = 0; i < PERF_COUNT; i++)
if (t->fds[i] != -1)
close(t->fds[i]);
return -1;
}
for (int i = 0; i < PERF_COUNT; i++)
{
ioctl(t->fds[i], PERF_EVENT_IOC_RESET, 0);
ioctl(t->fds[i], PERF_EVENT_IOC_ENABLE, 0);
}
return 0;
}
// Free fds
void free_thread_perf(thread_perf_list *t)
{
for (int i = 0; i < PERF_COUNT; i++)
{
if (t->fds[i] != -1)
{
ioctl(t->fds[i], PERF_EVENT_IOC_DISABLE, 0);
close(t->fds[i]);
}
}
}
void print_perf_metrics(thread_perf_list *t, const char *cid,PCONTAINER_WORKER worker)
{
if (t->tid <= 0)
return;
uint64_t vals[PERF_COUNT];
memset(vals, 0, sizeof(vals));
uint64_t invalid = INVALID_COUNT;
for (int i = 0; i < PERF_COUNT; i++)
{
if (read(t->fds[i], &vals[i], sizeof(uint64_t)) == -1)
vals[i] = invalid;
}
time_t now = time(NULL);
char buf[64];
strftime(buf, sizeof(buf), "%Y%m%d%H%M%S", gmtime(&now));
/*
printf("[%s] TID %d:\n", buf, t->tid);
printf(" Total instructions: %lu\n", vals[PERF_TOTAL]);
printf(" Scalar FP instructions: %lu\n", vals[PERF_SCALAR]);
printf(" Scalar MAC/FMA: %lu\n", vals[PERF_SCALAR_MAC]);
printf(" 128-bit SIMD FP: %lu\n", vals[PERF_PACK_128]);
printf(" 256-bit SIMD FP: %lu\n", vals[PERF_PACK_256]);
printf(" 512-bit SIMD FP: %lu\n", vals[PERF_PACK_512]);
printf(" Vector MAC/FMA: %lu\n", vals[PERF_VECTOR_MAC]);
printf(" Packed Int (all): %lu\n", vals[PERF_INT_ALL]);
printf(" Packed Int 128-bit: %lu\n", vals[PERF_INT_128]);
printf(" Packed Int 256-bit: %lu\n", vals[PERF_INT_256]);
printf(" Branch Instructions: %lu\n", vals[PERF_EX_RET_BRN]);
printf(" Mispredicted Branch: %lu\n", vals[PERF_EX_RET_BRN_MISP]);
*/
for (int i = 0; i < PERF_COUNT; i++)
{
if (vals[i] != 0){
break;
}
return ;
}
printf("%s,%s,%d,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu,%lu\n",
buf, // 时间
cid, // 容器ID
t->tid, // TID
vals[PERF_TOTAL],
vals[PERF_SCALAR],
vals[PERF_SCALAR_MAC],
vals[PERF_PACK_128],
vals[PERF_PACK_256],
vals[PERF_PACK_512],
vals[PERF_VECTOR_MAC],
vals[PERF_INT_ALL],
vals[PERF_INT_128],
vals[PERF_INT_256],
vals[PERF_EX_RET_BRN],
vals[PERF_EX_RET_BRN_MISP],
worker->LibGPUCount,
worker->MMAPSize);
//if(worker->ContainerPid == t->tid)worker->MMAPSize=0;
}
void* delayed_free_perf(void* arg) {
thread_perf_list* t = (thread_perf_list*)arg;
usleep(EXIT_DELAY_MICROSECONDS);
RemoveEntryList(&t->entry);
free_thread_perf(t);
free(t);
return NULL;
}
void monitor_threads_dynamic(PCONTAINER_WORKER worker)
{
pid_t root_pid = worker->ContainerPid;
volatile int *IsRunning = &worker->IsRunning;
const char *cid = worker->ContainerId;
LIST_ENTRY thread_head;
InitializeListHead(&thread_head);
worker->threads = &thread_head;
while (*IsRunning)
{
pprocess_list plist = GetAllProcessAndThreadByPID(root_pid);
if (!plist)
continue;
PLIST_ENTRY iter = plist->entry.flink;
while (iter != &plist->entry)
{
pprocess_list node = CONTAINING_RECORD(iter, process_list, entry);
pid_t tid = node->pid;
if (tid <= 0)
{
iter = iter->flink;
continue;
}
thread_perf_list *pos;
int found = 0;
PLIST_ENTRY p = thread_head.flink;
while (p != &thread_head)
{
pos = CONTAINING_RECORD(p, thread_perf_list, entry);
if (pos->tid == tid)
{
found = 1;
break;
}
p = p->flink;
}
if (!found)
{
thread_perf_list *t = malloc(sizeof(*t));
memset(t, -1, sizeof(*t));
t->tid = tid;
if (open_perf_for_thread(t) == 0)
{
InsertTailList(&thread_head, &t->entry);
}
else
free(t);
}
iter = iter->flink;
}
FreeProcessOrThreadList(plist);
PLIST_ENTRY p = thread_head.flink;
while (p != &thread_head)
{
thread_perf_list *t = CONTAINING_RECORD(p, thread_perf_list, entry);
PLIST_ENTRY next = p->flink;
if (kill(t->tid, 0) == -1 && errno == ESRCH)
{
if(!t->Exited){
pthread_t tid;
pthread_create(&tid, NULL, delayed_free_perf, t);
pthread_detach(tid);
}
t->Exited = 1;
}
print_perf_metrics(t, cid,worker);
p = next;
}
usleep(CONTAINER_INFO_REFRESH_INTERVAL);
}
PLIST_ENTRY p = thread_head.flink;
while (p != &thread_head)
{
thread_perf_list *t = CONTAINING_RECORD(p, thread_perf_list, entry);
PLIST_ENTRY next = p->flink;
RemoveEntryList(&t->entry);
free_thread_perf(t);
free(t);
p = next;
}
}
void *ContainerWorkerEntry(void *wrk)
{
PCONTAINER_WORKER worker = (PCONTAINER_WORKER)wrk;
monitor_threads_dynamic(worker);
return NULL;
}