186 lines
5.1 KiB
C
186 lines
5.1 KiB
C
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <pthread.h>
|
|
#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);
|
|
}
|