From 32d3d5f97c30937d6b4ca9379350702c09c06ffa Mon Sep 17 00:00:00 2001 From: andreastaliad Date: Thu, 28 May 2026 23:40:52 +0300 Subject: [PATCH] added standalone run scripts for all tests and experiments --- creation_time_experiment/run_creation_time.sh | 154 ++++++++++++++ fork_bomb/run_fork_bomb.sh | 48 +++++ .../run_thread_recursive.sh | 200 +++++++++++------- 3 files changed, 320 insertions(+), 82 deletions(-) create mode 100755 creation_time_experiment/run_creation_time.sh create mode 100755 fork_bomb/run_fork_bomb.sh diff --git a/creation_time_experiment/run_creation_time.sh b/creation_time_experiment/run_creation_time.sh new file mode 100755 index 0000000..362afdc --- /dev/null +++ b/creation_time_experiment/run_creation_time.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +set -euo pipefail +LC_ALL=C + +DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +cd "$DIR" + +gcc -O2 -pthread -o creation_time creation_time.c + +echo "Compiled creation_time" + +CREATION_TIME_ITERS=${CREATION_TIME_ITERS:-"100 1000 10000"} +CREATION_TIME_SECONDS=${CREATION_TIME_SECONDS:-60} + +RUNS_DIR="$DIR/runs" +mkdir -p "$RUNS_DIR" +RUN_ID=$(date +"%Y%m%d_%H%M%S") +RUN_OUT="$RUNS_DIR/$RUN_ID" +mkdir -p "$RUN_OUT" + +LOG_FILE="$RUN_OUT/activity.log" +CSV="$RUN_OUT/creation_time.csv" +STDOUT_LOG="$RUN_OUT/creation_time_stdout.log" +STDERR_LOG="$RUN_OUT/creation_time_stderr.log" + +log() { + echo "[$(date -Iseconds)] $*" | tee -a "$LOG_FILE" +} + +count_processes() { + ls -d /proc/[0-9]* 2>/dev/null | wc -l +} + +count_threads_total() { + awk '/^Threads:/ {sum+=$2} END {print sum+0}' /proc/[0-9]*/status 2>/dev/null || echo 0 +} + +get_mem_kb() { + awk '/^MemTotal:/ {t=$2} /^MemAvailable:/ {a=$2} END {print t" "a}' /proc/meminfo +} + +sample_process_csv() { + local pid="$1" + local csv="$2" + local start_uptime="$3" + local max_seconds="$4" + + local have_pidstat=0 + if command -v pidstat >/dev/null 2>&1; then + have_pidstat=1 + else + log "pidstat not found; install sysstat for accurate CPU sampling" + fi + + local prev_cpu_total=0 + local prev_cpu_idle=0 + if [ -r /proc/stat ]; then + read -r _ c_user c_nice c_system c_idle c_iowait c_irq c_softirq c_steal _ _ < /proc/stat + prev_cpu_total=$((c_user + c_nice + c_system + c_idle + c_iowait + c_irq + c_softirq + c_steal)) + prev_cpu_idle=$((c_idle + c_iowait)) + fi + + while kill -0 "$pid" 2>/dev/null; do + local now_uptime elapsed_s + now_uptime=$(awk '{print $1}' /proc/uptime) + elapsed_s=$(awk -v s="$start_uptime" -v n="$now_uptime" 'BEGIN{printf "%.3f", (n-s)}') + + if [ "$max_seconds" -gt 0 ]; then + if awk -v e="$elapsed_s" -v m="$max_seconds" 'BEGIN{exit (e>m)?0:1}'; then + log "Timeout reached (${max_seconds}s), stopping PID=$pid" + kill -TERM "-$pid" 2>/dev/null || true + sleep 2 + kill -KILL "-$pid" 2>/dev/null || true + break + fi + fi + + local proc_count thread_total + proc_count=$(count_processes || echo 0) + thread_total=$(count_threads_total || echo 0) + + local load1 load5 load15 + read -r load1 load5 load15 _ < /proc/loadavg + + local mem_total mem_avail mem_used + read -r mem_total mem_avail < <(get_mem_kb || echo "0 0") + mem_used=$((mem_total - mem_avail)) + + local cpu rss vsz nlwp + rss=$(awk '/^VmRSS:/ {print $2}' "/proc/$pid/status" 2>/dev/null || echo 0) + vsz=$(awk '/^VmSize:/ {print $2}' "/proc/$pid/status" 2>/dev/null || echo 0) + nlwp=$(awk '/^Threads:/ {print $2}' "/proc/$pid/status" 2>/dev/null || echo 0) + if [ "$have_pidstat" -eq 1 ]; then + cpu=$(pidstat -p "$pid" 1 1 2>/dev/null | awk -v p="$pid" '$1 ~ /^[0-9]/ && $3==p {print $8; exit}') + cpu=${cpu:-0.00} + else + cpu=0.00 + fi + local stk=0 heap=0 + + local sys_cpu_pct=0.00 + if [ -r /proc/stat ]; then + read -r _ c_user c_nice c_system c_idle c_iowait c_irq c_softirq c_steal _ _ < /proc/stat + local cpu_total=$((c_user + c_nice + c_system + c_idle + c_iowait + c_irq + c_softirq + c_steal)) + local cpu_idle=$((c_idle + c_iowait)) + local dt_total=$((cpu_total - prev_cpu_total)) + local dt_idle=$((cpu_idle - prev_cpu_idle)) + sys_cpu_pct=$(awk -v t="$dt_total" -v i="$dt_idle" 'BEGIN{ if (t<=0) printf "0.00"; else printf "%.2f", (100.0*(t-i))/t }') + prev_cpu_total=$cpu_total + prev_cpu_idle=$cpu_idle + fi + + printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \ + "$(date -Iseconds)" "$elapsed_s" "$load1" "$load5" "$load15" \ + "$mem_total" "$mem_avail" "$mem_used" "$proc_count" "$thread_total" \ + "$pid" "$cpu" "$sys_cpu_pct" "${rss:-0}" "${vsz:-0}" "${stk:-0}" "${heap:-0}" "${nlwp:-0}" \ + >> "$csv" + + sleep 0.2 + done +} + +CMD="cd '$DIR' && { for n in $CREATION_TIME_ITERS; do echo \"=== iterations=\$n ===\"; ./creation_time -n \"\$n\"; done; } >'$STDOUT_LOG' 2>'$STDERR_LOG'" + +log "Starting creation_time: $CMD" + +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" > "$CSV" + +START_UPTIME=$(awk '{print $1}' /proc/uptime) + +if command -v setsid >/dev/null 2>&1; then + setsid bash -c "$CMD" & + PID=$! +else + bash -c "$CMD" & + PID=$! +fi + +sample_process_csv "$PID" "$CSV" "$START_UPTIME" "$CREATION_TIME_SECONDS" + +set +e +wait "$PID" +EXIT_CODE=$? +set -e + +log "Finished creation_time (exit_code=$EXIT_CODE)" + +echo +echo "Run complete" +echo " stdout: $STDOUT_LOG" +echo " stderr: $STDERR_LOG" +echo " samples: $CSV" +echo " log: $LOG_FILE" +echo " exit_code=$EXIT_CODE" diff --git a/fork_bomb/run_fork_bomb.sh b/fork_bomb/run_fork_bomb.sh new file mode 100755 index 0000000..69d7aa2 --- /dev/null +++ b/fork_bomb/run_fork_bomb.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +set -euo pipefail +LC_ALL=C + +DIR=$(cd "$(dirname "$0")" && pwd) +cd "$DIR" + +gcc -O2 -o fork_bomb fork_bomb.c + +echo "Compiled fork_bomb" + +# This experiment is dangerous: it forks processes until the OS limit is hit. +# You MUST set ALLOW_DANGEROUS=1 to run it. +ALLOW_DANGEROUS=${ALLOW_DANGEROUS:-0} +FORK_BOMB_SECONDS=${FORK_BOMB_SECONDS:-5} +PROC_SAMPLE_STEP=${PROC_SAMPLE_STEP:-50} + +RUNS_DIR="$DIR/runs" +mkdir -p "$RUNS_DIR" +RUN_ID=$(date +"%Y%m%d_%H%M%S") + +OUT_CSV="$RUNS_DIR/${RUN_ID}_fork_bomb.csv" + +if [ "$ALLOW_DANGEROUS" -ne 1 ]; then + echo "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,forks_per_sec,rss_kb,vsz_kb,stack_kb,heap_kb,proc_threads" > "$OUT_CSV" + echo " csv: $OUT_CSV" + exit 0 +fi + +echo "Running fork_bomb for ${FORK_BOMB_SECONDS}s (PROC_SAMPLE_STEP=$PROC_SAMPLE_STEP)" +echo " csv: $OUT_CSV" + +if command -v timeout >/dev/null 2>&1; then + timeout "$FORK_BOMB_SECONDS" sh -c "FORK_BOMB_CSV='$OUT_CSV' PROC_SAMPLE_STEP='$PROC_SAMPLE_STEP' '$DIR/fork_bomb'" || true +else + FORK_BOMB_CSV="$OUT_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 + +pkill -f "./fork_bomb" 2>/dev/null || true + +echo "Run complete" +echo " csv: $OUT_CSV" diff --git a/thread_recursive_scaling/run_thread_recursive.sh b/thread_recursive_scaling/run_thread_recursive.sh index 7889566..307fa7e 100755 --- a/thread_recursive_scaling/run_thread_recursive.sh +++ b/thread_recursive_scaling/run_thread_recursive.sh @@ -2,7 +2,7 @@ set -euo pipefail LC_ALL=C -DIR=$(cd "$(dirname "$0")" && pwd) +DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) cd "$DIR" gcc -O2 -pthread -o thread_recursive thread_recursive.c -lm @@ -18,103 +18,139 @@ BRANCH=${1:-6} DEPTH=${2:-6} HOLD=${3:-6} -RESULTS_CSV="$DIR/results.csv" RUNS_DIR="$DIR/runs" mkdir -p "$RUNS_DIR" - RUN_ID=$(date +"%Y%m%d_%H%M%S") -STDOUT_LOG="$RUNS_DIR/${RUN_ID}_stdout.log" -STDERR_LOG="$RUNS_DIR/${RUN_ID}_stderr.log" -SAMPLE_LOG="$RUNS_DIR/${RUN_ID}_samples.csv" +RUN_OUT="$RUNS_DIR/$RUN_ID" +mkdir -p "$RUN_OUT" -if [ ! -f "$RESULTS_CSV" ]; then - echo "run_id,timestamp,host,kernel,branch,depth,hold_s,exit_code,wall_s,max_rss_kb,max_vsz_kb,max_threads,avg_cpu,max_cpu,total_created_threads,estimated_full_tree" > "$RESULTS_CSV" -fi +LOG_FILE="$RUN_OUT/activity.log" +CSV="$RUN_OUT/thread_recursive_scaling.csv" -echo "Running: ./thread_recursive -b $BRANCH -d $DEPTH -s $HOLD" +log() { + echo "[$(date -Iseconds)] $*" | tee -a "$LOG_FILE" +} + +count_processes() { + ls -d /proc/[0-9]* 2>/dev/null | wc -l +} + +count_threads_total() { + awk '/^Threads:/ {sum+=$2} END {print sum+0}' /proc/[0-9]*/status 2>/dev/null || echo 0 +} + +get_mem_kb() { + awk '/^MemTotal:/ {t=$2} /^MemAvailable:/ {a=$2} END {print t" "a}' /proc/meminfo +} + +sample_process_csv() { + local pid="$1" + local csv="$2" + local start_uptime="$3" + local max_seconds="$4" + + local have_pidstat=0 + if command -v pidstat >/dev/null 2>&1; then + have_pidstat=1 + else + log "pidstat not found; install sysstat for accurate CPU sampling" + fi + + local prev_cpu_total=0 + local prev_cpu_idle=0 + if [ -r /proc/stat ]; then + read -r _ c_user c_nice c_system c_idle c_iowait c_irq c_softirq c_steal _ _ < /proc/stat + prev_cpu_total=$((c_user + c_nice + c_system + c_idle + c_iowait + c_irq + c_softirq + c_steal)) + prev_cpu_idle=$((c_idle + c_iowait)) + fi + + while kill -0 "$pid" 2>/dev/null; do + local now_uptime elapsed_s + now_uptime=$(awk '{print $1}' /proc/uptime) + elapsed_s=$(awk -v s="$start_uptime" -v n="$now_uptime" 'BEGIN{printf "%.3f", (n-s)}') + + if [ "$max_seconds" -gt 0 ]; then + if awk -v e="$elapsed_s" -v m="$max_seconds" 'BEGIN{exit (e>m)?0:1}'; then + log "Timeout reached (${max_seconds}s), stopping PID=$pid" + kill -TERM "-$pid" 2>/dev/null || true + sleep 2 + kill -KILL "-$pid" 2>/dev/null || true + break + fi + fi + + local proc_count thread_total + proc_count=$(count_processes || echo 0) + thread_total=$(count_threads_total || echo 0) + + local load1 load5 load15 + read -r load1 load5 load15 _ < /proc/loadavg + + local mem_total mem_avail mem_used + read -r mem_total mem_avail < <(get_mem_kb || echo "0 0") + mem_used=$((mem_total - mem_avail)) + + local cpu rss vsz nlwp + rss=$(awk '/^VmRSS:/ {print $2}' "/proc/$pid/status" 2>/dev/null || echo 0) + vsz=$(awk '/^VmSize:/ {print $2}' "/proc/$pid/status" 2>/dev/null || echo 0) + nlwp=$(awk '/^Threads:/ {print $2}' "/proc/$pid/status" 2>/dev/null || echo 0) + if [ "$have_pidstat" -eq 1 ]; then + cpu=$(pidstat -p "$pid" 1 1 2>/dev/null | awk -v p="$pid" '$1 ~ /^[0-9]/ && $3==p {print $8; exit}') + cpu=${cpu:-0.00} + else + cpu=0.00 + fi + local stk=0 heap=0 + + local sys_cpu_pct=0.00 + if [ -r /proc/stat ]; then + read -r _ c_user c_nice c_system c_idle c_iowait c_irq c_softirq c_steal _ _ < /proc/stat + local cpu_total=$((c_user + c_nice + c_system + c_idle + c_iowait + c_irq + c_softirq + c_steal)) + local cpu_idle=$((c_idle + c_iowait)) + local dt_total=$((cpu_total - prev_cpu_total)) + local dt_idle=$((cpu_idle - prev_cpu_idle)) + sys_cpu_pct=$(awk -v t="$dt_total" -v i="$dt_idle" 'BEGIN{ if (t<=0) printf "0.00"; else printf "%.2f", (100.0*(t-i))/t }') + prev_cpu_total=$cpu_total + prev_cpu_idle=$cpu_idle + fi + + printf "%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" \ + "$(date -Iseconds)" "$elapsed_s" "$load1" "$load5" "$load15" \ + "$mem_total" "$mem_avail" "$mem_used" "$proc_count" "$thread_total" \ + "$pid" "$cpu" "$sys_cpu_pct" "${rss:-0}" "${vsz:-0}" "${stk:-0}" "${heap:-0}" "${nlwp:-0}" \ + >> "$csv" + + sleep 0.2 + done +} + +CMD="cd '$DIR' && exec ./thread_recursive -b $BRANCH -d $DEPTH -s $HOLD" + +log "Starting thread_recursive_scaling: $CMD" + +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" > "$CSV" START_UPTIME=$(awk '{print $1}' /proc/uptime) -./thread_recursive -b "$BRANCH" -d "$DEPTH" -s "$HOLD" >"$STDOUT_LOG" 2>"$STDERR_LOG" & -PID=$! -echo "Sampling metrics for PID=$PID (1s interval)" -echo "sec_from_start,cpu_pct,rss_kb,vsz_kb,nlwp" > "$SAMPLE_LOG" - -MAX_RSS=0 -MAX_VSZ=0 -MAX_THR=0 -MAX_CPU=0 -SUM_CPU=0 -SAMPLE_COUNT=0 - -CLK_TCK=$(getconf CLK_TCK) -PREV_UPTIME=$(awk '{print $1}' /proc/uptime) -PREV_TICKS=0 -if [ -r "/proc/$PID/stat" ]; then - PREV_TICKS=$(awk '{print $14 + $15}' "/proc/$PID/stat" 2>/dev/null || echo 0) +if command -v setsid >/dev/null 2>&1; then + setsid bash -c "$CMD" & + PID=$! +else + bash -c "$CMD" & + PID=$! fi -while kill -0 "$PID" 2>/dev/null; do - NOW_UPTIME=$(awk '{print $1}' /proc/uptime) - ELAPSED_S=$(awk -v s="$START_UPTIME" -v n="$NOW_UPTIME" 'BEGIN{printf "%.3f", (n-s)}') - - if [ -r "/proc/$PID/status" ] && [ -r "/proc/$PID/stat" ]; then - RSS=$(awk '/^VmRSS:/ {print $2}' "/proc/$PID/status" 2>/dev/null || echo 0) - VSZ=$(awk '/^VmSize:/ {print $2}' "/proc/$PID/status" 2>/dev/null || echo 0) - NLWP=$(awk '/^Threads:/ {print $2}' "/proc/$PID/status" 2>/dev/null || echo 0) - CUR_TICKS=$(awk '{print $14 + $15}' "/proc/$PID/stat" 2>/dev/null || echo 0) - - RSS=${RSS:-0} - VSZ=${VSZ:-0} - NLWP=${NLWP:-0} - - DT=$(awk -v a="$PREV_UPTIME" -v b="$NOW_UPTIME" 'BEGIN{print b-a}') - DC=$(awk -v a="$PREV_TICKS" -v b="$CUR_TICKS" 'BEGIN{print b-a}') - CPU=$(awk -v dt="$DT" -v dc="$DC" -v hz="$CLK_TCK" 'BEGIN{ if (dt<=0) printf "0.00"; else printf "%.2f", (100.0*dc)/(dt*hz) }') - - echo "$ELAPSED_S,$CPU,$RSS,$VSZ,$NLWP" >> "$SAMPLE_LOG" - - MAX_RSS=$(awk -v a="$MAX_RSS" -v b="$RSS" 'BEGIN{print (b>a)?b:a}') - MAX_VSZ=$(awk -v a="$MAX_VSZ" -v b="$VSZ" 'BEGIN{print (b>a)?b:a}') - MAX_THR=$(awk -v a="$MAX_THR" -v b="$NLWP" 'BEGIN{print (b>a)?b:a}') - MAX_CPU=$(awk -v a="$MAX_CPU" -v b="$CPU" 'BEGIN{print (b>a)?b:a}') - SUM_CPU=$(awk -v s="$SUM_CPU" -v c="$CPU" 'BEGIN{print s+c}') - SAMPLE_COUNT=$((SAMPLE_COUNT + 1)) - - PREV_UPTIME=$NOW_UPTIME - PREV_TICKS=$CUR_TICKS - fi - sleep 1 -done +sample_process_csv "$PID" "$CSV" "$START_UPTIME" 0 set +e wait "$PID" EXIT_CODE=$? set -e -END_UPTIME=$(awk '{print $1}' /proc/uptime) -WALL_S=$(awk -v s="$START_UPTIME" -v e="$END_UPTIME" 'BEGIN{printf "%.6f", (e-s)}') -AVG_CPU=0 -if [ "$SAMPLE_COUNT" -gt 0 ]; then - AVG_CPU=$(awk -v s="$SUM_CPU" -v n="$SAMPLE_COUNT" 'BEGIN{printf "%.2f", s/n}') -fi -MAX_CPU_FMT=$(awk -v m="$MAX_CPU" 'BEGIN{printf "%.2f", m}') - -TOTAL_CREATED=$(grep -E "total_created_threads:" "$STDOUT_LOG" | awk -F': ' '{print $2}' | tail -n1) -ESTIMATED=$(grep -E "estimated_full_tree:" "$STDOUT_LOG" | awk -F': ' '{print $2}' | tail -n1) -TOTAL_CREATED=${TOTAL_CREATED:-NA} -ESTIMATED=${ESTIMATED:-NA} - -TS=$(date +"%Y-%m-%dT%H:%M:%S%z") -HOST=$(hostname) -KERNEL=$(uname -r) - -echo "$RUN_ID,$TS,$HOST,$KERNEL,$BRANCH,$DEPTH,$HOLD,$EXIT_CODE,$WALL_S,$MAX_RSS,$MAX_VSZ,$MAX_THR,$AVG_CPU,$MAX_CPU_FMT,$TOTAL_CREATED,$ESTIMATED" >> "$RESULTS_CSV" +log "Finished thread_recursive_scaling (exit_code=$EXIT_CODE)" echo echo "Run complete" -echo " stdout: $STDOUT_LOG" -echo " stderr: $STDERR_LOG" -echo " samples: $SAMPLE_LOG" -echo " results csv: $RESULTS_CSV" -echo " exit_code=$EXIT_CODE wall_s=$WALL_S max_rss_kb=$MAX_RSS max_threads=$MAX_THR avg_cpu=$AVG_CPU max_cpu=$MAX_CPU_FMT" +echo " samples: $CSV" +echo " log: $LOG_FILE" +echo " exit_code=$EXIT_CODE"