[READ-ONLY] Mirror of https://github.com/FoxxMD/crowdsecBench. Benchmark Crowdsec CPU usage with concurrent requests
benchmark cpu-usage crowdsec docker k6 monitoring visualization
0

Configure Feed

Select the types of activity you want to include in your feed.

Use goeffel for usage capture and graphing

FoxxMD (Sep 22, 2025, 3:01 PM EDT) 6f90f243 4cdaed04

+69 -72
+4 -1
.gitignore
··· 1 1 node_modules 2 2 .env 3 - data 3 + data 4 + /*.hdf5 5 + /*.png 6 + /*.command
+8 -7
README.md
··· 13 13 * Randomized path (`RANDOMIZE=true`) 14 14 * Randomized User-Agent 15 15 16 - Additionally, the bash script [`bench.sh`](/bench.sh) can be used to orchestrate the load call, monitor the crowdsec process, and create a .png plot of CPU/memory using [`psrecord`](https://github.com/astrofrog/psrecord), if it installed. 16 + Additionally, the bash script [`bench.sh`](/bench.sh) can be used to orchestrate the load call, monitor the crowdsec process, and create a .png plot of CPU using [`goeffel`](https://github.com/jgehrcke/goeffel), if it installed. 17 17 18 18 # Usage 19 19 ··· 30 30 31 31 ### Using `bench.sh` 32 32 33 - Install [`psrecord`](https://github.com/astrofrog/psrecord), if not present: 33 + Install latest development [`goeffel`](hhttps://github.com/jgehrcke/goeffel) version: 34 34 35 35 ```shell 36 - pipx install psrecord[plot] 36 + pipx install git+https://github.com/jgehrcke/goeffel 37 37 ``` 38 38 39 - Run `bench.sh` from the project directory, providing the duration the load will be run: 39 + Run `bench.sh` from the project directory. It requires `sudo` to collect metrics. 40 40 41 41 ```shell 42 - # DURATION=12 from .env then... 43 - ./bench.sh 12 42 + sudo ./bench.sh 44 43 ``` 45 44 46 - After the run has finished an image `plot_[unix_timestamp].png` will be generated in the project directory. 45 + After the run has finished an image `[date]_crowdsec-web-traffic-load-[unix_timestamp].png` will be generated in the project directory. 46 + 47 + Additional graphs can be plotted from the generated `hdf5` file using [`goeffel-analysis`](https://github.com/jgehrcke/goeffel?tab=readme-ov-file#goeffel-analysis-data-inspection-and-visualization). 47 48 48 49 ### Manually 49 50
+57 -8
bench.sh
··· 1 1 #!/bin/bash 2 - set -x 2 + 3 + ## https://askubuntu.com/a/970898 4 + if ! [ $(id -u) = 0 ]; then 5 + echo "The script need to be run as root." >&2 6 + exit 1 7 + fi 8 + 9 + if [ $SUDO_USER ]; then 10 + real_user=$SUDO_USER 11 + else 12 + real_user=$(whoami) 13 + fi 14 + 15 + trap 'exit 0;' SIGHUP SIGINT SIGKILL 16 + 17 + printf 'Starting traefik and echo...\n' 18 + sudo -u $real_user docker compose up traefik echo -d 19 + 20 + printf 'Starting crowdsec container...\n' 21 + sudo -u $real_user docker compose up crowdsec -d 22 + 23 + CS_PID=$(pgrep crowdsec --newest | head -n 1) 24 + while [ -z "$CS_PID" ] 25 + do 26 + printf 'Waiting for crowdsec to finish starting up...\n' 27 + sleep 1 28 + CS_PID=$(pgrep crowdsec --newest | head -n 1) 29 + done 30 + printf 'Crowdsec started! Waiting a few seconds for CPU to settle...\n' 31 + sleep 2 32 + 33 + printf 'Starting goeffel capture of crowdsec PID %s \n' "$CS_PID" 34 + goeffel --pid $CS_PID --no-system-metrics --label crowdsec & 35 + G_PID=$! 3 36 4 - DURATION=${1} 37 + printf 'Starting k6\n' 38 + sudo -u $real_user docker compose up k6 -d 5 39 6 - docker compose up traefik crowdsec echo -d 40 + #printf 'Waiting for k6 to finish...\n' 41 + docker compose wait k6 42 + printf 'k6 container exited!\n' 7 43 8 - CSPID=$(pgrep crowdsec) 44 + printf 'Stopping crowdsec\n' 45 + sudo -u $real_user docker compose down crowdsec 9 46 10 - docker compose up k6 -d 47 + while test -d /proc/$G_PID; do 48 + printf 'Waiting for goeffel to finish...\n' 49 + sleep 1 50 + done 51 + 52 + DATA=$(ls -t1 *.hdf5 | head -n 1) 11 53 12 54 timestamp=$(date +%s) 13 55 14 - psrecord $CSPID --plot plot_$timestamp.png --interval 0.1 --duration $DURATION 56 + printf 'Generating plot for %s\n' "$DATA" 15 57 16 - #./topplot/capture.sh $CSPID & sleep $DURATION;kill $! 17 - #./topplot/plot-usage.gp top.dat top.png 58 + sudo -u $real_user goeffel-analysis flexplot \ 59 + --series $DATA host \ 60 + --column proc_cpu_util_percent_total \ 61 + 'CPU util (total) / %' \ 62 + "Crowdsec Web Traffic Load $timestamp" 5 \ 63 + --subtitle '50 concurrent requests, measured with Goeffel' \ 64 + --legend-loc 'upper right' \ 65 + --mean-style solid \ 66 + --custom-y-limit 0 100
-14
topplot/capture.sh
··· 1 - #!/bin/sh 2 - ## https://theholyjava.wordpress.com/2018/10/17/monitoring-process-memory-cpu-usage-with-top-and-plotting-it-with-gnuplot/ 3 - ## 4 - ## BEWARE: Check with your impl. of top what exactly it returns, it migth differ from mine 5 - ## 6 - # Usage: ./monitor-usage.sh <PID of the process> 7 - # Output: top.dat with lines such as `1539689171 305m 2.0`, i.e. unix time - memory with m suffix - CPU load in % 8 - # To plot the output, see https://gist.github.com/holyjak/1b58dedae3207b4a56c9abcde5f3fdb5 9 - export PID=$1 10 - rm top.dat 11 - while true; do top -p $PID -bn 1 -em | grep -E '^ *[0-9]+' | awk -v now=$(date +%s.%N) '{print now,$6,$9}' >> top.dat; done 12 - # top: -p <pid> target process, -b batch mode, -n 1 run once; -em display mem in MB 13 - # egrep extracts the line starting with the pid, with the metrics 14 - # awk prepends a date and extracts columns 6 (RES = residential memory, ie RAM) and 9, which should be the memory and cpu load
-42
topplot/plot-usage.gp
··· 1 - #!/usr/bin/env -S gnuplot --persist -c 2 - # Plot memory and CPU usage over time. Usage: 3 - # usage-plot.gp <input file> [<output .png file>] 4 - # where the input file has the columns `<unix time> <memory, with m/g suffix> <% cpu>` 5 - # To create the input file, see https://gist.github.com/jakubholynet/931a3441982c833f5f8fcdcf54d05c91 6 - 7 - # Arguments: 8 - infile=ARG1 9 - outfile=ARG2 10 - set term x11 11 - set title 'Memory, CPU usage from' . infile 12 - set xdata time 13 - set timefmt "%s" 14 - set xlabel "Time [[hh:]mm:ss]" 15 - set ylabel "Memory usage" 16 - set format y '%.1s%cB' 17 - 18 - set y2label 'CPU usage' 19 - set format y2 '%.0s%%' 20 - set y2tics nomirror 21 - set tics out 22 - set autoscale y 23 - set autoscale y2 24 - 25 - # Credit: Christoph @ https://stackoverflow.com/a/52822256/204205 26 - resolveUnit(s)=(pos=strstrt("kmgtp",s[strlen(s):*]), real(s)*(1024**pos)) 27 - 28 - if (exists("outfile") && strlen(outfile) > 0) { 29 - print "Outputting to the file ", outfile 30 - set term png # 640,480 31 - set output outfile 32 - } 33 - 34 - # Styling 35 - set style line 1 linewidth 1 linecolor 'light-blue' 36 - set style line 2 linecolor 'dark-green' 37 - #set xtics font ", 10" 38 - set tics font ", 10" 39 - set xtics rotate 60 # put label every 60s, make vertical so they don't clash in .png if too many 40 - 41 - plot infile u 1:3 with lp axes x1y2 title "cpu" linestyle 2, \ 42 - infile using 1:(resolveUnit(stringcolumn(2))) with linespoints title "memory" linestyle 1