Skip to content

Commit 0480ec4

Browse files
holly-cumminsclaude
andcommitted
Add energy measurement support (RAPL + iDRAC)
Add RAPL (CPU-level) and iDRAC (system-level) power measurement to the measure-rss benchmark phase. Energy sources are controlled by per-source config flags (config.energy.rapl, config.energy.idrac) with a single --energy CLI flag accepting comma-separated values (all, none, rapl, idrac, or rapl,idrac). - New helpers/energy.yml with install-rapl-plot and capture-system-power - Hardware guards skip unsupported measurements silently (safe on any platform) - All sh/regex patterns use then blocks for qDup 0.11 compatibility - Uses sudo script instead of sh: sudo - Energy file downloads queued early for resilience - Per-iteration average watts written to JSON output with cross-iteration averages - Auto-adds measure-rss to test list when --energy is explicitly set Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 7756393 commit 0480ec4

3 files changed

Lines changed: 191 additions & 1 deletion

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: Energy-related scripts
2+
scripts:
3+
capture-system-power:
4+
- script: idrac-login
5+
with:
6+
idrac: ${{= ${{servers}}.filter( server => { return server.hostname == "${{env.HOST}}"})[0].idrac}}
7+
password: ${{idrac_pwd}}
8+
- set-state: RUN.svrPwr []
9+
- repeat-until: ${{COMPLETE_SIGNAL}}
10+
then:
11+
- sleep: 1s
12+
- sh: racadm get system.Power.Realtime.Power
13+
then:
14+
- regex: (?<watts>\\d+) W | (?<btu>\\d+) Btu/hr
15+
then:
16+
- script: state-array-push
17+
with:
18+
array: RUN.svrPwr
19+
value: ${{watts}}
20+
install-rapl-plot:
21+
- read-state: ${{config.energy.rapl}}
22+
then:
23+
- regex: "enabled"
24+
then:
25+
- sh: "[[ -d /sys/class/powercap/intel-rapl ]] && echo RAPL_SUPPORTED || echo RAPL_UNSUPPORTED"
26+
then:
27+
- regex: RAPL_SUPPORTED
28+
then:
29+
- sh: "[[ -f ${{RAPL_PATH:/tmp/rapl}}/${{RAPL_EXE:rapl-plot}} ]] || echo GETRAPL;"
30+
then:
31+
- regex: GET
32+
then:
33+
- sh: mkdir -p ${{RAPL_PATH:/tmp/rapl}}
34+
- sh: cd ${{RAPL_PATH:/tmp/rapl}}
35+
- sh: git clone https://github.com/deater/uarch-configure.git
36+
- sh: cd uarch-configure/rapl-read
37+
- sh: make all
38+
- sh: cp rapl-plot ${{RAPL_PATH:/tmp/rapl}}/${{RAPL_EXE:rapl-plot}}
39+
- set-state: RUN.RAPL_BIN ${{RAPL_PATH:/tmp/rapl}}/${{RAPL_EXE:rapl-plot}}
40+
- regex: RAPL_UNSUPPORTED
41+
then:
42+
- log: RAPL not available on this system, skipping energy measurement via RAPL

scripts/perf-lab/main.yml

Lines changed: 98 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ states:
1414
config.units.load.throughputDensity: tps per MiB
1515
config.units.load.errors.connectionErrors: absolute number
1616
config.units.load.errors.requestTimeouts: absolute number
17+
config.units.energy.idrac: W
18+
config.units.energy.raplPkg: W
19+
config.units.energy.raplDram: W
1720

1821
config.jvm.home: #/path/to/java
1922
config.jvm.version: 25.0.2-tem
@@ -42,6 +45,8 @@ states:
4245
config.resources.cpu.monitor: 11
4346
config.resources.cpu.otel: 12-14
4447

48+
config.energy.rapl: enabled #disabled
49+
config.energy.idrac: enabled #disabled
4550
config.profiler.name: none #jfr syncjfr flamegraph
4651
config.profiler.events: cpu
4752

@@ -517,15 +522,43 @@ scripts:
517522
var-name: RUN.output.results.${{RUNTIMECMD.name}}.startup.avStartTime
518523
array: RUN.output.results.${{RUNTIMECMD.name}}.startup.timings
519524

520-
measure-rss:
525+
measure-rss: # also measures energy
521526
- log: Measuring RSS
522527
- sh: java -version
523528
- sh: cd ${{RUNTIMECMD.dir}}
524529
- for-each: ITERATION ${{=[...Array(${{config.num_iterations}}).keys()]}}
525530
then:
531+
- set-state: RUN.OUTPUT_DIR ${{REPO_DIR}}/logs
532+
- set-state: RUN.COMPLETE_SIGNAL measure-rss-${{RUNTIMECMD.name}}-${{ITERATION}}
526533
- queue-download: ${{REPO_DIR}}/logs/measure-rss-${{RUNTIMECMD.name}}-${{ITERATION}}.log
534+
- queue-download: ${{OUTPUT_DIR}}/${{COMPLETE_SIGNAL}}.rapl
535+
- queue-download: ${{OUTPUT_DIR}}/${{COMPLETE_SIGNAL}}.svrPwr
527536
- script: start-test-services
528537
- script: sync-drop-fs-cache
538+
- read-state: ${{config.energy.rapl}}
539+
then:
540+
- regex: "enabled"
541+
then:
542+
- sh: "[[ -x ${{RUN.RAPL_BIN:__NORAPL__}} ]] && echo RAPL_READY"
543+
then:
544+
- regex: RAPL_READY
545+
then:
546+
- script: sudo
547+
with:
548+
command: ${{RUN.RAPL_BIN}} -p > ${{OUTPUT_DIR}}/${{COMPLETE_SIGNAL}}.rapl &
549+
- sh: echo $!
550+
- read-state: ${{config.energy.idrac}}
551+
then:
552+
- regex: "enabled"
553+
then:
554+
- sh: "command -v racadm > /dev/null 2>&1 && echo IDRAC_READY"
555+
then:
556+
- regex: IDRAC_READY
557+
then:
558+
- set-signal: ${{COMPLETE_SIGNAL}} 1
559+
- script:
560+
name: capture-system-power
561+
async: true
529562
- sh: ${{RUNTIMECMD.runCmd}} &>${{REPO_DIR}}/logs/measure-rss-${{RUNTIMECMD.name}}-${{ITERATION}}.log &
530563
- sh: APP_PID=$!
531564
- sh: sleep ${{PAUSE_TIME}}
@@ -544,6 +577,41 @@ scripts:
544577
with:
545578
array: RUN.output.results.${{RUNTIMECMD.name}}.rss.firstRequest
546579
value: ${{= ${{FIRST_REQUEST}}/1024 }}
580+
- read-state: ${{config.energy.idrac}}
581+
then:
582+
- regex: "enabled"
583+
then:
584+
- sh: "command -v racadm > /dev/null 2>&1 && echo IDRAC_READY"
585+
then:
586+
- regex: IDRAC_READY
587+
then:
588+
- signal: ${{COMPLETE_SIGNAL}}
589+
- sh: echo "${{RUN.svrPwr}}" > ${{OUTPUT_DIR}}/${{COMPLETE_SIGNAL}}.svrPwr
590+
- set-state: IDRAC_AVG_WATTS ${{= (${{RUN.svrPwr}}.reduce((a, b) => a + b, 0) / ${{RUN.svrPwr}}.length) || 0 }}
591+
- script: state-array-push
592+
with:
593+
array: RUN.output.results.${{RUNTIMECMD.name}}.energy.idrac
594+
value: ${{IDRAC_AVG_WATTS}}
595+
- read-state: ${{config.energy.rapl}}
596+
then:
597+
- regex: "enabled"
598+
then:
599+
- sh: "[[ -x ${{RUN.RAPL_BIN:__NORAPL__}} ]] && echo RAPL_READY"
600+
then:
601+
- regex: RAPL_READY
602+
then:
603+
- sh: awk -F', ' '/^[^#]/{s+=$2; d+=$4; n++} END{if(n>0) printf "%.2f %.2f", s/n, d/n; else print "0 0"}' ${{OUTPUT_DIR}}/${{COMPLETE_SIGNAL}}.rapl
604+
then:
605+
- regex: (?<pkg>\S+) (?<dram>\S+)
606+
then:
607+
- script: state-array-push
608+
with:
609+
array: RUN.output.results.${{RUNTIMECMD.name}}.energy.raplPkg
610+
value: ${{pkg}}
611+
- script: state-array-push
612+
with:
613+
array: RUN.output.results.${{RUNTIMECMD.name}}.energy.raplDram
614+
value: ${{dram}}
547615
- sh: kill -15 $APP_PID
548616
- sh: sleep ${{PAUSE_TIME}}
549617
- script: stop-test-services
@@ -555,6 +623,34 @@ scripts:
555623
with:
556624
var-name: RUN.output.results.${{RUNTIMECMD.name}}.rss.avFirstRequestRss
557625
array: RUN.output.results.${{RUNTIMECMD.name}}.rss.firstRequest
626+
- read-state: ${{config.energy.idrac}}
627+
then:
628+
- regex: "enabled"
629+
then:
630+
- sh: "command -v racadm > /dev/null 2>&1 && echo IDRAC_READY"
631+
then:
632+
- regex: IDRAC_READY
633+
then:
634+
- script: state-array-calc-avg
635+
with:
636+
var-name: RUN.output.results.${{RUNTIMECMD.name}}.energy.avIdrac
637+
array: RUN.output.results.${{RUNTIMECMD.name}}.energy.idrac
638+
- read-state: ${{config.energy.rapl}}
639+
then:
640+
- regex: "enabled"
641+
then:
642+
- sh: "[[ -x ${{RUN.RAPL_BIN:__NORAPL__}} ]] && echo RAPL_READY"
643+
then:
644+
- regex: RAPL_READY
645+
then:
646+
- script: state-array-calc-avg
647+
with:
648+
var-name: RUN.output.results.${{RUNTIMECMD.name}}.energy.avRaplPkg
649+
array: RUN.output.results.${{RUNTIMECMD.name}}.energy.raplPkg
650+
- script: state-array-calc-avg
651+
with:
652+
var-name: RUN.output.results.${{RUNTIMECMD.name}}.energy.avRaplDram
653+
array: RUN.output.results.${{RUNTIMECMD.name}}.energy.raplDram
558654

559655
run-load-test:
560656
- log: Running workload
@@ -805,6 +901,7 @@ roles:
805901
- ensure-container-runtime
806902
- capture-repo-info
807903
- stop-test-services
904+
- install-rapl-plot
808905
- start-timestamp
809906
run-scripts:
810907
- run-tests

scripts/perf-lab/run-benchmarks.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ help() {
3737
echo " --cpus-otel <CPUS_OTEL> CPU list for the OpenTelemetry stack (e.g. 14,16,18)"
3838
echo " Default: ${CPUS_OTEL}"
3939
echo " --description <DESCRIPTION> A human-readable description to be added to the run output"
40+
echo " --energy <ENERGY> Energy measurement sources, separated by commas"
41+
echo " Accepted values (1 or more of): rapl, idrac"
42+
echo " Special values: all, none"
43+
echo " Default: 'all'"
4044
echo " --drop-fs-caches Purge/drop OS filesystem caches between iterations"
4145
echo " --extra-qdup-args <EXTRA_QDUP_ARGS> Any extra arguments that need to be passed to qDup ahead of the qDup scripts"
4246
echo " NOTE: This is an advanced option. Make sure you know what you are doing when using it."
@@ -149,6 +153,9 @@ print_values() {
149153
echo " NATIVE_QUARKUS_BUILD_OPTIONS: $NATIVE_QUARKUS_BUILD_OPTIONS"
150154
echo " NATIVE_SPRING3_BUILD_OPTIONS: $NATIVE_SPRING3_BUILD_OPTIONS"
151155
echo " NATIVE_SPRING4_BUILD_OPTIONS: $NATIVE_SPRING4_BUILD_OPTIONS"
156+
echo " ENERGY: $ENERGY"
157+
echo " ENERGY_IDRAC: $ENERGY_IDRAC"
158+
echo " ENERGY_RAPL: $ENERGY_RAPL"
152159
echo " PROFILER: $PROFILER"
153160
echo " QUARKUS_BUILD_CONFIG_ARGS: $QUARKUS_BUILD_CONFIG_ARGS"
154161
echo " QUARKUS_VERSION: $QUARKUS_VERSION"
@@ -274,6 +281,8 @@ ${JBANG_CMD} io.hyperfoil.tools:qDup:0.11.0 \
274281
-S config.jvm.version=${JAVA_VERSION} \
275282
-S config.quarkus.native_build_options="${NATIVE_QUARKUS_BUILD_OPTIONS}" \
276283
-S config.jvm.args="${JVM_ARGS}" \
284+
-S config.energy.idrac=${ENERGY_IDRAC} \
285+
-S config.energy.rapl=${ENERGY_RAPL} \
277286
-S config.profiler.name=${PROFILER} \
278287
-S config.resources.app_cpus="$(count_cpus "${CPUS_APP}")" \
279288
-S config.resources.cpu.app="${CPUS_APP}" \
@@ -332,6 +341,10 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
332341
NATIVE_QUARKUS_BUILD_OPTIONS=""
333342
NATIVE_SPRING3_BUILD_OPTIONS=""
334343
NATIVE_SPRING4_BUILD_OPTIONS=""
344+
ENERGY="all"
345+
ALLOWED_ENERGY=("rapl" "idrac")
346+
ENERGY_IDRAC="enabled"
347+
ENERGY_RAPL="enabled"
335348
PROFILER="none"
336349
QUARKUS_BUILD_CONFIG_ARGS=""
337350
QUARKUS_VERSION=""
@@ -390,6 +403,37 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
390403
shift
391404
;;
392405

406+
--energy)
407+
ENERGY_SET_BY_USER="true"
408+
ENERGY="$2"
409+
ENERGY_IDRAC="disabled"
410+
ENERGY_RAPL="disabled"
411+
412+
if [[ "$2" == "all" ]]; then
413+
ENERGY_IDRAC="enabled"
414+
ENERGY_RAPL="enabled"
415+
elif [[ "$2" == "none" ]]; then
416+
: # both already disabled
417+
else
418+
en=($(IFS=','; echo $2))
419+
420+
for item in "${en[@]}"; do
421+
if [[ ! "${ALLOWED_ENERGY[@]}" =~ "${item}" ]]; then
422+
echo "!! [ERROR] --energy option must be 'all', 'none', or 1 or more of [${ALLOWED_ENERGY[@]}]!!"
423+
exit_abnormal
424+
fi
425+
done
426+
427+
for item in "${en[@]}"; do
428+
case "$item" in
429+
rapl) ENERGY_RAPL="enabled" ;;
430+
idrac) ENERGY_IDRAC="enabled" ;;
431+
esac
432+
done
433+
fi
434+
shift 2
435+
;;
436+
393437
--extra-qdup-args)
394438
EXTRA_QDUP_ARGS="$2"
395439
shift 2
@@ -585,6 +629,13 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
585629
done
586630
TESTS_TO_RUN=${filtered_tests[@]}
587631

632+
# If user explicitly set --energy, ensure measure-rss is in the test list
633+
if [[ -n "${ENERGY_SET_BY_USER:-}" && "$ENERGY" != "none" ]]; then
634+
if [[ ! "${TESTS_TO_RUN[@]}" =~ "measure-rss" ]]; then
635+
TESTS_TO_RUN="$TESTS_TO_RUN measure-rss"
636+
fi
637+
fi
638+
588639
validate_values
589640
calculate_scenario
590641
print_values

0 commit comments

Comments
 (0)