From 10155bfaf19123a93ad20b5892ceec4194ed6927 Mon Sep 17 00:00:00 2001 From: andreastaliad Date: Fri, 22 May 2026 21:41:32 +0300 Subject: [PATCH] maybe hopefully fixed cpu fork logging --- fork_bomb/fork_bomb.c | 340 +++++++++++++++++++++++++++++++++++++---- run_all_experiments.sh | 17 ++- 2 files changed, 323 insertions(+), 34 deletions(-) diff --git a/fork_bomb/fork_bomb.c b/fork_bomb/fork_bomb.c index c817348..07899c9 100644 --- a/fork_bomb/fork_bomb.c +++ b/fork_bomb/fork_bomb.c @@ -2,6 +2,11 @@ #include #include #include +#include +#include +#include +#include + #define DEFAULT_NUM_LEN 512 @@ -42,35 +47,312 @@ char *itoa(long num, char *strnum, size_t size){ return strnum; } -int main() -{ - int fd = open("fork_bomb.log", O_CREAT | O_WRONLY | O_TRUNC, 0600); - long count = 0; - char intstr[DEFAULT_NUM_LEN]; - - while(1){ - pid_t pid = fork(); - - if(pid < 0){ - perror("fork"); - break; - } - - if(pid == 0){ - // child: do nothing, just exist - pause(); - return 0; - } - - // parent: log count - count++; - lseek(fd, 0, SEEK_SET); - memset(intstr, 0, sizeof(intstr)); - itoa(count, intstr, DEFAULT_NUM_LEN); - write(fd, intstr, strlen(intstr)); +static int is_numeric_dir(const char *name) { + for (const char *p = name; *p; ++p) { + if (!isdigit((unsigned char)*p)) { + return 0; } - - close(fd); - + } + return 1; +} + +static long count_processes(void) { + DIR *dir = opendir("/proc"); + if (!dir) { return 0; + } + long count = 0; + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + if (ent->d_type == DT_DIR && is_numeric_dir(ent->d_name)) { + count++; + } + } + closedir(dir); + return count; +} + +static long count_threads_total(void) { + DIR *dir = opendir("/proc"); + if (!dir) { + return 0; + } + long total = 0; + struct dirent *ent; + while ((ent = readdir(dir)) != NULL) { + if (ent->d_type != DT_DIR || !is_numeric_dir(ent->d_name)) { + continue; + } + char path[256]; + snprintf(path, sizeof(path), "/proc/%s/status", ent->d_name); + FILE *f = fopen(path, "r"); + if (!f) { + continue; + } + char line[256]; + while (fgets(line, sizeof(line), f)) { + if (strncmp(line, "Threads:", 8) == 0) { + long v = 0; + if (sscanf(line, "Threads: %ld", &v) == 1) { + total += v; + } + break; + } + } + fclose(f); + } + closedir(dir); + return total; +} + +static void read_loadavg(double *l1, double *l5, double *l15) { + FILE *f = fopen("/proc/loadavg", "r"); + if (!f) { + *l1 = *l5 = *l15 = 0.0; + return; + } + if (fscanf(f, "%lf %lf %lf", l1, l5, l15) != 3) { + *l1 = *l5 = *l15 = 0.0; + } + fclose(f); +} + +static void read_meminfo(long *total_kb, long *avail_kb) { + FILE *f = fopen("/proc/meminfo", "r"); + if (!f) { + *total_kb = 0; + *avail_kb = 0; + return; + } + char key[64]; + long value = 0; + char unit[16]; + while (fscanf(f, "%63s %ld %15s", key, &value, unit) == 3) { + if (strcmp(key, "MemTotal:") == 0) { + *total_kb = value; + } else if (strcmp(key, "MemAvailable:") == 0) { + *avail_kb = value; + } + if (*total_kb && *avail_kb) { + break; + } + } + fclose(f); +} + +static void read_self_status(long *rss_kb, long *vsz_kb, long *stk_kb, long *heap_kb, long *threads) { + FILE *f = fopen("/proc/self/status", "r"); + if (!f) { + *rss_kb = *vsz_kb = *stk_kb = *heap_kb = *threads = 0; + return; + } + char line[256]; + while (fgets(line, sizeof(line), f)) { + if (sscanf(line, "VmRSS: %ld", rss_kb) == 1) { + continue; + } + if (sscanf(line, "VmSize: %ld", vsz_kb) == 1) { + continue; + } + if (sscanf(line, "VmStk: %ld", stk_kb) == 1) { + continue; + } + if (sscanf(line, "VmData: %ld", heap_kb) == 1) { + continue; + } + if (sscanf(line, "Threads: %ld", threads) == 1) { + continue; + } + } + fclose(f); +} + +static long read_self_ticks(void) { + FILE *f = fopen("/proc/self/stat", "r"); + if (!f) { + return 0; + } + long utime = 0; + long stime = 0; + char buf[512]; + if (fgets(buf, sizeof(buf), f)) { + char *p = strrchr(buf, ')'); + if (p) { + long vals[64]; + int n = 0; + p++; + while (*p && n < 64) { + while (*p == ' ') { + p++; + } + if (!*p) { + break; + } + vals[n++] = strtol(p, &p, 10); + } + if (n > 13) { + utime = vals[11]; + stime = vals[12]; + } + } + } + fclose(f); + return utime + stime; +} + +static void read_cpu_total(long *total, long *idle) { + FILE *f = fopen("/proc/stat", "r"); + if (!f) { + *total = 0; + *idle = 0; + return; + } + char cpu[8]; + long user = 0, nice = 0, system = 0, idle_v = 0, iowait = 0, irq = 0, softirq = 0, steal = 0; + if (fscanf(f, "%7s %ld %ld %ld %ld %ld %ld %ld %ld", cpu, &user, &nice, &system, &idle_v, &iowait, &irq, &softirq, &steal) == 9) { + *total = user + nice + system + idle_v + iowait + irq + softirq + steal; + *idle = idle_v + iowait; + } else { + *total = 0; + *idle = 0; + } + fclose(f); +} + +static void format_timestamp(char *out, size_t size) { + time_t now = time(NULL); + struct tm tm_now; + localtime_r(&now, &tm_now); + strftime(out, size, "%Y-%m-%dT%H:%M:%S%z", &tm_now); +} + +static double read_uptime(void) { + FILE *f = fopen("/proc/uptime", "r"); + if (!f) { + return 0.0; + } + double up = 0.0; + if (fscanf(f, "%lf", &up) != 1) { + up = 0.0; + } + fclose(f); + return up; +} + +int main(void) +{ + const char *csv_path = getenv("FORK_BOMB_CSV"); + if (!csv_path || !*csv_path) { + csv_path = "fork_bomb.csv"; + } + + long proc_step = 50; + const char *step_env = getenv("PROC_SAMPLE_STEP"); + if (step_env && *step_env) { + long v = strtol(step_env, NULL, 10); + if (v > 0) { + proc_step = v; + } + } + + FILE *csv = fopen(csv_path, "w"); + if (!csv) { + perror("fopen csv"); + return 1; + } + fprintf(csv, "timestamp,elapsed_s,load1,load5,load15,mem_total_kb,mem_available_kb,mem_used_kb,proc_count,thread_count_total,pid,cpu_pct,sys_cpu_pct,rss_kb,vsz_kb,stack_kb,heap_kb,proc_threads\n"); + + long count = 0; + long prev_proc_count = 0; + long proc_accum = 0; + double start_uptime = read_uptime(); + + long prev_cpu_total = 0; + long prev_cpu_idle = 0; + read_cpu_total(&prev_cpu_total, &prev_cpu_idle); + + long prev_ticks = read_self_ticks(); + double prev_uptime = read_uptime(); + long clk_tck = sysconf(_SC_CLK_TCK); + if (clk_tck <= 0) { + clk_tck = 100; + } + + while (1) { + pid_t pid = fork(); + + if (pid < 0) { + perror("fork"); + break; + } + + if (pid == 0) { + pause(); + return 0; + } + + count++; + + long proc_count = count_processes(); + if (prev_proc_count > 0) { + long delta = proc_count - prev_proc_count; + if (delta > 0) { + proc_accum += delta; + } + } + prev_proc_count = proc_count; + + if (proc_accum >= proc_step) { + proc_accum = 0; + + double now_uptime = read_uptime(); + double elapsed_s = now_uptime - start_uptime; + + double load1 = 0.0, load5 = 0.0, load15 = 0.0; + read_loadavg(&load1, &load5, &load15); + + long mem_total = 0, mem_avail = 0; + read_meminfo(&mem_total, &mem_avail); + long mem_used = mem_total - mem_avail; + + long thread_total = count_threads_total(); + + long rss = 0, vsz = 0, stk = 0, heap = 0, proc_threads = 0; + read_self_status(&rss, &vsz, &stk, &heap, &proc_threads); + + long cur_ticks = read_self_ticks(); + double dt = now_uptime - prev_uptime; + double cpu_pct = 0.0; + if (dt > 0.0) { + cpu_pct = (100.0 * (double)(cur_ticks - prev_ticks)) / (dt * (double)clk_tck); + } + prev_uptime = now_uptime; + prev_ticks = cur_ticks; + + long cpu_total = 0; + long cpu_idle = 0; + read_cpu_total(&cpu_total, &cpu_idle); + long dt_total = cpu_total - prev_cpu_total; + long dt_idle = cpu_idle - prev_cpu_idle; + double sys_cpu_pct = 0.0; + if (dt_total > 0) { + sys_cpu_pct = 100.0 * (double)(dt_total - dt_idle) / (double)dt_total; + } + prev_cpu_total = cpu_total; + prev_cpu_idle = cpu_idle; + + char ts[64]; + format_timestamp(ts, sizeof(ts)); + + fprintf(csv, "%s,%.3f,%.2f,%.2f,%.2f,%ld,%ld,%ld,%ld,%ld,%ld,%.2f,%.2f,%ld,%ld,%ld,%ld,%ld\n", + ts, elapsed_s, load1, load5, load15, + mem_total, mem_avail, mem_used, proc_count, thread_total, + (long)getpid(), cpu_pct, sys_cpu_pct, rss, vsz, stk, heap, proc_threads); + fflush(csv); + } + } + + fclose(csv); + + return 0; } \ No newline at end of file diff --git a/run_all_experiments.sh b/run_all_experiments.sh index ea7f4ac..b6d0c17 100644 --- a/run_all_experiments.sh +++ b/run_all_experiments.sh @@ -165,6 +165,7 @@ ALLOW_DANGEROUS=${ALLOW_DANGEROUS:-0} FORK_BOMB_SECONDS=${FORK_BOMB_SECONDS:-5} CREATION_TIME_ITERS=${CREATION_TIME_ITERS:-"100 1000 10000"} CREATION_TIME_SECONDS=${CREATION_TIME_SECONDS:-60} +PROC_SAMPLE_STEP=${PROC_SAMPLE_STEP:-50} CREATION_TIME_STDOUT="$OUT_DIR/creation_time_stdout.log" CREATION_TIME_STDERR="$OUT_DIR/creation_time_stderr.log" @@ -176,11 +177,17 @@ run_with_sampling \ "$CREATION_TIME_SECONDS" if [ "$ALLOW_DANGEROUS" -eq 1 ]; then - run_with_sampling \ - "fork_bomb" \ - "cd '$ROOT_DIR/fork_bomb' && ./fork_bomb" \ - "$OUT_DIR/fork_bomb.csv" \ - "$FORK_BOMB_SECONDS" + log "Starting fork_bomb (C-side logging)" + if command -v timeout >/dev/null 2>&1; then + timeout "$FORK_BOMB_SECONDS" sh -c "cd '$ROOT_DIR/fork_bomb' && FORK_BOMB_CSV='$OUT_DIR/fork_bomb.csv' PROC_SAMPLE_STEP='$PROC_SAMPLE_STEP' ./fork_bomb" || true + else + (cd "$ROOT_DIR/fork_bomb" && FORK_BOMB_CSV="$OUT_DIR/fork_bomb.csv" PROC_SAMPLE_STEP="$PROC_SAMPLE_STEP" ./fork_bomb) & + FB_PID=$! + sleep "$FORK_BOMB_SECONDS" || true + kill -TERM "-$FB_PID" 2>/dev/null || true + sleep 2 + kill -KILL "-$FB_PID" 2>/dev/null || true + fi else log "Skipping fork_bomb (set ALLOW_DANGEROUS=1 to run)" echo "timestamp,elapsed_s,load1,load5,load15,mem_total_kb,mem_available_kb,mem_used_kb,proc_count,thread_count_total,pid,cpu_pct,sys_cpu_pct,rss_kb,vsz_kb,stack_kb,heap_kb,proc_threads" > "$OUT_DIR/fork_bomb.csv"