Commit cef6425bcac678157f58e9eafabb7e63c5831d18

Authored by Jay Berkenbilt
1 parent da71dc6f

Disable QTC inside the library by default (fixes #714)

This results in measurable performance improvements to packaged binary
libqpdf distributions. QTC remains available for library users and is
still selectively enabled in CI.
CMakeLists.txt
@@ -43,6 +43,9 @@ CMAKE_DEPENDENT_OPTION( @@ -43,6 +43,9 @@ CMAKE_DEPENDENT_OPTION(
43 GENERATE_AUTO_JOB "Automatically regenerate job files" OFF 43 GENERATE_AUTO_JOB "Automatically regenerate job files" OFF
44 "NOT MAINTAINER_MODE" ON) 44 "NOT MAINTAINER_MODE" ON)
45 CMAKE_DEPENDENT_OPTION( 45 CMAKE_DEPENDENT_OPTION(
  46 + ENABLE_QTC "Enable QTC test coverage" OFF
  47 + "NOT MAINTAINER_MODE" ON)
  48 +CMAKE_DEPENDENT_OPTION(
46 SHOW_FAILED_TEST_OUTPUT "Show qtest output on failure" OFF 49 SHOW_FAILED_TEST_OUTPUT "Show qtest output on failure" OFF
47 "NOT CI_MODE" ON) 50 "NOT CI_MODE" ON)
48 51
@@ -110,8 +113,15 @@ endif() @@ -110,8 +113,15 @@ endif()
110 113
111 add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:POINTERHOLDER_TRANSITION=4>) 114 add_compile_definitions($<$<COMPILE_LANGUAGE:CXX>:POINTERHOLDER_TRANSITION=4>)
112 115
  116 +if(ENABLE_QTC)
  117 + set(ENABLE_QTC_ARG)
  118 +else()
  119 + add_compile_definitions(QPDF_DISABLE_QTC=1)
  120 + set(ENABLE_QTC_ARG --disable-tc)
  121 +endif()
  122 +
113 enable_testing() 123 enable_testing()
114 -set(RUN_QTEST perl ${qpdf_SOURCE_DIR}/run-qtest) 124 +set(RUN_QTEST perl ${qpdf_SOURCE_DIR}/run-qtest ${ENABLE_QTC_ARG})
115 125
116 if(WIN32) 126 if(WIN32)
117 find_program(COPY_COMMAND NAMES cp copy) 127 find_program(COPY_COMMAND NAMES cp copy)
@@ -335,6 +345,7 @@ message(STATUS &quot; build shared libraries: ${BUILD_SHARED_LIBS}&quot;) @@ -335,6 +345,7 @@ message(STATUS &quot; build shared libraries: ${BUILD_SHARED_LIBS}&quot;)
335 message(STATUS " build static libraries: ${BUILD_STATIC_LIBS}") 345 message(STATUS " build static libraries: ${BUILD_STATIC_LIBS}")
336 message(STATUS " build manual: ${BUILD_DOC}") 346 message(STATUS " build manual: ${BUILD_DOC}")
337 message(STATUS " compiler warnings are errors: ${WERROR}") 347 message(STATUS " compiler warnings are errors: ${WERROR}")
  348 +message(STATUS " QTC test coverage: ${ENABLE_QTC}")
338 message(STATUS " system: ${CPACK_SYSTEM_NAME}") 349 message(STATUS " system: ${CPACK_SYSTEM_NAME}")
339 message(STATUS "") 350 message(STATUS "")
340 message(STATUS "*** Options Summary ***") 351 message(STATUS "*** Options Summary ***")
ChangeLog
  1 +2022-08-07 Jay Berkenbilt <ejb@ql.org>
  2 +
  3 + * Add new build configuration option ENABLE_QTC, which is off by
  4 + default when not running in MAINTAINER_MODE. When this is off,
  5 + QTC coverage calls sprinkled throughout the qpdf source code are
  6 + compiled out for increased performance. See "Build Options" in the
  7 + manual for a discussion. Fixes #714.
  8 +
1 2022-08-06 Jay Berkenbilt <ejb@ql.org> 9 2022-08-06 Jay Berkenbilt <ejb@ql.org>
2 10
3 * Added by m-holger: QPDF::getObject() method as a simpler form of 11 * Added by m-holger: QPDF::getObject() method as a simpler form of
@@ -4,14 +4,9 @@ Next @@ -4,14 +4,9 @@ Next
4 4
5 Before Release: 5 Before Release:
6 6
7 -* Improve performance around QTC  
8 - * Make it possible to compile it out and deal with it in the tests  
9 - * Make sure at least some CI test is run with coverage enabled  
10 - * Cache environment variables  
11 - * Remove coverage cases for things that are heavily exercised or are  
12 - in critical paths  
13 * Make ./performance_check usable by other people by having published 7 * Make ./performance_check usable by other people by having published
14 files to use for testing. 8 files to use for testing.
  9 + * https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf
15 * Evaluate issues tagged with `next` 10 * Evaluate issues tagged with `next`
16 * Stay on top of https://github.com/pikepdf/pikepdf/pull/315 11 * Stay on top of https://github.com/pikepdf/pikepdf/pull/315
17 12
build-scripts/test-sanitizers
@@ -10,7 +10,8 @@ env CFLAGS=&quot;-fsanitize=address -fsanitize=undefined&quot; \ @@ -10,7 +10,8 @@ env CFLAGS=&quot;-fsanitize=address -fsanitize=undefined&quot; \
10 CC=clang CXX=clang++ \ 10 CC=clang CXX=clang++ \
11 cmake -S . -B build \ 11 cmake -S . -B build \
12 -DCI_MODE=1 -DBUILD_SHARED_LIBS=0 -DCMAKE_BUILD_TYPE=Debug \ 12 -DCI_MODE=1 -DBUILD_SHARED_LIBS=0 -DCMAKE_BUILD_TYPE=Debug \
13 - -DREQUIRE_CRYPTO_OPENSSL=1 -DREQUIRE_CRYPTO_GNUTLS=1 13 + -DREQUIRE_CRYPTO_OPENSSL=1 -DREQUIRE_CRYPTO_GNUTLS=1 \
  14 + -DENABLE_QTC=1
14 cmake --build build -j$(nproc) -- -k 15 cmake --build build -j$(nproc) -- -k
15 cd build 16 cd build
16 # libtests automatically runs with all crypto providers. 17 # libtests automatically runs with all crypto providers.
include/qpdf/QTC.hh
@@ -24,10 +24,24 @@ @@ -24,10 +24,24 @@
24 24
25 #include <qpdf/DLL.h> 25 #include <qpdf/DLL.h>
26 26
  27 +// Defining QPDF_DISABLE_QTC will effectively compile out any QTC::TC
  28 +// calls in any code that includes this file, but QTC will still be
  29 +// built into the library. That way, it is possible to build and
  30 +// package qpdf with QPDF_DISABLE_QTC while still making QTC::TC
  31 +// available to end users.
  32 +
27 namespace QTC 33 namespace QTC
28 { 34 {
29 QPDF_DLL 35 QPDF_DLL
30 - void TC(char const* const scope, char const* const ccase, int n = 0); 36 + void TC_real(char const* const scope, char const* const ccase, int n = 0);
  37 +
  38 + inline void
  39 + TC(char const* const scope, char const* const ccase, int n = 0)
  40 + {
  41 +#ifndef QPDF_DISABLE_QTC
  42 + TC_real(scope, ccase, n);
  43 +#endif // QPDF_DISABLE_QTC
  44 + }
31 }; // namespace QTC 45 }; // namespace QTC
32 46
33 #endif // QTC_HH 47 #endif // QTC_HH
libqpdf/QTC.cc
@@ -13,7 +13,7 @@ tc_active(char const* const scope) @@ -13,7 +13,7 @@ tc_active(char const* const scope)
13 } 13 }
14 14
15 void 15 void
16 -QTC::TC(char const* const scope, char const* const ccase, int n) 16 +QTC::TC_real(char const* const scope, char const* const ccase, int n)
17 { 17 {
18 static std::map<std::string, bool> active; 18 static std::map<std::string, bool> active;
19 auto is_active = active.find(scope); 19 auto is_active = active.find(scope);
manual/installation.rst
@@ -257,6 +257,16 @@ CHECK_SIZES @@ -257,6 +257,16 @@ CHECK_SIZES
257 that ensures an exact match between classes in ``sizes.cc`` and 257 that ensures an exact match between classes in ``sizes.cc`` and
258 classes in the library's public API. This option requires Python 3. 258 classes in the library's public API. This option requires Python 3.
259 259
  260 +ENABLE_QTC
  261 + This is off by default, except in maintainer mode. When off,
  262 + ``QTC::TC`` calls are compiled out by having ``QTC::TC`` be an empty
  263 + inline function. The underlying ``QTC::TC`` remains in the library,
  264 + so it is possible to build and package the qpdf library with
  265 + ``ENABLE_QTC`` turned off while still allowing developer code to use
  266 + ``QTC::TC`` if desired. If you are modifying qpdf code, it's a good
  267 + idea to have this on for more robust automated testing. Otherwise,
  268 + there's no reason to have it on.
  269 +
260 GENERATE_AUTO_JOB 270 GENERATE_AUTO_JOB
261 Some qpdf source files are automatically generated from 271 Some qpdf source files are automatically generated from
262 :file:`job.yml` and the CLI documentation. If you are adding new 272 :file:`job.yml` and the CLI documentation. If you are adding new
@@ -297,6 +307,8 @@ MAINTAINER_MODE @@ -297,6 +307,8 @@ MAINTAINER_MODE
297 307
298 - ``CHECK_SIZES`` 308 - ``CHECK_SIZES``
299 309
  310 + - ``ENABLE_QTC``
  311 +
300 - ``GENERATE_AUTO_JOB`` 312 - ``GENERATE_AUTO_JOB``
301 313
302 - ``WERROR`` 314 - ``WERROR``
manual/release-notes.rst
@@ -7,6 +7,12 @@ For a detailed list of changes, please see the file @@ -7,6 +7,12 @@ For a detailed list of changes, please see the file
7 :file:`ChangeLog` in the source distribution. 7 :file:`ChangeLog` in the source distribution.
8 8
9 11.0.0 9 11.0.0
  10 + - Performance improvements
  11 +
  12 + - Many performance enhancements have been added. In developer
  13 + performance benchmarks, gains on the order of 20% have been
  14 + observed.
  15 +
10 - Replacement of ``PointerHolder`` with ``std::shared_ptr`` 16 - Replacement of ``PointerHolder`` with ``std::shared_ptr``
11 17
12 - The qpdf-specific ``PointerHolder`` smart pointer implementation 18 - The qpdf-specific ``PointerHolder`` smart pointer implementation
@@ -231,6 +237,14 @@ For a detailed list of changes, please see the file @@ -231,6 +237,14 @@ For a detailed list of changes, please see the file
231 - The qpdf source code is now formatted automatically with 237 - The qpdf source code is now formatted automatically with
232 ``clang-format``. See :ref:`code-formatting` for information. 238 ``clang-format``. See :ref:`code-formatting` for information.
233 239
  240 + - Test coverage with ``QTC`` is enabled during development but
  241 + compiled out of distributed qpdf binaries by default. This
  242 + results in a significant performance improvement, especially on
  243 + Windows. ``QTC::TC`` is still available in the library and is
  244 + still usable by end user code even though calls to it made
  245 + internally by the library are turned off. Internally, there is
  246 + some additional caching to reduce the overhead of repeatedly
  247 + reading environment variables at runtime.
234 248
235 10.6.3: March 8, 2022 249 10.6.3: March 8, 2022
236 - Announcement of upcoming change: 250 - Announcement of upcoming change:
run-qtest
@@ -13,6 +13,7 @@ my $code = undef; @@ -13,6 +13,7 @@ my $code = undef;
13 my @bin = (); 13 my @bin = ();
14 my $color = undef; 14 my $color = undef;
15 my $show_on_failure = 0; 15 my $show_on_failure = 0;
  16 +my $disable_tc = 0;
16 my @tc = (); 17 my @tc = ();
17 18
18 if ($^O =~ m/^MSWin32|msys$/) 19 if ($^O =~ m/^MSWin32|msys$/)
@@ -51,6 +52,10 @@ while (@ARGV) @@ -51,6 +52,10 @@ while (@ARGV)
51 usage() unless @ARGV; 52 usage() unless @ARGV;
52 $show_on_failure = cmake_bool(shift(@ARGV)); 53 $show_on_failure = cmake_bool(shift(@ARGV));
53 } 54 }
  55 + elsif ($arg eq '--disable-tc')
  56 + {
  57 + $disable_tc = 1;
  58 + }
54 elsif ($arg eq '--tc') 59 elsif ($arg eq '--tc')
55 { 60 {
56 usage() unless @ARGV; 61 usage() unless @ARGV;
@@ -94,7 +99,7 @@ push(@cmd, @@ -94,7 +99,7 @@ push(@cmd,
94 "-datadir", "$code/qtest", 99 "-datadir", "$code/qtest",
95 "-junit-suffix", basename($code)); 100 "-junit-suffix", basename($code));
96 101
97 -if (scalar(@tc)) 102 +if (scalar(@tc) && (! $disable_tc))
98 { 103 {
99 my @tc_srcs = map { 104 my @tc_srcs = map {
100 File::Spec->abs2rel(abs_path($_)) 105 File::Spec->abs2rel(abs_path($_))