chore: update benchmark with bombardier

This commit is contained in:
Juan Rodriguez
2024-10-27 11:07:23 +01:00
parent ea71d3825e
commit e6f64ea026
2 changed files with 121 additions and 130 deletions
+119 -129
View File
@@ -1,148 +1,138 @@
#!/bin/bash
api_url="http://localhost:4001/api/links"
num_links=1000
num_requests=10
# Check dependencies
if ! command -v bombardier &> /dev/null; then
echo "Error: bombardier is not installed. Please install it to proceed."
exit 1
fi
if ! command -v jq &> /dev/null; then
echo "Error: jq is not installed. Please install it to proceed."
exit 1
fi
server_url="http://localhost:4001"
api_url="${server_url}/api/links"
num_links=10000 # Total number of links to create by curl
num_requests=10000 # Total number of requests to perform by bombardier
concurrency=100 # Number of multiple requests to make at a time
resource_usage_interval=1 # Interval in seconds for resource usage logging
container_name="bit"
semaphore="/tmp/semaphore"
max_concurrent_processes=$(ulimit -u) # Adjust this number based on your system's capability
# Initialize semaphore
mkfifo $semaphore
exec 3<> $semaphore
rm $semaphore
for ((i=0; i<max_concurrent_processes; i++)); do
echo >&3
done
echo "Semaphore initialized with $max_concurrent_processes slots."
function get_resource_usage {
while true; do
docker stats --no-stream --format "table {{.MemUsage}} {{.CPUPerc}}" bit-app-1 | awk 'NR>1 {print "Memory:", $1, "CPU:", $2}' >> resource_usage.txt
function monitor_resource_usage {
echo "Timestamp,CPU(%),Memory(MB)" > resource_usage.csv
while :; do
stats=$(docker stats --no-stream --format "{{.CPUPerc}},{{.MemUsage}}" $container_name)
cpu=$(echo $stats | awk -F',' '{print $1}' | sed 's/%//')
mem=$(echo $stats | awk -F',' '{print $2}' | awk '{print $1}')
timestamp=$(date +%s)
echo "$timestamp,$cpu,$mem" >> resource_usage.csv
sleep $resource_usage_interval
done
}
function calculate_average_usage {
total_mem=0
total_cpu=0
count=0
echo "Setting up..."
while read -r line; do
if echo $line | grep -q 'Memory'; then
mem=$(echo $line | awk '{print $2}' | sed 's/MiB//')
total_mem=$(echo "$total_mem + $mem" | bc)
elif echo $line | grep -q 'CPU'; then
cpu=$(echo $line | awk '{print $2}' | sed 's/%//')
total_cpu=$(echo "$total_cpu + $cpu" | bc)
fi
((count++))
done < resource_usage.txt
avg_mem=$(echo "scale=2; $total_mem / ($count / 2)" | bc) # Since there are 2 lines per interval
avg_cpu=$(echo "scale=2; $total_cpu / ($count / 2)" | bc)
rm resource_usage.txt
echo "Average Memory Usage: $avg_mem MiB"
echo "Average CPU Usage: $avg_cpu%"
}
function measure {
total_time=0
declare -a refer_links
# Start resource usage logging in the background
nohup bash -c "$(declare -f get_resource_usage); get_resource_usage" &> /dev/null &
resource_usage_pid=$!
disown
echo "Creating $num_links short links..."
for ((i=1; i<=num_links; i++)); do
response=$(curl --silent --request POST \
--url $api_url \
--header "X-Api-Key: $api_key" \
--header "Content-Type: application/json" \
--data "{ \"url\": \"https://kagi.com\" }")
refer=$(echo $response | awk -F'"' '/"refer":/{print $(NF-1)}')
if [[ -n $refer ]]; then
refer_links+=("$refer")
if (( i % 100 == 0 )); then
echo "Created short link $i/$num_links"
fi
else
echo "Failed to create short link $i"
echo $response
exit 1
fi
done
echo "Accessing each link $num_requests times concurrently..."
> times.txt # Ensure times.txt is created and empty
total_accesses=$((num_links * num_requests))
accesses_done=0
for refer in "${refer_links[@]}"; do
for ((i=1; i<=num_requests; i++)); do
# Wait for a slot
read -u 3
{
start_time=$(date +%s%6N)
curl -s "$refer" >> /dev/null
end_time=$(date +%s%6N)
elapsed_time=$(echo "$end_time - $start_time" | bc)
echo $elapsed_time >> times.txt
# Release the slot
echo >&3
((accesses_done++))
if (( accesses_done % 10 == 0 )); then
echo "Accessed $accesses_done/$total_accesses"
fi
} &
done
done
wait
# Stop resource usage logging
if kill -0 $resource_usage_pid 2>/dev/null; then
kill $resource_usage_pid
fi
# Read all elapsed times and calculate total
while read -r time; do
total_time=$(echo "$total_time + $time" | bc)
done < times.txt
rm times.txt
echo "****Results****"
calculate_average_usage
echo "Average Response Time: $(echo "scale=2; $total_time / ($num_links * $num_requests)" | bc) µs"
}
echo "Setup..."
docker-compose up -d
docker compose up -d
if [ $? -ne 0 ]; then
echo "Failed to start Docker containers."
exit 1
fi
# Create a new user and capture the API key
output=$(docker-compose exec -T app cli --create-user=Admin)
output=$(docker compose exec -T app cli --create-user=Admin)
api_key=$(echo "$output" | awk -F' ' '/X-Api-Key:/{print $NF}')
echo "Captured API Key: $api_key"
echo "Waiting for database to be ready..."
sleep 5
# Ensure the API key is valid
if [[ -z "$api_key" ]]; then
echo "Error: API key could not be retrieved."
exit 1
fi
measure
echo "Waiting for the application to be ready..."
until curl --silent --head --fail --header "X-Api-Key: $api_key" "$server_url/api/ping"; do
sleep 2
done
# Clean up
docker-compose down
echo "Starting resource usage monitoring..."
monitor_resource_usage & # Run in the background
monitor_pid=$!
echo "Creating $num_links short links..."
batch_size=$((num_links / 10))
progress_bar_width=50
for ((batch=1; batch<=num_links; batch+=batch_size)); do
progress=$(( (batch - 1) * progress_bar_width / num_links))
bar=$(printf "%-${progress_bar_width}s" "#" | tr ' ' '#')
printf "\r[%-${progress_bar_width}s] %d%%" "${bar:0:progress}" $(((batch - 1) * 100 / num_links))
# Launch a batch of background processes
for ((i=batch; i<batch+batch_size && i<=num_links; i++)); do
unique_url="https://example.com/${RANDOM}-${i}"
curl --silent --request POST \
--url "$api_url" \
--header "X-Api-Key: $api_key" \
--header "Content-Type: application/json" \
--data "{ \"url\": \"$unique_url\" }" > /dev/null &
done
wait # Wait for all processes in the current batch to finish
progress=$((batch * progress_bar_width / num_links))
bar=$(printf "%-${progress_bar_width}s" "#" | tr ' ' '#')
printf "\r[%-${progress_bar_width}s] %d%%" "${bar:0:progress}" $((batch * 100 / num_links))
done
printf "\r[%-${progress_bar_width}s] 100%%\n" "$(printf "%-${progress_bar_width}s" "#" | tr ' ' '#')"
echo "Link creation complete: $num_links links created."
echo "Fetching all created links from /api/links..."
all_links_response=$(curl --silent --request GET \
--url "$api_url" \
--header "X-Api-Key: $api_key" \
--header "Content-Type: application/json")
links=($(echo "$all_links_response" | jq -r '.data[] | .refer'))
if [[ ${#links[@]} -ne $num_links ]]; then
echo "Error: Expected $num_links links but found ${#links[@]}."
exit 1
fi
random_link="${links[RANDOM % ${#links[@]}]}"
echo "Selected link for benchmarking: $random_link"
echo "Starting benchmark with Bombardier..."
bombardier -c $concurrency -n $num_requests "$random_link"
echo "Benchmark completed."
# Stop resource monitoring
kill $monitor_pid 2>/dev/null
echo "Analyzing resource usage..."
total_cpu=0
total_mem=0
count=0
# Process each line in the resource usage log
while IFS=',' read -r timestamp cpu mem; do
# Skip the header line
if [[ $timestamp != "Timestamp" ]]; then
total_cpu=$(echo "$total_cpu + $cpu" | bc)
total_mem=$(echo "$total_mem + $mem" | bc)
((count++))
fi
done < resource_usage.csv
# Calculate averages; if count is 0, output will be 0.00
avg_cpu=$(echo "scale=2; $total_cpu / ($count == 0 ? 1 : $count)" | bc)
avg_mem=$(echo "scale=2; $total_mem / ($count == 0 ? 1 : $count)" | bc)
echo "**** Results ****"
echo "Average CPU Usage: $avg_cpu%"
echo "Average Memory Usage: $avg_mem MiB"
echo "Cleaning up..."
rm resource_usage.csv
docker compose down