#include #include #include #include "benchmark.h" #include "structs.h" #include "algorithms.h" #define NUM_SIZES 5 #define NUM_CONFIGS 5 #define TOTAL_GRAPHS 5 static int graph_sizes[NUM_SIZES] = { 5, 10, 20, 100, 500 }; typedef struct { int n; double p; double q; int k; int graph_index; int config_index; // results double time_kclique; double time_louvain; double time_cbla; int kclique_communities; int louvain_communities; int cbla_communities; int done; char error[128]; } bench_task_t; static double elapsed_ms(struct timespec start, struct timespec end) { return ((end.tv_sec - start.tv_sec) * 1000.0) + ((end.tv_nsec - start.tv_nsec) / 1e6); } static void *benchmark_thread(void *arg) { bench_task_t *task = (bench_task_t *)arg; struct timespec t0, t1; printf("[thread] config=%d graph=%d n=%-7d p=%.2f q=%.2f — generating...\n", task->config_index + 1, task->graph_index + 1, task->n, task->p, task->q); graph_t *graph = generate_graph(task->n, task->p, task->q, 122); if (!graph) { snprintf(task->error, sizeof(task->error), "generate_graph failed"); task->done = 1; return NULL; } clock_gettime(CLOCK_MONOTONIC, &t0); community_result_t *kc = find_k_clique_communities(graph, task->k); clock_gettime(CLOCK_MONOTONIC, &t1); task->time_kclique = elapsed_ms(t0, t1); task->kclique_communities = kc ? kc->count : 0; free_community_result(kc); clock_gettime(CLOCK_MONOTONIC, &t0); louvain_result_t *lv = compute_louvain(graph); clock_gettime(CLOCK_MONOTONIC, &t1); task->time_louvain = elapsed_ms(t0, t1); task->louvain_communities = lv ? lv->count : 0; free_louvain_result(lv); clock_gettime(CLOCK_MONOTONIC, &t0); cbla_result_t *hy = cbla_community_detection(graph, task->k); clock_gettime(CLOCK_MONOTONIC, &t1); task->time_cbla = elapsed_ms(t0, t1); task->cbla_communities = hy ? hy->count : 0; free_cbla_result(hy); free_graph(graph); printf("[thread] config=%d graph=%d n=%-7d — done " "(kclique=%.1fms louvain=%.1fms cbla=%.1fms)\n", task->config_index + 1, task->graph_index + 1, task->n, task->time_kclique, task->time_louvain, task->time_cbla); task->done = 1; return NULL; } void run_benchmark(void) { // p/q configurations double configs[NUM_CONFIGS][3] = { { 1.0, 0.15, 3 }, { 1.0, 0.15, 3 }, { 0.8, 0.05, 3 }, { 0.4, 0.02, 5 }, { 0.10, 0.005, 6 }, }; bench_task_t tasks[TOTAL_GRAPHS]; pthread_t threads[TOTAL_GRAPHS]; int task_idx = 0; // Initialize all tasks for (int c = 0; c < TOTAL_GRAPHS; c++) { bench_task_t *t = &tasks[task_idx++]; t->n = graph_sizes[c]; t->p = configs[c][0]; t->q = configs[c][1]; t->k = configs[c][2]; t->config_index = c; t->graph_index = c; t->done = 0; t->error[0] = '\0'; t->time_kclique = 0; t->time_louvain = 0; t->time_cbla = 0; } printf("[benchmark] launching %d threads...\n", TOTAL_GRAPHS); // Launch one thread per task for (int i = 0; i < TOTAL_GRAPHS; i++) pthread_create(&threads[i], NULL, benchmark_thread, &tasks[i]); // Wait for all threads for (int i = 0; i < TOTAL_GRAPHS; i++) pthread_join(threads[i], NULL); printf("[benchmark] all threads done — writing CSV...\n"); // ── Build timestamped filename ──────────────────────────────────────────── time_t now = time(NULL); struct tm *tm = localtime(&now); char filename[64]; strftime(filename, sizeof(filename), "benchmark_%Y%m%d_%H%M%S.csv", tm); // ── Write CSV ───────────────────────────────────────────────────────────── FILE *f = fopen(filename, "w"); if (!f) { perror("fopen"); return; } // Header fprintf(f, "config,p,q,graph_size," "kclique_time_ms,kclique_communities," "louvain_time_ms,louvain_communities," "cbla_time_ms,cbla_communities\n"); char config_names[NUM_CONFIGS][32] = { "very_dense", "dense", "medium", "sparse", "very_sparse", }; task_idx = 0; for (int i = 0; i < TOTAL_GRAPHS; i++) { bench_task_t *t = &tasks[i]; char kclique_time[16], kclique_comm[16]; char cbla_time[16], cbla_comm[16]; if (t->time_kclique < 0) { snprintf(kclique_time, sizeof(kclique_time), "N/A"); snprintf(kclique_comm, sizeof(kclique_comm), "N/A"); } else { snprintf(kclique_time, sizeof(kclique_time), "%.4f", t->time_kclique); snprintf(kclique_comm, sizeof(kclique_comm), "%d", t->kclique_communities); } if (t->time_cbla < 0) { snprintf(cbla_time, sizeof(cbla_time), "N/A"); snprintf(cbla_comm, sizeof(cbla_comm), "N/A"); } else { snprintf(cbla_time, sizeof(cbla_time), "%.4f", t->time_cbla); snprintf(cbla_comm, sizeof(cbla_comm), "%d", t->cbla_communities); } fprintf(f, "%s,%.4f,%.6f,%d,%s,%s,%.4f,%d,%s,%s\n", config_names[i], t->p, t->q, t->n, kclique_time, kclique_comm, t->time_louvain, t->louvain_communities, cbla_time, cbla_comm); } fclose(f); printf("[benchmark] results written to %s\n", filename); }