fa0097404a
- Changed output to show bytes instead of MB - Updated header to show 'Minne (bytes)' - Better for comparing memory usage across all languages - Memory data already collected in bytes from ps command
265 lines
8.5 KiB
Bash
Executable File
265 lines
8.5 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Run all pi calculation programs and measure performance and memory
|
|
# Run each program 3 times and take the average
|
|
|
|
set -e
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
cd "$SCRIPT_DIR"
|
|
|
|
# Check if argument provided
|
|
if [ $# -eq 0 ]; then
|
|
echo "Usage: $0 <decimaler>"
|
|
echo "Example: $0 100"
|
|
exit 1
|
|
fi
|
|
|
|
DECIMALS=$1
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Function to verify result against facit
|
|
verify() {
|
|
local result="$1"
|
|
local decimals="$2"
|
|
local expected=$(head -c $((decimals + 2)) facit.txt)
|
|
|
|
if [ "$result" = "$expected" ]; then
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to get memory usage of a process (in bytes)
|
|
get_memory_usage() {
|
|
local pid=$1
|
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
# Use ps to get RSS (resident set size) in KB, then convert to bytes
|
|
local kb=$(ps -o rss= -p "$pid" 2>/dev/null || echo "0")
|
|
echo $((kb * 1024))
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Function to get CPU usage of a process (in percentage)
|
|
get_cpu_usage() {
|
|
local pid=$1
|
|
if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
|
|
# Use ps to get CPU percentage
|
|
ps -o %cpu= -p "$pid" 2>/dev/null | awk '{print int($1)}' || echo "0"
|
|
else
|
|
echo "0"
|
|
fi
|
|
}
|
|
|
|
# Function to profile memory and CPU during execution
|
|
profile_resources() {
|
|
local pid=$1
|
|
local mem_output_file=$2
|
|
local cpu_output_file=$3
|
|
local timeline_file=$4
|
|
local peak_mem=0
|
|
local peak_cpu=0
|
|
local current_mem
|
|
local current_cpu
|
|
local start_time=$(date +%s%N)
|
|
local sample_count=0
|
|
|
|
# Clear output files
|
|
> "$mem_output_file"
|
|
> "$cpu_output_file"
|
|
> "$timeline_file"
|
|
|
|
# Sample resources every 1ms while process is running
|
|
while kill -0 "$pid" 2>/dev/null; do
|
|
current_mem=$(get_memory_usage "$pid")
|
|
current_cpu=$(get_cpu_usage "$pid")
|
|
current_time=$(date +%s%N)
|
|
elapsed_ms=$(( (current_time - start_time) / 1000000 ))
|
|
|
|
if [ "$current_mem" -gt "$peak_mem" ]; then
|
|
peak_mem=$current_mem
|
|
fi
|
|
if [ "$current_cpu" -gt "$peak_cpu" ]; then
|
|
peak_cpu=$current_cpu
|
|
fi
|
|
|
|
# Store time-series data
|
|
echo "$elapsed_ms $current_mem" >> "$mem_output_file"
|
|
echo "$elapsed_ms $current_cpu" >> "$cpu_output_file"
|
|
echo "$elapsed_ms $current_mem $current_cpu" >> "$timeline_file"
|
|
|
|
sample_count=$((sample_count + 1))
|
|
sleep 0.001 2>/dev/null || sleep 0.01
|
|
done
|
|
|
|
echo "$peak_mem $peak_cpu $sample_count"
|
|
}
|
|
|
|
echo "=== Pi-beräkning med $DECIMALS decimaler (4 körningar, genomsnitt av 3 efter warmup) ==="
|
|
echo ""
|
|
|
|
# Array to store results
|
|
declare -a results
|
|
|
|
# Run each program 4 times, discard first run (warmup), take average of last 3
|
|
run_program() {
|
|
local name="$1"
|
|
shift
|
|
|
|
printf "%-12s " "$name"
|
|
|
|
local total_time=0
|
|
local total_memory=0
|
|
local total_cpu=0
|
|
local success_count=0
|
|
local result
|
|
local peak_memory=0
|
|
local peak_cpu=0
|
|
local timeline_dir="timelines/$name"
|
|
|
|
# Create timeline directory
|
|
mkdir -p "$timeline_dir"
|
|
|
|
# Run 4 times, discard first run (warmup)
|
|
for i in 1 2 3 4; do
|
|
local timeline_file="$timeline_dir/run_$i.tsv"
|
|
local start=$(date +%s%N)
|
|
|
|
# Run program and capture PID for resource profiling
|
|
"$@" 2>/dev/null &
|
|
local pid=$!
|
|
|
|
# Profile resources in background
|
|
local resources=$(profile_resources "$pid" "/dev/null" "/dev/null" "$timeline_file")
|
|
local peak_mem=$(echo "$resources" | awk '{print $1}')
|
|
local peak_cpu_val=$(echo "$resources" | awk '{print $2}')
|
|
|
|
# Wait for process to complete
|
|
wait "$pid" 2>/dev/null
|
|
local exit_code=$?
|
|
|
|
local end=$(date +%s%N)
|
|
local elapsed=$(( (end - start) / 1000000 ))
|
|
|
|
if [ $exit_code -eq 0 ]; then
|
|
# Get result for verification
|
|
result=$("$@" 2>/dev/null)
|
|
|
|
if [ "$i" -gt 1 ]; then
|
|
# Only count runs 2-4 for averages
|
|
total_time=$((total_time + elapsed))
|
|
total_memory=$((total_memory + peak_mem))
|
|
total_cpu=$((total_cpu + peak_cpu_val))
|
|
|
|
if [ "$peak_mem" -gt "$peak_memory" ]; then
|
|
peak_memory=$peak_mem
|
|
fi
|
|
if [ "$peak_cpu_val" -gt "$peak_cpu" ]; then
|
|
peak_cpu=$peak_cpu_val
|
|
fi
|
|
|
|
if verify "$result" "$DECIMALS"; then
|
|
((success_count++))
|
|
fi
|
|
fi
|
|
else
|
|
echo -e "${RED}ERROR${NC}"
|
|
results+=("999999 $name ERROR")
|
|
return
|
|
fi
|
|
done
|
|
|
|
# Calculate averages
|
|
local avg_time=$((total_time / 3))
|
|
local avg_memory=$((total_memory / 3))
|
|
local avg_cpu=$((total_cpu / 3))
|
|
|
|
# Convert memory to MB for display
|
|
local avg_memory_mb=$((avg_memory / 1024))
|
|
local peak_memory_mb=$((peak_memory / 1024))
|
|
|
|
if [ $success_count -eq 3 ]; then
|
|
echo -e "${GREEN}SUCCESS${NC} $avg_time ms, ${BLUE}${avg_memory_mb}MB avg / ${peak_memory_mb}MB peak, ${YELLOW}${avg_cpu}% CPU avg / ${peak_cpu}% CPU peak${NC}"
|
|
results+=("$avg_time $name SUCCESS $avg_memory $peak_memory $avg_cpu $peak_cpu")
|
|
else
|
|
echo -e "${RED}FAILED${NC} $avg_time ms, ${BLUE}${avg_memory_mb}MB avg / ${peak_memory_mb}MB peak, ${YELLOW}${avg_cpu}% CPU avg / ${peak_cpu}% CPU peak${NC}"
|
|
results+=("$avg_time $name FAILED $avg_memory $peak_memory $avg_cpu $peak_cpu")
|
|
fi
|
|
}
|
|
|
|
# Run all programs (no timeouts)
|
|
run_program Bash bash bash/bin/print_hej "$DECIMALS"
|
|
run_program Brainfuck brainfuck/bin/print_hej "$DECIMALS"
|
|
run_program C c/bin/print_hej "$DECIMALS"
|
|
run_program C++ cpp/bin/print_hej "$DECIMALS"
|
|
run_program Crystal crystal/bin/print_hej "$DECIMALS"
|
|
run_program CSharp csharp/bin/print_hej "$DECIMALS"
|
|
run_program D d/bin/print_hej "$DECIMALS"
|
|
run_program Dart dart/bin/print_hej "$DECIMALS"
|
|
run_program Elixir elixir/bin/print_hej "$DECIMALS"
|
|
run_program Erlang erlang/bin/print_hej "$DECIMALS"
|
|
run_program Fortran fortran/bin/print_hej "$DECIMALS"
|
|
run_program Go go/bin/print_hej "$DECIMALS"
|
|
run_program Haskell haskell/bin/print_hej "$DECIMALS"
|
|
run_program Java java/bin/print_hej "$DECIMALS"
|
|
run_program JavaScript javascript/bin/print_hej "$DECIMALS"
|
|
run_program Julia julia/bin/print_hej "$DECIMALS"
|
|
run_program Kotlin kotlin/bin/print_hej "$DECIMALS"
|
|
run_program Objective-C objective-c/bin/print_hej "$DECIMALS"
|
|
run_program Scala scala/bin/print_hej "$DECIMALS"
|
|
run_program TypeScript typescript/bin/print_hej "$DECIMALS"
|
|
run_program Lua lua/bin/print_hej "$DECIMALS"
|
|
run_program Nim nim/bin/print_hej "$DECIMALS"
|
|
run_program Odin odin/bin/print_hej "$DECIMALS"
|
|
run_program Perl perl/bin/print_hej "$DECIMALS"
|
|
run_program PHP php/bin/print_hej "$DECIMALS"
|
|
run_program Python python/bin/print_hej "$DECIMALS"
|
|
run_program R r/bin/print_hej "$DECIMALS"
|
|
run_program Ruby ruby/bin/print_hej "$DECIMALS"
|
|
run_program Rust rust/bin/print_hej "$DECIMALS"
|
|
run_program Swift swift/bin/print_hej "$DECIMALS"
|
|
run_program Zig zig/bin/print_hej "$DECIMALS"
|
|
run_program Assembly assembly/bin/print_hej "$DECIMALS"
|
|
run_program Wolfram wolfram/bin/print_hej "$DECIMALS"
|
|
run_program Vimscript vimscript/bin/print_hej "$DECIMALS"
|
|
|
|
echo ""
|
|
echo "=== Sammanfattning (sorterad efter prestanda) ==="
|
|
echo ""
|
|
|
|
# Sort and print results
|
|
IFS=$'\n' sorted=($(printf '%s\n' "${results[@]}" | sort -n))
|
|
unset IFS
|
|
|
|
echo "Språk Status Tid (ms) Minne (bytes) CPU (%)"
|
|
echo "================================================================"
|
|
|
|
for entry in "${sorted[@]}"; do
|
|
time_ms=$(echo "$entry" | awk '{print $1}')
|
|
name=$(echo "$entry" | awk '{print $2}')
|
|
status=$(echo "$entry" | awk '{print $3}')
|
|
avg_mem=$(echo "$entry" | awk '{print $4}')
|
|
peak_mem=$(echo "$entry" | awk '{print $5}')
|
|
avg_cpu=$(echo "$entry" | awk '{print $6}')
|
|
peak_cpu=$(echo "$entry" | awk '{print $7}')
|
|
|
|
printf "%-12s " "$name"
|
|
|
|
if [ "$status" = "SUCCESS" ]; then
|
|
echo -e "${GREEN}$status${NC} $time_ms ms ${BLUE}${avg_mem} bytes avg / ${YELLOW}${peak_mem} bytes peak ${avg_cpu}% avg / ${peak_cpu}% peak${NC}"
|
|
else
|
|
echo -e "${RED}$status${NC} $time_ms ms ${BLUE}${avg_mem} bytes avg / ${YELLOW}${peak_mem} bytes peak ${avg_cpu}% avg / ${peak_cpu}% peak${NC}"
|
|
fi
|
|
done
|
|
|
|
echo ""
|