https://gcc.gnu.org/bugzilla/show_bug.cgi?id=91101
Bug ID: 91101 Summary: Possible performance regression in libasan with detect_stack_use_after_return=1 Product: gcc Version: 9.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: sanitizer Assignee: unassigned at gcc dot gnu.org Reporter: frantisek at sumsal dot cz CC: dodji at gcc dot gnu.org, dvyukov at gcc dot gnu.org, jakub at gcc dot gnu.org, kcc at gcc dot gnu.org, marxin at gcc dot gnu.org Target Milestone: --- Hello, in systemd we recently noticed[0], that certain CI's started timeouting after upgrade to gcc 9.1.0 and 9.1.1. After a bit of investigation it seems that the runtime of instrumented binaries with ASan is more than doubled. (The GitHub thread contains claims about the performance issue being present even without sanitizers, but that hasn't been confirmed yet, so please ignore it). Also, I apologize if this report is useless for upstream, since it's not using the trunk GCC, but I'd really like to know if we're doing something fundamentally wrong or if this is an actual issue. The following report is from Arch Linux with GCC 9.1.0, but I also managed to reproduce this on Fedora Rawhide with GCC 9.1.1[1]. As this thread is without any response so far, I've been trying to collect as much information as possible regarding this issue, as testing systemd with bleeding-edge software is particularly important for us. The following statistics provide comparison between two particular systemd test cases compiled with GCC 8.3.0 (with and without ASan and UBSan) and the same statistics for GCC 9.1.0: ---- [vagrant@arch build]$ pacman -Q gcc gcc-libs gcc 8.3.0-1 gcc-libs 8.3.0-1 [vagrant@arch build]$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/8.3.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto Thread model: posix gcc version 8.3.0 (GCC) # Basically git clone https://github.com/systemd/systemd /build [vagrant@arch build]$ meson build-gcc-8.3.0-sanitizers -Db_sanitize=address,undefined <...snip...> [vagrant@arch build]$ meson build-gcc-8.3.0 <...snip...> [vagrant@arch build]$ ninja -C build-gcc-8.3.0-sanitizers <...snip...> [vagrant@arch build]$ ninja -C build-gcc-8.3.0 <...snip...> # Sanitizer-specific options [vagrant@arch build]$ export ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 [vagrant@arch build]$ export UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 # WITHOUT sanitizers [vagrant@arch build]$ /bin/time -v build-gcc-8.3.0/test-conf-parser >/dev/null <...snip...> Command being timed: "build-gcc-8.3.0/test-conf-parser" User time (seconds): 1.25 System time (seconds): 0.01 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.28 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 9944 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 930 Voluntary context switches: 12 Involuntary context switches: 107 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 [vagrant@arch build]$ cd build-gcc-8.3.0 && /bin/time -v ../test/hwdb-test.sh >/dev/null Command being timed: "../test/hwdb-test.sh" User time (seconds): 0.40 System time (seconds): 0.01 Percent of CPU this job got: 98% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.41 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 25752 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 0 Minor (reclaiming a frame) page faults: 7264 Voluntary context switches: 71 Involuntary context switches: 30 Swaps: 0 File system inputs: 0 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 # WITH sanitizers [vagrant@arch build]$ /bin/time -v build-gcc-8.3.0-sanitizers/test-conf-parser >/dev/null <...snip...> Command being timed: "build-gcc-8.3.0-sanitizers/test-conf-parser" User time (seconds): 3.05 System time (seconds): 0.28 Percent of CPU this job got: 92% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:03.61 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 347056 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 16 Minor (reclaiming a frame) page faults: 180270 Voluntary context switches: 85 Involuntary context switches: 395 Swaps: 0 File system inputs: 35568 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 [vagrant@arch build]$ cd build-gcc-8.3.0-sanitizers/ && /bin/time -v ../test/hwdb-test.sh >/dev/null Command being timed: "../test/hwdb-test.sh" User time (seconds): 40.08 System time (seconds): 31.98 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 1:12.41 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 805060 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 3 Minor (reclaiming a frame) page faults: 22857463 Voluntary context switches: 97 Involuntary context switches: 414 Swaps: 0 File system inputs: 288 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 # GCC upgrade [vagrant@arch build]$ sudo pacman -Sy gcc gcc-libs ... Packages (2) gcc-9.1.0-2 gcc-libs-9.1.0-2 ... [vagrant@arch build]$ gcc -v Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/9.1.0/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto Thread model: posix gcc version 9.1.0 (GCC) [vagrant@arch build]$ meson build-gcc-9.1.0-sanitizers -Db_sanitize=address,undefined <...snip...> [vagrant@arch build]$ meson build-gcc-9.1.0 <...snip...> [vagrant@arch build]$ ninja -C build-gcc-9.1.0-sanitizers <...snip...> [vagrant@arch build]$ ninja -C build-gcc-9.1.0 <...snip...> # WITHOUT sanitizers [vagrant@arch build]$ /bin/time -v build-gcc-9.1.0/test-conf-parser >/dev/null <...snip...> Command being timed: "build-gcc-9.1.0/test-conf-parser" User time (seconds): 1.26 System time (seconds): 0.00 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:01.28 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 10016 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 1 Minor (reclaiming a frame) page faults: 928 Voluntary context switches: 6 Involuntary context switches: 111 Swaps: 0 File system inputs: 96 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 [vagrant@arch build]$ cd build-gcc-9.1.0 && /bin/time -v ../test/hwdb-test.sh >/dev/null Command being timed: "../test/hwdb-test.sh" User time (seconds): 0.43 System time (seconds): 0.03 Percent of CPU this job got: 95% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.49 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 25856 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 3 Minor (reclaiming a frame) page faults: 7279 Voluntary context switches: 108 Involuntary context switches: 68 Swaps: 0 File system inputs: 1144 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 # WITH sanitizers [vagrant@arch build]$ /bin/time -v build-gcc-9.1.0-sanitizers/test-conf-parser >/dev/null <...snip...> Command being timed: "build-gcc-9.1.0-sanitizers/test-conf-parser" User time (seconds): 30.03 System time (seconds): 0.33 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:30.50 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 348972 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 17 Minor (reclaiming a frame) page faults: 180473 Voluntary context switches: 31 Involuntary context switches: 160 Swaps: 0 File system inputs: 5200 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 [vagrant@arch build]$ cd build-gcc-9.1.0-sanitizers/ && /bin/time -v ../test/hwdb-test.sh >/dev/null Command being timed: "../test/hwdb-test.sh" User time (seconds): 129.53 System time (seconds): 32.94 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 2:43.29 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 805868 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 6 Minor (reclaiming a frame) page faults: 22858160 Voluntary context switches: 118 Involuntary context switches: 1136 Swaps: 0 File system inputs: 11640 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 ---- Notice the huge difference in user/wall time in the ASan+UBsan run, which is ~10 times slower with GCC 9.1.x as opposed to GCC 8.3.0. However, by switching the `detect_stack_use_after_return` option off, the performance issue is much less noticeable: ---- [vagrant@arch build]$ export ASAN_OPTIONS=strict_string_checks=1:check_initialization_order=1:strict_init_order=1:detect_stack_use_after_return=0 [vagrant@arch build]$ /bin/time -v build-gcc-9.1.0-sanitizers/test-conf-parser >/dev/null <...snip...> /tmp/test-conf-parser.Q8S7gi:1: Continuation line too long Command being timed: "build-gcc-9.1.0-sanitizers/test-conf-parser" User time (seconds): 2.61 System time (seconds): 0.23 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:02.87 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 347316 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 9 Minor (reclaiming a frame) page faults: 179814 Voluntary context switches: 22 Involuntary context switches: 108 Swaps: 0 File system inputs: 1160 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 [vagrant@arch build]$ cd build-gcc-9.1.0-sanitizers/ && /bin/time -v ../test/hwdb-test.sh >/dev/null Command being timed: "../test/hwdb-test.sh" User time (seconds): 22.71 System time (seconds): 32.06 Percent of CPU this job got: 99% Elapsed (wall clock) time (h:mm:ss or m:ss): 0:55.11 Average shared text size (kbytes): 0 Average unshared data size (kbytes): 0 Average stack size (kbytes): 0 Average total size (kbytes): 0 Maximum resident set size (kbytes): 802892 Average resident set size (kbytes): 0 Major (requiring I/O) page faults: 15 Minor (reclaiming a frame) page faults: 22856894 Voluntary context switches: 171 Involuntary context switches: 657 Swaps: 0 File system inputs: 25384 File system outputs: 0 Socket messages sent: 0 Socket messages received: 0 Signals delivered: 0 Page size (bytes): 4096 Exit status: 0 --- So far I've failed to convince meson/ninja to build systemd and leave the GCC's temporary files intact, so I'll provide them as soon as possible. Thank you. [0] https://github.com/systemd/systemd/pull/12856#issuecomment-504395847 [1] https://bugzilla.redhat.com/show_bug.cgi?id=1722949