Загрузка данных


#include <libunwind.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdatomic.h>

#define MAX_EDGES 64
#define MAX_NAME 128
#define SAMPLE_US 200000
#define DRAW_US 300000

typedef struct {
    char caller[MAX_NAME];
    char callee[MAX_NAME];
    unsigned long hits;
} Edge;

static Edge edges[MAX_EDGES];
static int cnt = 0;
static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static atomic_int run = 1;

// Capture stack and merge into shared graph
static void capture(void) {
    unw_context_t ctx;
    unw_cursor_t cur;
    unw_getcontext(&ctx);
    unw_init_local(&cur, &ctx);

    char stk[16][MAX_NAME];
    int n = 0;
    while (unw_step(&cur) > 0 && n < 16) {
        unw_word_t ip;
        unw_get_reg(&cur, UNW_REG_IP, &ip);
        stk[n][0] = '\0';
        if (unw_get_proc_name(&cur, stk[n], MAX_NAME, NULL) != 0)
            snprintf(stk[n], MAX_NAME, "0x%lx", (unsigned long)ip);
        n++;
    }

    pthread_mutex_lock(&lock);
    for (int i = 1; i < n; i++) {
        int found = 0;
        for (int j = 0; j < cnt; j++) {
            if (strcmp(edges[j].caller, stk[i]) == 0 && strcmp(edges[j].callee, stk[i-1]) == 0) {
                edges[j].hits++;
                found = 1;
                break;
            }
        }
        if (!found && cnt < MAX_EDGES) {
            strncpy(edges[cnt].caller, stk[i], MAX_NAME - 1);
            strncpy(edges[cnt].callee, stk[i-1], MAX_NAME - 1);
            edges[cnt].hits = 1;
            cnt++;
        }
    }
    pthread_mutex_unlock(&lock);
}

// Synthetic call tree
static void leaf(void) { usleep(50); }
static void mid(void) { leaf(); leaf(); }
static void root(void) { mid(); leaf(); }

// Worker: executes workload and triggers sampling
static void* worker(void* arg) {
    (void)arg;
    while (atomic_load(&run)) {
        root();
        capture();
        usleep(1000);
    }
    return NULL;
}

// Renderer: clears terminal and prints live graph
static void* renderer(void* arg) {
    (void)arg;
    while (atomic_load(&run)) {
        printf("\033[2J\033[H");
        pthread_mutex_lock(&lock);
        printf("LIVE CALL GRAPH\n---\n");
        for (int i = 0; i < cnt; i++)
            printf("%s -> %s [%lu]\n", edges[i].caller, edges[i].callee, edges[i].hits);
        pthread_mutex_unlock(&lock);
        fflush(stdout);
        usleep(DRAW_US);
    }
    return NULL;
}

int main(void) {
    pthread_t w, r;
    pthread_create(&w, NULL, worker, NULL);
    pthread_create(&r, NULL, renderer, NULL);
    
    sleep(5);
    atomic_store(&run, 0);
    pthread_join(w, NULL);
    pthread_join(r, NULL);
    return 0;
}

// Compile: gcc -O2 -g -rdynamic main.c -o live_graph -lunwind -lunwind-x86_64 -lpthread
// Run: ./live_graph
// Note: Uses ANSI escape codes for terminal refresh. Requires x86_64 Linux.