diff --git a/.github/workflows/dev-long-tests.yml b/.github/workflows/dev-long-tests.yml index 4b0f6c2acee..fab0b96203f 100644 --- a/.github/workflows/dev-long-tests.yml +++ b/.github/workflows/dev-long-tests.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: make test run: | - make test + make -j test make -j zstd ./tests/test_process_substitution.bash ./zstd @@ -40,7 +40,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: make test on macos - run: make test + run: make -j test # lasts ~10mn make-test-32bit: @@ -72,7 +72,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: no intrinsics fuzztest - run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -C tests fuzztest + run: MOREFLAGS="-DZSTD_NO_INTRINSICS" make -j -C tests fuzztest # lasts ~8mn tsan-zstreamtest: @@ -95,7 +95,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: thread sanitizer fuzztest - run: CC=clang make tsan-fuzztest + run: CC=clang make -j tsan-fuzztest big-tests-zstreamtest32: runs-on: ubuntu-latest @@ -151,14 +151,14 @@ jobs: echo "deb [arch=amd64] http://archive.ubuntu.com/ubuntu focal main universe" | sudo tee -a /etc/apt/sources.list sudo apt-get -qqq update make gcc8install - CC=gcc-8 FUZZER_FLAGS="--long-tests" make clean uasan-fuzztest + CC=gcc-8 FUZZER_FLAGS="--long-tests" make -j clean uasan-fuzztest clang-asan-ubsan-fuzz: runs-on: ubuntu-latest steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: clang + ASan + UBSan + Fuzz Test - run: CC=clang FUZZER_FLAGS="--long-tests" make clean uasan-fuzztest + run: CC=clang FUZZER_FLAGS="--long-tests" make -j clean uasan-fuzztest # the only job decoding real legacy frames under sanitizers. # fuzzers do build these decoders, but only reach them if an input @@ -178,7 +178,7 @@ jobs: run: | sudo apt-get -qqq update make libc6install - CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make uasan-fuzztest + CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make -j uasan-fuzztest clang-asan-fuzz32: runs-on: ubuntu-latest @@ -188,7 +188,7 @@ jobs: run: | sudo apt-get -qqq update make libc6install - CC=clang CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make asan-fuzztest + CC=clang CFLAGS="-O3 -m32" FUZZER_FLAGS="--long-tests" make -j asan-fuzztest # The following test seems to have issues on github CI specifically, # it does not provide the `__mulodi4` instruction emulation @@ -231,10 +231,12 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: clang + MSan + Fuzz Test + # -O0 targets the unit tests on unoptimized code: random fuzzing is kept short. + # clang-msan-fuzz runs the long random fuzzing. run: | sudo apt-get -qqq update sudo apt-get install clang - CC=clang MOREFLAGS="-O0" make clean msan-fuzztest + CC=clang MOREFLAGS="-O0" FUZZERTEST=-T60s ZSTREAM_TESTTIME=-T30s make clean msan-fuzztest clang-msan-fuzz: runs-on: ubuntu-latest @@ -251,8 +253,10 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # tag=v7.0.1 - name: clang + MSan + Test Zstd + # ZSTDRTTEST= : skip the large data tests of playTests.sh, too slow under MSan. + # They still run in the make-test* and ASan + UBSan testzstd jobs. run: | - CC=clang make -j msan-test-zstd HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=0 V=1 + CC=clang make -j msan-test-zstd HAVE_ZLIB=0 HAVE_LZ4=0 HAVE_LZMA=0 ZSTDRTTEST= V=1 armfuzz: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 03ecbde6af8..6868bc7245d 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ googletest/ *.d *.vscode *.code-workspace +.claude/ compile_commands.json .clangd perf.data diff --git a/tests/fuzz/README.md b/tests/fuzz/README.md index e2196e832c6..8732c8c3978 100644 --- a/tests/fuzz/README.md +++ b/tests/fuzz/README.md @@ -105,7 +105,7 @@ CC=afl-clang CXX=afl-clang++ ./fuzz.py build all --enable-asan --enable-ubsan ## Regression Testing The regression test supports the `all` target to run all the fuzzers in one -command. +command. Targets run in parallel, one per CPU. ``` CC=clang CXX=clang++ ./fuzz.py build all --enable-asan --enable-ubsan diff --git a/tests/fuzz/fuzz.py b/tests/fuzz/fuzz.py index 492be3486d0..22a1ee3f925 100755 --- a/tests/fuzz/fuzz.py +++ b/tests/fuzz/fuzz.py @@ -11,6 +11,7 @@ # ########################################################################## import argparse +import concurrent.futures import contextlib import os import re @@ -648,6 +649,13 @@ def afl(args): return 0 +def corpus_size(target): + size = 0 + for root, _, files in os.walk(abs_join(CORPORA_DIR, target)): + size += sum(os.path.getsize(os.path.join(root, f)) for f in files) + return size + + def regression(args): try: description = """ @@ -655,18 +663,34 @@ def regression(args): The fuzzer should have been built with LIB_FUZZING_ENGINE='libregression.a'. Takes input from CORPORA. + Targets run in parallel, one per CPU. """ args = targets_parser(args, description) except Exception as e: print(e) return 1 - for target in args.TARGET: + + def run(target): corpora = create(abs_join(CORPORA_DIR, target)) - target = abs_join(FUZZ_DIR, target) - cmd = [target, corpora] - print(' '.join(cmd)) - subprocess.check_call(cmd) - return 0 + cmd = [abs_join(FUZZ_DIR, target), corpora] + result = subprocess.run(cmd, stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + return cmd, result + + # Largest corpora take longest: start them first + targets = sorted(args.TARGET, key=corpus_size, reverse=True) + failed = [] + with concurrent.futures.ThreadPoolExecutor(os.cpu_count()) as pool: + runs = [pool.submit(run, target) for target in targets] + for done in concurrent.futures.as_completed(runs): + cmd, result = done.result() + print(' '.join(cmd)) + print(result.stdout.decode(errors='replace'), end='', flush=True) + if result.returncode != 0: + failed.append(cmd[0]) + for target in failed: + print('FAILED: {}'.format(target)) + return 1 if failed else 0 def gen_parser(args): diff --git a/tests/playTests.sh b/tests/playTests.sh index d8ea0c3dad3..44bc82b5610 100755 --- a/tests/playTests.sh +++ b/tests/playTests.sh @@ -1909,10 +1909,10 @@ println "- Create second (different) dictionary" zstd -T0 --train-cover=k=56,d=8 "$TESTDIR"/*.c "$PRGDIR"/*.c "$PRGDIR"/*.h -o tmpDictC zstd -d tmp.zst -D tmpDictC -fo result && die "wrong dictionary not detected!" println "- Create dictionary using shrink-dict flag" -zstd -T0 --train-cover=steps=256,shrink "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict -zstd -T0 --train-cover=steps=256,shrink=1 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict1 -zstd -T0 --train-cover=steps=256,shrink=5 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict2 -zstd -T0 --train-cover=shrink=5,steps=256 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict3 +zstd -T0 --train-cover=steps=7,shrink "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict +zstd -T0 --train-cover=steps=7,shrink=1 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict1 +zstd -T0 --train-cover=steps=7,shrink=5 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict2 +zstd -T0 --train-cover=shrink=5,steps=7 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpShrinkDict3 println "- Create dictionary with short dictID" zstd -T0 --train-cover=k=46,d=8,split=80 "$TESTDIR"/*.c "$PRGDIR"/*.c --dictID=1 -o tmpDict1 cmp tmpDict tmpDict1 && die "dictionaries should have different ID !"