@@ -31,6 +31,26 @@ echo "${SCRIPT_NAME}: DCPERF_PERF_RECORD=${DCPERF_PERF_RECORD}"
3131function benchreps_tell_state () {
3232 date +" %Y-%m-%d_%T ${1} " >> $BREPS_LFILE
3333}
34+
35+ # ─── CPU utilization helpers (used by adaptive depth) ────────────────────────
36+ # Read /proc/stat's aggregate cpu line and echo "total idle_all" jiffies.
37+ cpu_snapshot () {
38+ local cpu u n s idle iow irq sirq st rest
39+ read -r cpu u n s idle iow irq sirq st rest < /proc/stat
40+ local idle_all=$(( idle + iow))
41+ local total=$(( u + n + s + idle + iow + irq + sirq + st))
42+ echo " $total $idle_all "
43+ }
44+ # System-wide CPU busy% (100 - idle%) measured over the next $1 seconds.
45+ cpu_busy_over () {
46+ local secs=" $1 " s1 s2 t1 i1 t2 i2 dt di
47+ s1=$( cpu_snapshot) ; t1=${s1% * } ; i1=${s1#* }
48+ sleep " $secs "
49+ s2=$( cpu_snapshot) ; t2=${s2% * } ; i2=${s2#* }
50+ dt=$(( t2 - t1 )) ; di=$(( i2 - i1 ))
51+ if [ " $dt " -le 0 ]; then echo " 0" ; return ; fi
52+ echo " scale=1; (($dt - $di ) * 100) / $dt " | bc
53+ }
3454# Source runtime breakdown utilities if they exist
3555if [ -f " ${BENCHPRESS_ROOT} /packages/common/runtime_breakdown_utils.sh" ]; then
3656 source " ${BENCHPRESS_ROOT} /packages/common/runtime_breakdown_utils.sh"
@@ -99,6 +119,11 @@ mutilate (EuroSys \'14) [https://github.com/leverich/mutilate]
99119 without retrying. Optional
100120 -P PID of the process to log runtime breakdowns. Optional
101121 -B Folder to log runtime breakdowns. Optional
122+ -D Adaptive depth: max driver pipeline depth. When set, the peak
123+ phase raises the driver's --depth from 1 until the server is
124+ saturated (system CPU >= 95% OR achieved p95 >= SLA), then holds
125+ that depth for the QPS search. Overrides any --depth in the
126+ driver command. Optional.
102127EOF
103128}
104129
@@ -145,7 +170,7 @@ run_loadtest() {
145170 for r in $( seq 1 $load_test_retries ) ; do
146171 # run the command, saving result to tmpfile
147172 local tmp_file=$( mktemp)
148- $command $threads_arg $qps_arg & > $tmp_file &
173+ $command $threads_arg $qps_arg $adaptive_depth_arg & > $tmp_file &
149174 LOADTEST_PID=$!
150175
151176 if [ " $no_retry_mode " = " 1" ]; then
@@ -301,14 +326,19 @@ max_warmup_iterations=10
301326no_retry_mode=" "
302327breakdown_pid=" "
303328breakdown_folder=" "
329+ adaptive_depth_max=" " # -D: when set, search_qps raises driver --depth in the
330+ adaptive_depth_arg=" " # peak phase until the server saturates (CPU>=95% or p95>=SLA)
304331
305332OPTIND=1 # Reset is necessary if getopts was used previously in the script. It is a good idea to make this local in a function.
306- while getopts " ht:f:w:m:s:q:ao:r:x:NP:B:" opt; do
333+ while getopts " ht:f:w:m:s:q:ao:r:x:NP:B:D: " opt; do
307334 case " $opt " in
308335 h)
309336 show_help
310337 exit 0
311338 ;;
339+ D)
340+ adaptive_depth_max=$OPTARG
341+ ;;
312342 t)
313343 experiment_time=$OPTARG
314344 ;;
364394# remaining argument is loadtest command
365395command=$@
366396
397+ # In adaptive-depth mode, search_qps owns the driver's --depth: strip any fixed
398+ # --depth from the command so our per-attempt --depth is the only one, and start
399+ # the peak search at depth=1.
400+ if [ -n " $adaptive_depth_max " ]; then
401+ command=$( echo " $command " | sed -E ' s/[[:space:]]*--depth=[0-9]+//g' )
402+ adaptive_depth_arg=" --depth=1"
403+ fi
404+
367405# make sure latency_type and latency_target are specified
368406if [[ -z " $fixed_qps " ]] && ( [[ $latency_type = " " ]] || [[ $latency_target = " " ]] ); then
369407 echo ' error: -s metric:target must be specified' >&2 ; exit 1
513551
514552# find peak QPS
515553benchreps_tell_state " before peak_qps"
516- run_loadtest peak_qps measured_latency " " " "
554+ if [ -n " $adaptive_depth_max " ]; then
555+ # Adaptive depth: the peak load test offers at most threads*connections*depth
556+ # concurrent requests. Starting at depth=1, keep raising depth (and re-running
557+ # peak) until the server saturates — system CPU >= 95% OR achieved p95 >= SLA
558+ # — so platforms that need more offered concurrency reach a real bound instead
559+ # of capping on driver concurrency (the t19 anti-pattern). The selected depth
560+ # is then held for the QPS search / tuning / final phases.
561+ cur_depth=1
562+ while : ; do
563+ adaptive_depth_arg=" --depth=$cur_depth "
564+ # Sample system CPU busy% over a mid-run window while the peak load runs.
565+ cpu_busy_file=" /tmp/adaptive_cpu_busy_$$ "
566+ ( sleep 20; cpu_busy_over 40 > " $cpu_busy_file " ) &
567+ cpu_sampler_pid=$!
568+ run_loadtest peak_qps measured_latency " " " "
569+ wait " $cpu_sampler_pid " 2> /dev/null
570+ cpu_busy=$( cat " $cpu_busy_file " 2> /dev/null || echo 0)
571+ rm -f " $cpu_busy_file "
572+ cpu_sat=$( echo " ${cpu_busy:- 0} >= 95" | bc 2> /dev/null || echo 0)
573+ lat_sat=$( echo " $measured_latency >= $latency_target " | bc 2> /dev/null || echo 0)
574+ printf " adaptive-depth: depth=%d peak_qps=%.2f p95=%.2f cpu_busy=%s%% cpu_sat=%s lat_sat=%s\n" \
575+ " $cur_depth " " $peak_qps " " $measured_latency " " ${cpu_busy:- 0} " " $cpu_sat " " $lat_sat "
576+ echo " adaptive-depth: depth=$cur_depth peak_qps=$peak_qps p95=$measured_latency cpu_busy=${cpu_busy} % cpu_sat=$cpu_sat lat_sat=$lat_sat " >> $BREPS_LFILE
577+ if [ " $cpu_sat " -eq 1 ] || [ " $lat_sat " -eq 1 ] || [ " $cur_depth " -ge " $adaptive_depth_max " ]; then
578+ break
579+ fi
580+ cur_depth=$(( cur_depth + 1 ))
581+ sleep " $wait_time "
582+ done
583+ echo " adaptive-depth: SELECTED depth=$cur_depth (cpu_busy=${cpu_busy} %, p95=$measured_latency , sla=$latency_target )" >> $BREPS_LFILE
584+ printf " adaptive-depth: selected depth=%d (cpu_busy=%s%%, p95=%.2f)\n" " $cur_depth " " ${cpu_busy:- 0} " " $measured_latency "
585+ else
586+ run_loadtest peak_qps measured_latency " " " "
587+ fi
517588printf " peak qps = %.2f, latency = %.2f\n" $peak_qps $measured_latency
518589benchreps_tell_state " after peak_qps"
519590
0 commit comments