342 lines
7.6 KiB
C
342 lines
7.6 KiB
C
|
|
#define _GNU_SOURCE
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
#include <sys/resource.h>
|
|
#include <pthread.h>
|
|
#include <bpf/libbpf.h>
|
|
#include "ebpf.skel.h"
|
|
#include "event.h"
|
|
#include "data_structure/list_entry.h"
|
|
#include "container_worker.h"
|
|
|
|
#define MAX_CMD_LEN 512
|
|
|
|
LIST_ENTRY g_ContainerList;
|
|
|
|
PCONTAINER_WORKER
|
|
FindContainer(
|
|
const char *ContainerId)
|
|
{
|
|
if (IsListEmpty(&g_ContainerList))
|
|
return NULL;
|
|
|
|
PLIST_ENTRY Entry = g_ContainerList.flink;
|
|
|
|
while (Entry != &g_ContainerList)
|
|
{
|
|
|
|
PCONTAINER_WORKER Worker =
|
|
CONTAINING_RECORD(Entry, CONTAINER_WORKER, ListEntry);
|
|
|
|
if (strcmp(Worker->ContainerId, ContainerId) == 0)
|
|
return Worker;
|
|
|
|
Entry = Entry->flink;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void InsertContainer(
|
|
const char *ContainerId,
|
|
pid_t ContainerPid)
|
|
{
|
|
PCONTAINER_WORKER Worker =
|
|
(PCONTAINER_WORKER)malloc(sizeof(CONTAINER_WORKER));
|
|
|
|
if (!Worker)
|
|
return;
|
|
|
|
memset(Worker, 0, sizeof(CONTAINER_WORKER));
|
|
|
|
strncpy(Worker->ContainerId,
|
|
ContainerId,
|
|
MAX_CONTAINER_ID - 1);
|
|
|
|
Worker->ContainerPid = ContainerPid;
|
|
Worker->IsRunning = 1;
|
|
pthread_create(&Worker->MonitorThread, NULL,
|
|
ContainerWorkerEntry, Worker);
|
|
|
|
InsertTailList(&g_ContainerList, &Worker->ListEntry);
|
|
}
|
|
|
|
void RemoveContainer(
|
|
PCONTAINER_WORKER Worker)
|
|
{
|
|
|
|
Worker->IsRunning = 0;
|
|
pthread_join(Worker->MonitorThread, NULL);
|
|
RemoveEntryList(&Worker->ListEntry);
|
|
|
|
free(Worker);
|
|
}
|
|
|
|
void *delayed_free(void *arg)
|
|
{
|
|
PCONTAINER_WORKER Worker = (PCONTAINER_WORKER)arg;
|
|
|
|
usleep(EXIT_DELAY_MICROSECONDS);
|
|
|
|
RemoveContainer(Worker);
|
|
return NULL;
|
|
}
|
|
|
|
void RefreshContainerList(void)
|
|
{
|
|
|
|
FILE *Pipe = popen(
|
|
"docker inspect -f '{{.Name}} {{.State.Pid}}' $(docker ps -q) 2>/dev/null",
|
|
"r");
|
|
|
|
if (!Pipe)
|
|
{
|
|
perror("docker inspect failed");
|
|
return;
|
|
}
|
|
|
|
char Buffer[65536] = {0};
|
|
size_t Offset = 0;
|
|
while (fgets(Buffer + Offset, sizeof(Buffer) - Offset, Pipe))
|
|
{
|
|
Offset = strlen(Buffer); // 更新 Offset
|
|
if (Offset >= sizeof(Buffer) - 1)
|
|
break;
|
|
}
|
|
pclose(Pipe);
|
|
|
|
if (!IsListEmpty(&g_ContainerList))
|
|
{
|
|
PLIST_ENTRY Entry = g_ContainerList.flink;
|
|
while (Entry != &g_ContainerList)
|
|
{
|
|
PCONTAINER_WORKER Worker =
|
|
CONTAINING_RECORD(Entry, CONTAINER_WORKER, ListEntry);
|
|
Worker->ContainerPid = -1;
|
|
Entry = Entry->flink;
|
|
}
|
|
}
|
|
|
|
char *Line = strtok(Buffer, "\n");
|
|
while (Line)
|
|
{
|
|
char ContainerId[MAX_CONTAINER_ID];
|
|
int ContainerPid = -1;
|
|
|
|
if (sscanf(Line, "%64s %d", ContainerId, &ContainerPid) != 2)
|
|
{
|
|
Line = strtok(NULL, "\n");
|
|
continue;
|
|
}
|
|
|
|
if (ContainerId[0] == '/')
|
|
memmove(ContainerId, ContainerId + 1, strlen(ContainerId));
|
|
|
|
if (ContainerPid <= 0 || strncmp(ContainerId, "k8s", 3) == 0)
|
|
{
|
|
Line = strtok(NULL, "\n");
|
|
continue;
|
|
}
|
|
|
|
PCONTAINER_WORKER Worker = FindContainer(ContainerId);
|
|
if (Worker)
|
|
{
|
|
Worker->ContainerPid = ContainerPid;
|
|
}
|
|
else
|
|
{
|
|
InsertContainer(ContainerId, ContainerPid);
|
|
}
|
|
|
|
Line = strtok(NULL, "\n");
|
|
}
|
|
|
|
PLIST_ENTRY Entry = g_ContainerList.flink;
|
|
while (Entry != &g_ContainerList)
|
|
{
|
|
PCONTAINER_WORKER Worker =
|
|
CONTAINING_RECORD(Entry, CONTAINER_WORKER, ListEntry);
|
|
PLIST_ENTRY Next = Entry->flink;
|
|
|
|
if (Worker->ContainerPid == -1)
|
|
{
|
|
if(!Worker->Exited){
|
|
|
|
pthread_t tid;
|
|
pthread_create(&tid, NULL, delayed_free, Worker);
|
|
pthread_detach(tid);
|
|
}
|
|
//
|
|
|
|
Worker->Exited = 1;
|
|
}
|
|
|
|
Entry = Next;
|
|
}
|
|
}
|
|
|
|
static volatile sig_atomic_t exiting = 0;
|
|
|
|
static void handle_signal(int sig)
|
|
{
|
|
exiting = 1;
|
|
}
|
|
|
|
static int handle_event(void *ctx, void *data, size_t data_sz)
|
|
{
|
|
struct event *e = data;
|
|
pid_t pid = e->pid;
|
|
|
|
EbpfOpCode opcode = e->op;
|
|
|
|
if (IsListEmpty(&g_ContainerList))
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
int print = 0;
|
|
|
|
PLIST_ENTRY Entry = g_ContainerList.flink;
|
|
while (Entry != &g_ContainerList)
|
|
{
|
|
|
|
PCONTAINER_WORKER Worker =
|
|
CONTAINING_RECORD(Entry, CONTAINER_WORKER, ListEntry);
|
|
|
|
do
|
|
{
|
|
if (pid == Worker->ContainerPid)
|
|
{
|
|
print = 1;
|
|
break;
|
|
}
|
|
|
|
if (Worker->threads == NULL)
|
|
break;
|
|
|
|
PLIST_ENTRY Threads = Worker->threads->flink;
|
|
|
|
while (Threads != Worker->threads)
|
|
{
|
|
thread_perf_list *Thread =
|
|
CONTAINING_RECORD(Threads, thread_perf_list, entry);
|
|
if (pid == Thread->tid)
|
|
{
|
|
print = 1;
|
|
break;
|
|
}
|
|
Threads = Threads->flink;
|
|
}
|
|
} while (0);
|
|
|
|
if (print)
|
|
{
|
|
if (opcode == OPEN)
|
|
Worker->LibGPUCount++;
|
|
if (opcode == MMAP && strcmp(e->comm,"runc:[2:INIT]"))
|
|
{
|
|
Worker->MMAPSize += (unsigned long long)e->size;
|
|
}
|
|
if (opcode == MUNMAP && strcmp(e->comm,"runc:[2:INIT]"))
|
|
{
|
|
Worker->MMAPSize -= (unsigned long long)e->size;
|
|
}
|
|
break;
|
|
}
|
|
Entry = Entry->flink;
|
|
}
|
|
|
|
// if (print && e->op == MUNMAP && strcmp(e->comm,"python"))
|
|
// {
|
|
|
|
// printf(
|
|
// "pid=%u comm=%s size=%llu path=%s\n",
|
|
// pid,
|
|
// e->comm,
|
|
// (unsigned long long)e->size,
|
|
// e->path[0] ? e->path : "-");
|
|
// }
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main()
|
|
{
|
|
InitializeListHead(&g_ContainerList);
|
|
|
|
struct ebpf_bpf *skel;
|
|
struct ring_buffer *rb = NULL;
|
|
int err;
|
|
|
|
struct rlimit rlim = {
|
|
.rlim_cur = RLIM_INFINITY,
|
|
.rlim_max = RLIM_INFINITY,
|
|
};
|
|
setrlimit(RLIMIT_MEMLOCK, &rlim);
|
|
|
|
signal(SIGINT, handle_signal);
|
|
signal(SIGTERM, handle_signal);
|
|
|
|
skel = ebpf_bpf__open();
|
|
if (!skel)
|
|
{
|
|
fprintf(stderr, "Failed to open BPF skeleton\n");
|
|
return 1;
|
|
}
|
|
|
|
do
|
|
{
|
|
err = ebpf_bpf__load(skel);
|
|
if (err)
|
|
{
|
|
fprintf(stderr, "Failed to load BPF skeleton: %d\n", err);
|
|
break;
|
|
}
|
|
|
|
err = ebpf_bpf__attach(skel);
|
|
if (err)
|
|
{
|
|
fprintf(stderr, "Failed to attach BPF programs: %d\n", err);
|
|
break;
|
|
}
|
|
|
|
rb = ring_buffer__new(
|
|
bpf_map__fd(skel->maps.events),
|
|
handle_event,
|
|
NULL,
|
|
NULL);
|
|
if (!rb)
|
|
{
|
|
fprintf(stderr, "Failed to create ring buffer\n");
|
|
break;
|
|
}
|
|
setvbuf(stdout, NULL, _IONBF, 0);
|
|
printf("time,cid,tid,total,scalar,scalar_mac,pack_128,pack_256,pack_512,vector_mac,int_all,int_128,int_256,ex_ret_brn,ex_ret_brn_misp,libgpuopen,mmapsize\n");
|
|
while (!exiting)
|
|
{
|
|
RefreshContainerList();
|
|
err = ring_buffer__poll(rb, 10);
|
|
if (err == -EINTR)
|
|
break;
|
|
if (err < 0)
|
|
{
|
|
fprintf(stderr, "ring_buffer__poll error: %d\n", err);
|
|
break;
|
|
}
|
|
usleep(1000000);
|
|
}
|
|
} while (0);
|
|
|
|
ring_buffer__free(rb);
|
|
ebpf_bpf__destroy(skel);
|
|
return err < 0 ? -err : 0;
|
|
|
|
return 0;
|
|
}
|