#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; }