@@ -29,6 +29,10 @@ source $(dirname $0)/../buildlib/tools/common.sh
2929WORKSPACE=${WORKSPACE:= $PWD }
3030ucx_inst=${WORKSPACE} /install
3131
32+ # Absolute path to the source tree, captured before any 'cd' so it stays valid
33+ # regardless of the current directory at call time.
34+ ucx_src_dir=$( cd " $( dirname " $0 " ) " && pwd)
35+
3236if [ -z " $BUILD_NUMBER " ]; then
3337 echo " Running interactive"
3438 BUILD_NUMBER=1
@@ -178,6 +182,7 @@ run_client_server_app() {
178182 server_addr_arg=$3
179183 kill_server=$4
180184 error_emulation=$5
185+ out_file=${6:- }
181186
182187 server_port_arg=" -p $server_port "
183188 step_server_port
@@ -195,11 +200,19 @@ run_client_server_app() {
195200 set +Ee
196201 fi
197202
198- taskset -c $affinity_client ${test_exe} ${test_args} ${server_addr_arg} ${server_port_arg} &
203+ if [ -n " ${out_file} " ]
204+ then
205+ taskset -c $affinity_client ${test_exe} ${test_args} ${server_addr_arg} ${server_port_arg} > " ${out_file} " 2>&1 &
206+ else
207+ taskset -c $affinity_client ${test_exe} ${test_args} ${server_addr_arg} ${server_port_arg} &
208+ fi
199209 client_pid=$!
200210
201211 wait ${client_pid}
202212
213+ # Echo captured output so it still appears in the CI log.
214+ [ -n " ${out_file} " ] && cat " ${out_file} " || true
215+
203216 if [ $error_emulation -eq 1 ]
204217 then
205218 set -eE
@@ -634,7 +647,53 @@ run_ucx_perftest_with_daemon() {
634647}
635648
636649#
637- # Run UCX performance cuda device test
650+ # Run the cuda device perftest against a given install prefix, capturing the
651+ # client output to a results file (when given).
652+ #
653+ run_device_perftest_at () {
654+ local inst=$1
655+ local out_file=${2:- }
656+ # TODO: Run on all GPUs & NICs combinations
657+ local ucp_test_args=" -b ${inst} /share/ucx/perftest/test_types_ucp_device_cuda"
658+ local ucp_client_args=" -a cuda:0 $( hostname) "
659+
660+ # TODO: Run with cuda_ipc_tls (cuda_copy,rc,cuda_ipc)
661+ export UCX_TLS=" cuda_copy,rc,rc_gda"
662+ run_client_server_app " ${inst} /bin/ucx_perftest" " ${ucp_test_args} " \
663+ " ${ucp_client_args} " 0 0 " ${out_file} "
664+ unset UCX_TLS
665+ }
666+
667+ #
668+ # Build UCX at a specific commit into a separate prefix ($base_inst), used to
669+ # produce the "before" binaries for perf regression compare. Built in devel
670+ # mode to match the head leg's devel build (line ~1335); --enable-gtest is
671+ # omitted on purpose - it adds the gtest suite but does not change the
672+ # ucx_perftest / libucp / libuct codegen, so the comparison stays fair.
673+ #
674+ build_ucx_at_commit () {
675+ local sha=$1
676+ local base_src=" ${WORKSPACE} /base-src"
677+ base_inst=" ${WORKSPACE} /install-base"
678+
679+ (cd " ${WORKSPACE} " && git worktree add -f --detach " ${base_src} " " ${sha} " ) \
680+ || return 1
681+
682+ local rc=0
683+ (
684+ WORKSPACE=" ${base_src} "
685+ ucx_inst=" ${base_inst} "
686+ prepare
687+ build devel --without-valgrind
688+ ) || rc=1
689+
690+ (cd " ${WORKSPACE} " && git worktree remove --force " ${base_src} " ) || true
691+ return ${rc}
692+ }
693+
694+ #
695+ # Run UCX performance cuda device test, and (on a PR build) compare the
696+ # bandwidth/latency against the PR base to catch device-API regressions.
638697#
639698run_ucx_perftest_cuda_device () {
640699 if [ " X$have_cuda " == " Xno" ]; then
@@ -652,23 +711,50 @@ run_ucx_perftest_cuda_device() {
652711 return 0
653712 fi
654713
655- echo " ==== Running ucx_perftest with cuda kernel ===="
656- ucx_inst_ptest=$ucx_inst /share/ucx/perftest
657- ucx_perftest=" $ucx_inst /bin/ucx_perftest"
658- ucp_test_args=" -b $ucx_inst_ptest /test_types_ucp_device_cuda"
714+ echo " ==== Running ucx_perftest with cuda kernel ===="
715+ local repeat=" ${UCX_PERFTEST_REPEAT:- 3} "
716+ # OSU perf (dedicated nodes) uses 5%; device perf runs on shared, noisier
717+ # GPU CI nodes, so the default tolerance is higher.
718+ local threshold=" ${UCX_PERFTEST_REGRESSION_THRESHOLD:- 15} "
719+ local res_dir=" ${WORKSPACE} /device_perf"
720+ rm -rf " ${res_dir} "
721+ mkdir -p " ${res_dir} "
722+
723+ # On a PR build the checkout is the merge ref: HEAD^1 is the target branch
724+ # tip (base) and HEAD^2 is the PR head. master / non-merge builds have no
725+ # HEAD^2, so there is nothing to compare against - run once for coverage.
726+ if ! (cd " ${WORKSPACE} " && git rev-parse --verify -q HEAD^2 > /dev/null 2>&1 )
727+ then
728+ echo " ==== Not a PR merge build; running device perftest without comparison ===="
729+ run_device_perftest_at " ${ucx_inst} " " "
730+ return 0
731+ fi
659732
660- # TODO: Run on all GPUs & NICs combinations
661- ucp_client_args=" -a cuda:0 $( hostname) "
662- gda_tls=" cuda_copy,rc,rc_gda"
663- cuda_ipc_tls=" cuda_copy,rc,cuda_ipc"
733+ local base_sha
734+ base_sha=$( cd " ${WORKSPACE} " && git rev-parse HEAD^1)
735+ echo " ==== Building base ${base_sha} for device perftest comparison ===="
736+ if ! build_ucx_at_commit " ${base_sha} "
737+ then
738+ echo " ==== Base build failed; running device perftest without comparison ===="
739+ run_device_perftest_at " ${ucx_inst} " " "
740+ return 0
741+ fi
664742
665- # TODO: Run with cuda_ipc_tls
666- for tls in " $gda_tls "
743+ # Interleave head/base runs so both see the same node-load window - on the
744+ # shared GPU CI nodes, measuring them far apart would skew the comparison.
745+ local i
746+ for i in $( seq 1 " ${repeat} " )
667747 do
668- export UCX_TLS= ${tls}
669- run_client_server_app " $ucx_perftest " " $ucp_test_args " " $ucp_client_args " 0 0
748+ run_device_perftest_at " ${ucx_inst} " " ${res_dir} /head. ${i} .txt "
749+ run_device_perftest_at " ${base_inst} " " ${res_dir} /base. ${i} .txt "
670750 done
671- unset UCX_TLS
751+
752+ echo " ==== Comparing device perftest: base vs head ===="
753+ python3 " ${ucx_src_dir} /../buildlib/tools/compare_ucx_perftest.py" \
754+ --names " ${ucx_inst} /share/ucx/perftest/test_types_ucp_device_cuda" \
755+ --threshold " ${threshold} " \
756+ --base " ${res_dir} " /base.* .txt \
757+ --head " ${res_dir} " /head.* .txt
672758}
673759
674760#
0 commit comments