maybe hopefully fixed cpu fork logging
This commit is contained in:
+297
-15
@@ -2,6 +2,11 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_NUM_LEN 512
|
#define DEFAULT_NUM_LEN 512
|
||||||
|
|
||||||
@@ -42,35 +47,312 @@ char *itoa(long num, char *strnum, size_t size){
|
|||||||
return strnum;
|
return strnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
static int is_numeric_dir(const char *name) {
|
||||||
{
|
for (const char *p = name; *p; ++p) {
|
||||||
int fd = open("fork_bomb.log", O_CREAT | O_WRONLY | O_TRUNC, 0600);
|
if (!isdigit((unsigned char)*p)) {
|
||||||
long count = 0;
|
return 0;
|
||||||
char intstr[DEFAULT_NUM_LEN];
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
while(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();
|
pid_t pid = fork();
|
||||||
|
|
||||||
if(pid < 0){
|
if (pid < 0) {
|
||||||
perror("fork");
|
perror("fork");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(pid == 0){
|
if (pid == 0) {
|
||||||
// child: do nothing, just exist
|
|
||||||
pause();
|
pause();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parent: log count
|
|
||||||
count++;
|
count++;
|
||||||
lseek(fd, 0, SEEK_SET);
|
|
||||||
memset(intstr, 0, sizeof(intstr));
|
long proc_count = count_processes();
|
||||||
itoa(count, intstr, DEFAULT_NUM_LEN);
|
if (prev_proc_count > 0) {
|
||||||
write(fd, intstr, strlen(intstr));
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close(fd);
|
fclose(csv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
+12
-5
@@ -165,6 +165,7 @@ ALLOW_DANGEROUS=${ALLOW_DANGEROUS:-0}
|
|||||||
FORK_BOMB_SECONDS=${FORK_BOMB_SECONDS:-5}
|
FORK_BOMB_SECONDS=${FORK_BOMB_SECONDS:-5}
|
||||||
CREATION_TIME_ITERS=${CREATION_TIME_ITERS:-"100 1000 10000"}
|
CREATION_TIME_ITERS=${CREATION_TIME_ITERS:-"100 1000 10000"}
|
||||||
CREATION_TIME_SECONDS=${CREATION_TIME_SECONDS:-60}
|
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_STDOUT="$OUT_DIR/creation_time_stdout.log"
|
||||||
CREATION_TIME_STDERR="$OUT_DIR/creation_time_stderr.log"
|
CREATION_TIME_STDERR="$OUT_DIR/creation_time_stderr.log"
|
||||||
@@ -176,11 +177,17 @@ run_with_sampling \
|
|||||||
"$CREATION_TIME_SECONDS"
|
"$CREATION_TIME_SECONDS"
|
||||||
|
|
||||||
if [ "$ALLOW_DANGEROUS" -eq 1 ]; then
|
if [ "$ALLOW_DANGEROUS" -eq 1 ]; then
|
||||||
run_with_sampling \
|
log "Starting fork_bomb (C-side logging)"
|
||||||
"fork_bomb" \
|
if command -v timeout >/dev/null 2>&1; then
|
||||||
"cd '$ROOT_DIR/fork_bomb' && ./fork_bomb" \
|
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
|
||||||
"$OUT_DIR/fork_bomb.csv" \
|
else
|
||||||
"$FORK_BOMB_SECONDS"
|
(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
|
else
|
||||||
log "Skipping fork_bomb (set ALLOW_DANGEROUS=1 to run)"
|
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"
|
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"
|
||||||
|
|||||||
Reference in New Issue
Block a user