262 lines
8.0 KiB
C
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;
|
|
}
|