Skip to content

Commit ce07a2c

Browse files
authored
Merge pull request #2995 from meddle0x53/staging
Implement reporting unit test timings in CI
2 parents 1337b39 + 09df9e0 commit ce07a2c

File tree

2 files changed

+217
-15
lines changed

2 files changed

+217
-15
lines changed

.circleci/config.yml

Lines changed: 216 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,181 @@ commands:
149149
- checkout
150150
- setup_environment:
151151
cache_key: v4.2.0-rust-1.88.0-<< parameters.workspace_member >><< parameters.cache_key_suffix >>-cache
152+
153+
- run:
154+
name: Install cargo-nextest
155+
command: |
156+
cargo install cargo-nextest --locked || true
157+
152158
- run:
153159
name: "Run Tests"
154160
timeout: << parameters.timeout >>
155161
no_output_timeout: << parameters.no_output_timeout >>
156-
command: RUST_MIN_STACK=67108864 cargo test --package=<< parameters.workspace_member >> << parameters.flags >>
162+
command: |
163+
set -euo pipefail
164+
export CARGO_TERM_COLOR=never
165+
166+
# Create artifact + nextest output directories
167+
mkdir -p artifacts target/nextest/ci
168+
169+
# Create artifact + nextest output directories
170+
OUT="artifacts/<< parameters.workspace_member >>-nextest.txt"
171+
CSV="artifacts/<< parameters.workspace_member >>-test-times.csv"
172+
TOP="artifacts/<< parameters.workspace_member >>-slow-tests-top30.csv"
173+
JUNIT="target/nextest/ci/junit.xml"
174+
175+
# Extract and trim flags from parameters
176+
FLAGS_FULL="<< parameters.flags >>"
177+
FLAGS_TRIM="$(printf '%s' "$FLAGS_FULL" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
178+
179+
# Split flags into cargo build flags (before --) and libtest args (after --)
180+
RIGHT_OF_SEP=""
181+
if printf '%s' "$FLAGS_TRIM" | grep -q ' -- '; then
182+
BUILD_FLAGS="${FLAGS_TRIM%% -- *}"
183+
RIGHT_OF_SEP="${FLAGS_TRIM#* -- }"
184+
elif printf '%s' "$FLAGS_TRIM" | grep -Eq '^--[[:space:]]'; then
185+
BUILD_FLAGS=""
186+
RIGHT_OF_SEP="${FLAGS_TRIM#-- }"
187+
else
188+
BUILD_FLAGS="$FLAGS_TRIM"
189+
fi
190+
191+
# Remove any --test target flags,they cause nextest build errors
192+
BUILD_FLAGS_SANITIZED="$(printf '%s' "$BUILD_FLAGS" \
193+
| sed -E "s/(^|[[:space:]])--test[[:space:]]+'[^']*'([[:space:]]|$)/ /g" \
194+
| sed -E 's/(^|[[:space:]])--test[[:space:]]+\"[^\"]*\"([[:space:]]|$)/ /g' \
195+
| sed -E 's/(^|[[:space:]])--test[[:space:]]+[^[:space:]]+([[:space:]]|$)/ /g' \
196+
| tr -s ' ' | sed -E 's/^[[:space:]]+//; s/[[:space:]]+$//' \
197+
)"
198+
199+
# Detect wildcard integration selection: `--test '*'` (with or without quotes)
200+
HAS_TEST_WILDCARD=0
201+
if printf '%s\n' "$BUILD_FLAGS" | grep -Eq -- '--test[[:space:]]+("\*"|'\''\*'\''|\*)'; then
202+
HAS_TEST_WILDCARD=1
203+
fi
204+
205+
# Build nextest filter expression from any --skip <pattern> arguments
206+
FILTER_EXPR=""
207+
208+
WSM="<< parameters.workspace_member >>"
209+
if [ "$WSM" = "snarkvm-synthesizer" ] && [ "$HAS_TEST_WILDCARD" -eq 1 ]; then
210+
FILTER_EXPR='test(/test_command_parse/)+test(/test_instruction_parse/)+test(/test_process_execute/)+test(/test_program_parse/)+test(/test_vm_execute_and_finalize/)'
211+
fi
212+
213+
# Build nextest filter expression from any --skip <pattern> arguments
214+
if [ -z "$FILTER_EXPR" ] && [ -n "$RIGHT_OF_SEP" ]; then
215+
SKIPS="$(printf '%s\n' "$RIGHT_OF_SEP" \
216+
| sed -E 's/[[:space:]]+/ /g' \
217+
| grep -oE -- '--skip[[:space:]]+(\"[^\"]+\"|'\''[^'\'']+'\''|[^[:space:]]+)' || true)"
218+
if [ -n "$SKIPS" ]; then
219+
EXPRS=""
220+
tmpf="$(mktemp)"
221+
printf '%s\n' "$SKIPS" > "$tmpf"
222+
while IFS= read -r line; do
223+
pat="${line#--skip }"
224+
pat="${pat%\"}"; pat="${pat#\"}"
225+
pat="${pat%\'}"; pat="${pat#\'}"
226+
pat_rx="${pat//\//\\/}" # escape forward slashes for regex
227+
if [ -z "$EXPRS" ]; then
228+
EXPRS="test(/$pat_rx/)"
229+
else
230+
EXPRS="$EXPRS or test(/$pat_rx/)"
231+
fi
232+
done < "$tmpf"
233+
rm -f "$tmpf"
234+
if [ -n "$EXPRS" ]; then
235+
FILTER_EXPR="not ($EXPRS)"
236+
fi
237+
fi
238+
fi
239+
240+
# Detect and extract --test-threads value (used to set JOBS)
241+
TEST_THREADS=""
242+
if [ -n "$RIGHT_OF_SEP" ]; then
243+
# form: --test-threads=8
244+
TEST_THREADS="$(printf '%s\n' "$RIGHT_OF_SEP" | sed -nE 's/.*--test-threads=([0-9]+).*/\1/p' | head -n1)"
245+
if [ -z "$TEST_THREADS" ]; then
246+
# form: --test-threads 8
247+
TEST_THREADS="$(printf '%s\n' "$RIGHT_OF_SEP" | sed -nE 's/.*--test-threads[[:space:]]+([0-9]+).*/\1/p' | head -n1)"
248+
fi
249+
fi
250+
251+
DEFAULT_JOBS=12
252+
253+
# Default JOBS, overridden by TEST_THREADS if set
254+
JOBS="${NEXTEST_JOBS:-$DEFAULT_JOBS}"
255+
if [ -n "$TEST_THREADS" ]; then
256+
JOBS="$TEST_THREADS"
257+
fi
258+
259+
# Create nextest config (disable fail-fast, add slow-timeout + JUnit output)
260+
SLOW_PERIOD="${NEXTEST_SLOW_PERIOD:-60s}"
261+
CFG_ARGS=()
262+
TMPD="$(mktemp -d)"
263+
if [ -f ".config/nextest.toml" ]; then
264+
CFG_ARGS+=(--config-file ".config/nextest.toml")
265+
fi
266+
{
267+
printf '%s\n' '[profile.ci]'
268+
printf '%s\n' 'fail-fast = false'
269+
printf '%s\n' "slow-timeout = \"${SLOW_PERIOD}\""
270+
printf '%s\n' ''
271+
printf '%s\n' '[profile.ci.junit]'
272+
printf '%s\n' 'path = "junit.xml"'
273+
} > "$TMPD/nextest-override.toml"
274+
CFG_ARGS+=(--config-file "$TMPD/nextest-override.toml")
275+
276+
# Print configuration summary for debugging
277+
echo "==> nextest package: << parameters.workspace_member >>"
278+
echo "==> build flags (sanitized): '${BUILD_FLAGS_SANITIZED}'"
279+
echo "==> filter-expr: ${FILTER_EXPR:-<none>} (right-of-sep: ${RIGHT_OF_SEP:-<none>})"
280+
echo "==> test-threads override: ${TEST_THREADS:-<none>}"
281+
echo "==> jobs: ${JOBS}"
282+
283+
# Use plain cargo test if --no-run was requested
284+
# Otherwise, run tests with cargo nextest
285+
if printf '%s' " $BUILD_FLAGS_SANITIZED " | grep -q ' --no-run '; then
286+
RUST_MIN_STACK=67108864 cargo test --package="<< parameters.workspace_member >>" $BUILD_FLAGS_SANITIZED | tee "$OUT"
287+
: > "$CSV"; : > "$TOP"
288+
else
289+
RUST_MIN_STACK=67108864 cargo nextest run \
290+
-p "<< parameters.workspace_member >>" $BUILD_FLAGS_SANITIZED \
291+
--profile ci -j "${JOBS}" "${CFG_ARGS[@]}" \
292+
--status-level fail --hide-progress-bar \
293+
--no-tests=pass \
294+
${FILTER_EXPR:+--filter-expr "$FILTER_EXPR"} \
295+
2>&1 | tee "$OUT"
296+
297+
# Parse junit.xml to extract test timings
298+
if [ -f "$JUNIT" ]; then
299+
awk -v RS='<testcase ' '
300+
NR>1 {
301+
name=""; classname=""; time="";
302+
start=index($0,"classname=\""); if(start>0){ start+=11; rest=substr($0,start); end=index(rest,"\""); if(end>0) classname=substr(rest,1,end-1) }
303+
start=index($0,"name=\""); if(start>0){ start+=6; rest=substr($0,start); end=index(rest,"\""); if(end>0) name=substr(rest,1,end-1) }
304+
start=index($0,"time=\""); if(start>0){ start+=6; rest=substr($0,start); end=index(rest,"\""); if(end>0) time=substr(rest,1,end-1) }
305+
if(name!="" && time!=""){ full=(classname!=""?classname"::"name:name); printf "%s,%s\n", full, time }
306+
}
307+
' "$JUNIT" > "$CSV" || true
308+
309+
# Sort and store top 30 slowest tests
310+
sort -t, -k2,2nr "$CSV" | head -n 30 > "$TOP" || true
311+
else
312+
echo "WARN: $JUNIT not found; no timings extracted." >&2
313+
: > "$CSV"; : > "$TOP"
314+
fi
315+
fi
316+
317+
- store_artifacts:
318+
path: artifacts
319+
destination: test-timings/<< parameters.workspace_member >>
320+
- store_test_results:
321+
path: target/nextest/ci
322+
157323
- clear_environment:
158324
cache_key: v4.2.0-rust-1.88.0-<< parameters.workspace_member >><< parameters.cache_key_suffix >>-cache
159325

326+
160327
install_rust_nightly:
161328
description: "Install Rust nightly toolchain"
162329
steps:
@@ -439,14 +606,25 @@ jobs:
439606
- run_test:
440607
workspace_member: snarkvm-ledger
441608

442-
ledger-with-rocksdb:
609+
ledger-with-rocksdb-partition1:
443610
executor: rust-docker
444611
resource_class: << pipeline.parameters.large >>
445612
steps:
446613
- run_test:
447614
workspace_member: snarkvm-ledger
448-
flags: --release --features=rocks -- --test-threads=2
449-
timeout: 20m
615+
flags: --release --features=rocks --partition count:1/2 -- --test-threads=8
616+
no_output_timeout: 20m
617+
timeout: 30m
618+
619+
ledger-with-rocksdb-partition2:
620+
executor: rust-docker
621+
resource_class: << pipeline.parameters.large >>
622+
steps:
623+
- run_test:
624+
workspace_member: snarkvm-ledger
625+
flags: --release --features=rocks --partition count:2/2 -- --test-threads=8
626+
no_output_timeout: 20m
627+
timeout: 30m
450628

451629
ledger-with-valid-solutions:
452630
executor: rust-docker
@@ -470,6 +648,8 @@ jobs:
470648
steps:
471649
- run_test:
472650
workspace_member: snarkvm-ledger-block
651+
no_output_timeout: 20m
652+
timeout: 30m
473653

474654
ledger-committee:
475655
executor: rust-docker
@@ -593,24 +773,44 @@ jobs:
593773
workspace_member: snarkvm-parameters
594774
flags: -- --test-threads=2 --ignored test_load_bytes_mini
595775
cache_key_suffix: -v-{{ epoch }}
776+
no_output_timeout: 20m
777+
timeout: 30m
596778

597779
synthesizer:
598780
executor: rust-docker
599781
resource_class: << pipeline.parameters.twoxlarge >>
600782
steps:
601783
- run_test:
602784
workspace_member: snarkvm-synthesizer
603-
flags: --lib --bins
604-
timeout: 20m
785+
flags: --lib --bins -- --test-threads 16
786+
no_output_timeout: 20m
787+
timeout: 30m
605788

606-
synthesizer-test:
789+
synthesizer-test-partition1:
607790
executor: rust-docker
608791
resource_class: << pipeline.parameters.twoxlarge >>
609792
steps:
610793
- run_test:
611794
workspace_member: snarkvm-synthesizer
612-
flags: --lib --bins --features test
613-
cache_key_suffix: -test
795+
# nextest args before `--`, libtest args after `--`
796+
flags: >
797+
--lib --bins --features test
798+
--partition count:1/2
799+
-- --test-threads 16
800+
cache_key_suffix: -test1
801+
timeout: 25m
802+
803+
synthesizer-test-partition2:
804+
executor: rust-docker
805+
resource_class: << pipeline.parameters.twoxlarge >>
806+
steps:
807+
- run_test:
808+
workspace_member: snarkvm-synthesizer
809+
flags: >
810+
--lib --bins --features test
811+
--partition count:2/2
812+
-- --test-threads 16
813+
cache_key_suffix: -test2
614814
timeout: 25m
615815

616816
# synthesizer-mem-heavy:
@@ -631,7 +831,7 @@ jobs:
631831
# test_vm_execute_and_finalize can take over 10 minutes in the current setup
632832
no_output_timeout: 20m
633833
workspace_member: snarkvm-synthesizer
634-
flags: --test '*' --features test -- --test-threads=4
834+
flags: --test '*' --features test -- --test-threads=4
635835
cache_key_suffix: -integration
636836

637837
synthesizer-process:
@@ -640,15 +840,14 @@ jobs:
640840
steps:
641841
- run_test:
642842
workspace_member: snarkvm-synthesizer-process
643-
flags: -- --test-threads=8
644843

645844
synthesizer-process-with-rocksdb:
646845
executor: rust-docker
647846
resource_class: << pipeline.parameters.xlarge >>
648847
steps:
649848
- run_test:
650849
workspace_member: snarkvm-synthesizer-process
651-
flags: --features=rocks
850+
flags: --features=rocks -- --test-threads=4
652851
cache_key_suffix: -with-rocksdb
653852

654853
synthesizer-program:
@@ -665,7 +864,7 @@ jobs:
665864
steps:
666865
- run_test:
667866
workspace_member: snarkvm-synthesizer-program
668-
flags: -- --skip keccak --skip psd --skip sha --skip instruction::is --skip instruction::equal --skip instruction::commit
867+
flags: -- --skip keccak --skip psd --skip sha --skip instruction::is --skip instruction::equal --skip instruction::commit --test-threads=8
669868
cache_key_suffix: -integration
670869

671870
synthesizer-program-integration-keccak:
@@ -935,7 +1134,8 @@ workflows:
9351134
ledger-workflow:
9361135
jobs:
9371136
- ledger
938-
- ledger-with-rocksdb
1137+
- ledger-with-rocksdb-partition1
1138+
- ledger-with-rocksdb-partition2
9391139
- ledger-with-valid-solutions
9401140
- ledger-authority
9411141
- ledger-block
@@ -956,7 +1156,8 @@ workflows:
9561156
synthesizer-workflow:
9571157
jobs:
9581158
- synthesizer
959-
- synthesizer-test
1159+
- synthesizer-test-partition1
1160+
- synthesizer-test-partition2
9601161
# - synthesizer-mem-heavy
9611162
- synthesizer-integration
9621163
- synthesizer-process

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
!**/beta-h.usrs
1515
!**/neg-powers-of-beta.usrs
1616
**/proptest-regressions/
17+
artifacts

0 commit comments

Comments
 (0)