Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Google Test framework #1126

Merged
merged 8 commits into from
Mar 13, 2022

Conversation

nmoinvaz
Copy link
Member

@nmoinvaz nmoinvaz commented Jan 21, 2022

  • CMake now uses Google Test instead of example.
  • Configure/nmake no longer test example, but just use simple minigzip tests. This is because fetching Google Test repository might add more complexity than it is worth.
  • This resolves adler32 unit test does not test all optimized functions #1017 by testing each Adler32 and Crc32 variant available on the host platform.

image

@nmoinvaz nmoinvaz added cleanup Improving maintainability or removing code. Continuous Integration enhancement labels Jan 21, 2022
@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from 3069af5 to e53d554 Compare January 21, 2022 00:17
@nmoinvaz
Copy link
Member Author

nmoinvaz commented Jan 21, 2022

@KungFuJesus with Google Test, when running in Debug mode, using MSVC I get those AVX512 Adler32 errors the CI has seen. Only happens in Debug mode, Release mode is ok.

image

image

@codecov
Copy link

codecov bot commented Jan 21, 2022

Codecov Report

Merging #1126 (3d420eb) into develop (2a19125) will increase coverage by 0.36%.
The diff coverage is 79.43%.

Impacted file tree graph

@@             Coverage Diff             @@
##           develop    #1126      +/-   ##
===========================================
+ Coverage    87.09%   87.45%   +0.36%     
===========================================
  Files           96      112      +16     
  Lines         9149     9608     +459     
  Branches      2258     2429     +171     
===========================================
+ Hits          7968     8403     +435     
+ Misses        1063      961     -102     
- Partials       118      244     +126     
Flag Coverage Δ
macos_clang 27.58% <27.58%> (∅)
macos_gcc 71.04% <77.15%> (+2.03%) ⬆️
ubuntu_clang 86.03% <ø> (+1.69%) ⬆️
ubuntu_clang_debug 85.21% <ø> (+0.96%) ⬆️
ubuntu_clang_inflate_allow_invalid_dist 85.89% <ø> (+1.68%) ⬆️
ubuntu_clang_inflate_strict 85.97% <ø> (+1.68%) ⬆️
ubuntu_clang_mmap 85.44% <ø> (+1.03%) ⬆️
ubuntu_clang_pigz 39.71% <ø> (ø)
ubuntu_clang_pigz_no_optim 39.97% <ø> (ø)
ubuntu_clang_pigz_no_threads 39.29% <ø> (ø)
ubuntu_clang_reduced_mem 86.22% <ø> (+1.69%) ⬆️
ubuntu_gcc 73.05% <63.49%> (+0.82%) ⬆️
ubuntu_gcc_aarch64 72.70% <63.93%> (+0.39%) ⬆️
ubuntu_gcc_aarch64_compat_no_opt 70.10% <75.72%> (+1.30%) ⬆️
ubuntu_gcc_aarch64_no_acle 70.98% <76.72%> (+1.68%) ⬆️
ubuntu_gcc_aarch64_no_neon 70.94% <76.72%> (+1.47%) ⬆️
ubuntu_gcc_armhf 72.69% <63.93%> (+0.40%) ⬆️
ubuntu_gcc_armhf_compat_no_opt 70.01% <75.72%> (+1.31%) ⬆️
ubuntu_gcc_armhf_no_acle 72.71% <64.04%> (+0.23%) ⬆️
ubuntu_gcc_armhf_no_neon 72.65% <64.04%> (-0.01%) ⬇️
ubuntu_gcc_armsf 72.69% <63.93%> (+0.40%) ⬆️
ubuntu_gcc_armsf_compat_no_opt 70.01% <75.72%> (+1.31%) ⬆️
ubuntu_gcc_benchmark 74.57% <75.88%> (+1.13%) ⬆️
ubuntu_gcc_compat_no_opt 71.98% <62.65%> (-0.23%) ⬇️
ubuntu_gcc_compat_sprefix 73.97% <74.71%> (+1.89%) ⬆️
ubuntu_gcc_mingw_i686 0.00% <0.00%> (ø)
ubuntu_gcc_mingw_x86_64 0.00% <0.00%> (ø)
ubuntu_gcc_no_avx2 71.78% <76.15%> (+2.05%) ⬆️
ubuntu_gcc_no_ctz 73.91% <76.73%> (+1.11%) ⬆️
ubuntu_gcc_no_ctzll 73.67% <76.73%> (+1.12%) ⬆️
ubuntu_gcc_no_pclmulqdq 70.69% <76.15%> (+2.28%) ⬆️
ubuntu_gcc_no_sse2 71.56% <76.01%> (+2.14%) ⬆️
ubuntu_gcc_no_sse4 71.50% <76.01%> (+2.12%) ⬆️
ubuntu_gcc_o3 74.00% <75.88%> (+2.91%) ⬆️
ubuntu_gcc_osb ∅ <ø> (∅)
ubuntu_gcc_pigz 37.80% <ø> (ø)
ubuntu_gcc_pigz_aarch64 38.27% <ø> (ø)
ubuntu_gcc_ppc 73.39% <76.59%> (+1.53%) ⬆️
ubuntu_gcc_ppc64 74.15% <76.44%> (+1.47%) ⬆️
ubuntu_gcc_ppc64le 73.34% <76.44%> (+1.50%) ⬆️
ubuntu_gcc_ppc_no_power8 74.39% <76.59%> (+1.48%) ⬆️
ubuntu_gcc_s390x 74.40% <76.59%> (+1.05%) ⬆️
ubuntu_gcc_s390x_dfltcc 73.10% <76.87%> (+0.66%) ⬆️
ubuntu_gcc_s390x_dfltcc_compat 70.78% <75.86%> (+1.17%) ⬆️
ubuntu_gcc_s390x_no_crc32 74.16% <76.73%> (+1.09%) ⬆️
ubuntu_gcc_sparc64 74.29% <76.73%> (+1.08%) ⬆️
ubuntu_gcc_sprefix 73.78% <75.88%> (+1.96%) ⬆️
win64_gcc 73.00% <77.30%> (+2.65%) ⬆️
win64_gcc_compat_no_opt 72.73% <77.03%> (+1.21%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
test/test_cve-2003-0107.cc 71.42% <33.33%> (ø)
test/test_inflate_adler32.cc 68.75% <37.50%> (ø)
test/test_version.cc 40.00% <40.00%> (ø)
test/test_deflate_quick_bi_valid.cc 76.19% <50.00%> (ø)
test/test_deflate_quick_block_open.cc 74.28% <52.94%> (ø)
test/test_compress.cc 63.63% <63.63%> (ø)
test/test_deflate_prime.cc 65.30% <65.30%> (ø)
test/test_adler32.cc 66.66% <66.66%> (ø)
test/test_crc32.cc 66.66% <66.66%> (ø)
test/test_deflate_copy.cc 66.66% <66.66%> (ø)
... and 28 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2a19125...3d420eb. Read the comment docs.

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from e0d904e to c64fc2c Compare January 21, 2022 03:16
@KungFuJesus
Copy link
Contributor

KungFuJesus commented Jan 21, 2022

@KungFuJesus with Google Test, when running in Debug mode, using MSVC I get those AVX512 Adler32 errors the CI has seen. Only happens in Debug mode, Release mode is ok.

So I fixed an issue that can happen due to not properly zero extending the 128 bit registers to 512 bit. Are you on the latest version of this PR? The zextsi128 stuff should prevent that from happening.

Ohh, it just occurred me you probably are implementing this on top of develop. This will go away once that PR goes through. What's happening is the _mm512_castsi128_si512 allows the top half the register to be undefined unless you do an explicit 128 bit move first.

For the benefit of tracking, this is the PR: #1121.

@nmoinvaz nmoinvaz marked this pull request as draft January 21, 2022 17:47
@nmoinvaz
Copy link
Member Author

@KungFuJesus I am also now seeing the problem in AVX2 on CI. Before it was only AVX2-VNNI. Hopefully your PR fixes both. I could cherry-pick your PR into my branch to see if it helps.

@KungFuJesus
Copy link
Contributor

KungFuJesus commented Jan 21, 2022

Hopefully your PR fixes both

It definitely should, the proper zero extension is being done in both. It was just an unfortunate circumstance of it working enough that the undefined nature wasn't caught.

All part of my favorite t-shirt: https://my-store-be64e.creator-spring.com/listing/undefined-behavior-shirt?

@nmoinvaz
Copy link
Member Author

nmoinvaz commented Jan 22, 2022

@Dead2:

  • I recommend we remove from configure and nmake all the tests except for a simple minigzip test.
    • If that is not acceptable, we can have example binary co-exist with google tests but this is a lot of duplicate code.
  • Like @mtl1979 mentioned before we might find some old compiler that doesn't support C++ standard that Google Test uses. What do we want to do in this instance? Skip Google Test? For CMake, we would still run all our other minigzip tests..

@mtl1979
Copy link
Collaborator

mtl1979 commented Jan 22, 2022

It's not just about possibility of encountering too old C++ compiler, but also the C++ compiler is kind of optional separate package on a lot of distributions and as the core code doesn't need it, it should not be changed as mandatory build dependency.

@nmoinvaz
Copy link
Member Author

Windows doesn't even come with C compiler

@mtl1979
Copy link
Collaborator

mtl1979 commented Jan 22, 2022

Windows doesn't even come with C compiler

It doesn't come with C++ compiler either... Technically the API is plain C, but the compiler is C#, but it can also compile hybrid C++/C# code. Since .NET Framework was changed as mandatory build requirement for Windows, the Visual Studio compiler has been C#. Some people say CL is short for Common Language.

@KungFuJesus
Copy link
Contributor

Windows doesn't even come with C compiler

It doesn't come with C++ compiler either... Technically the API is plain C, but the compiler is C#, but it can also compile hybrid C++/C# code. Since .NET Framework was changed as mandatory build requirement for Windows, the Visual Studio compiler has been C#. Some people say CL is short for Common Language.

I'm pretty sure that microsoft has a plain jane C++/C compiler that is separate from the rest of the .NET VM. What microsoft refers to as "unmanaged code" is the vanilla C++ compiler. Managed code compiles to IL and then turns into .NET bytecode via some common language runtime. Native, or unmanaged code I think interacts with the .NET VM through cdecl calling convention with standard foreign function interfaces. At least that's what I can recall when dealing with it from C# on Linux.

Native code very much still exists, I definitely wouldn't want to write a driver that depended on the .NET VM.

@mtl1979
Copy link
Collaborator

mtl1979 commented Jan 22, 2022

I'm pretty sure that microsoft has a plain jane C++/C compiler that is separate from the rest of the .NET VM. What microsoft refers to as "unmanaged code" is the vanilla C++ compiler. Managed code compiles to IL and then turns into .NET bytecode via some common language runtime. Native, or unmanaged code I think interacts with the .NET VM through cdecl calling convention with standard foreign function interfaces. At least that's what I can recall when dealing with it from C# on Linux.

Native code very much still exists, I definitely wouldn't want to write a driver that depended on the .NET VM.

I've compiled enough C++ applications under Windows at work that I know all except very simple Hello World type applications need CL runtime to even execute correctly. You get cryptic error code if the run-time is missing or incompatible version. Because the run-time is delay-loaded, it doesn't show up as dependency using normal dependency walker unless it allows attaching debug hooks.

@KungFuJesus
Copy link
Contributor

I'm guessing/hoping that this fixes the "code coverage" in a way that tells us reliably that we're checking everything, at least on nodes that can execute it. Though, the runtime determined support checks may trigger codecov to say "hey, there's a good chance we won't execute this all the time".

It'd be useful from the standpoint of, "will this get tested by the unit tests, and if not, we should write a new test" sort of deal.

@nmoinvaz
Copy link
Member Author

I've been continuing work on a different branch on my repo so I don't spam zlib-ng CI pipeline or this PR. There are some other changes that I need to get in first that I will make a PR for.

@Dead2
Copy link
Member

Dead2 commented Jan 25, 2022

Configure running less stringent tests than CMake is OK I think, but it would be nice with a documented way to get Google Test running manually without CMake though, if possible. If the user has to download things themselves etc, then that is fine.

One possible issue I see with this is it requires CMake 3.12, and anything older than that will not be running the tests.

IDK, the above is not optimal, but is it acceptable?
Using Google Test looks great though, assuming test coverage gets back up from 54% of course.

@mtl1979
Copy link
Collaborator

mtl1979 commented Jan 25, 2022

For pkgcheck test to pass, it must skip all the files and directories installed by Google Test.

@phprus
Copy link
Contributor

phprus commented Jan 25, 2022

Can you tell please why did you choose Google Test framework?

Google Test is quite difficult to integrate in the project.
Compiling zlib-ng tests now requires internet access to download GTest sources.

Maybe use the frameworks:

  1. https://github.com/doctest/doctest (used in https://github.com/oneapi-src/oneTBB )
  2. https://github.com/catchorg/Catch2 (usage example: https://github.com/gulrak/filesystem/tree/master/test )
    ?

Catch 2 and doctest require adding a single header file to the project.

@nmoinvaz
Copy link
Member Author

It is the one I was most familiar with and since I also added Google Benchmark it was an easy extension of that to use Google Test. Anything that is C++ is going to make integration difficult because we haven't really had to deal with CXX compiler until now. It is possible to use locally downloaded sources, however one thing about keeping the sources separate is there are no licensing issues as we try to keep only zlib licensed code in the repository. I'm not interesting in reworking everything I've done to use another test framework.

@nmoinvaz
Copy link
Member Author

nmoinvaz commented Jan 26, 2022

Currently waiting on #1139 and #1136 and #1132.

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from 9d024ab to ed185a8 Compare January 27, 2022 20:57
@nmoinvaz
Copy link
Member Author

nmoinvaz commented Jan 27, 2022

The remaining CI failures are:

  • mwing is having problems with compiler with *-posix extension and some threading warnings.
  • msan is having issues with libc++ not being built by msan
  • ppc is segfaulting i'm not sure why.

Not sure how easily these can be overcome.

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from e51e7bd to 427d745 Compare February 25, 2022 01:29
@nmoinvaz
Copy link
Member Author

Rebased.

@Dead2
Copy link
Member

Dead2 commented Feb 25, 2022

I was thinking keep test_*, but remove cve and fuzzer targets.

test_ targets mainly do functional testing that tells a user that it is working correctly/compiled right etc. While the cve and fuzzer targets test things that are more useful for us as maintainers, regression tests etc, and should not crop up on a users compile without us already knowing about it.

@Dead2
Copy link
Member

Dead2 commented Feb 25, 2022

Oh, and keep example too ofc, since it is the basic functionality testing.

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from d45d7d9 to 8d8b761 Compare February 25, 2022 15:22
@nmoinvaz
Copy link
Member Author

nmoinvaz commented Feb 25, 2022

The test_crc32 and test_adler32 code has been transformed to use Google Test and test all variants of those functions available on the platform (should resolve #1017), that is why they are no longer in configure script.

I have removed the commit that removed example, so that should be back in there now.

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from 8d8b761 to 3d3060c Compare February 25, 2022 15:29
@nmoinvaz
Copy link
Member Author

nmoinvaz commented Feb 25, 2022

We can't remove fuzzers right now, because oss-fuzz uses configure script. However, if we change oss-fuzz to use cmake then we can remove them. That could potentially go in a separate PR.

@Dead2
Copy link
Member

Dead2 commented Mar 7, 2022

This fails to compile on EL7

/usr/bin/cc -DHAVE_BUILTIN_CTZ -DHAVE_BUILTIN_CTZLL -DHAVE_POSIX_MEMALIGN -DHAVE_SYS_SDT_H -DHAVE_VISIBILITY_HIDDEN -DHAVE_VISIBILITY_INTERNAL -DUNALIGNED64_OK -DUNALIGNED_OK -DWITH_GZFILEOP -DX86_AVX2 -DX86_AVX2_ADLER32 -DX86_AVX_CHUNKSET -DX86_FEATURES -DX86_PCLMULQDQ_CRC -DX86_SSE2 -DX86_SSE2_CHUNKSET -DX86_SSE2_SLIDEHASH -DX86_SSE41 -DX86_SSE41_ADLER32 -DX86_SSE42_CRC_HASH -DX86_SSE42_CRC_INTRIN -DX86_SSSE3 -DX86_SSSE3_ADLER32 -DZLIB_DLL -D_LARGEFILE64_SOURCE=1 -D__USE_LARGEFILE64 -I/usr/src/github/zlib-ng  -Wall -Wpedantic -falign-functions=64 -O2 -DNDEBUG -fPIC   -Wall -Wextra -Wpedantic -Wno-implicit-fallthrough -std=c11 -o CMakeFiles/zlib.dir/crc32_comb.c.o   -c /usr/src/github/zlib-ng/crc32_comb.c
In file included from /usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/internal/gtest-death-test-internal.h:42:0,
                 from /usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/gtest-death-test.h:43,
                 from /usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/gtest.h:60,
                 from /usr/src/github/zlib-ng/_deps/googletest-src/googletest/src/gtest-all.cc:38:
/usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/gtest-matchers.h: In static member function ‘static constexpr bool testing::internal::MatcherBase<T>::IsInlined()’:
/usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/gtest-matchers.h:418:12: error: ‘is_trivially_copy_constructible’ is not a member of ‘std’
            std::is_trivially_copy_constructible<M>::value &&
            ^
/usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/gtest-matchers.h:418:50: error: expected primary-expression before ‘>’ token
            std::is_trivially_copy_constructible<M>::value &&
                                                  ^
/usr/src/github/zlib-ng/_deps/googletest-src/googletest/include/gtest/gtest-matchers.h:418:51: error: ‘::value’ has not been declared
            std::is_trivially_copy_constructible<M>::value &&
                                                   ^

I think we would need to incorporate the patch mentioned earlier:
fmtlib/fmt@fd43e4d
It does not apply cleanly, but applied to _deps/googletest-src/googletest/include/gtest/gtest-matchers.h, it compiles and gtest runs successfully (And wow it is fast).

--- _deps/googletest-src/googletest/include/gtest/gtest-matchers.h.old  2022-03-07 14:27:56.484777293 +0100
+++ _deps/googletest-src/googletest/include/gtest/gtest-matchers.h      2022-03-07 14:23:27.514498802 +0100
@@ -242,6 +242,14 @@
   T value;
 };

+template <typename T>
+using is_trivially_copy_constructible =
+#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
+    std::has_trivial_copy_constructor<T>;
+#else
+    std::is_trivially_copy_constructible<T>;
+#endif
+
 // An internal class for implementing Matcher<T>, which will derive
 // from it.  We put functionalities common to all Matcher<T>
 // specializations here to avoid code duplication.
@@ -415,7 +423,7 @@
   template <typename M>
   static constexpr bool IsInlined() {
     return sizeof(M) <= sizeof(Buffer) && alignof(M) <= alignof(Buffer) &&
-           std::is_trivially_copy_constructible<M>::value &&
+           is_trivially_copy_constructible<M>::value &&
            std::is_trivially_destructible<M>::value;
   }

So, should we patch that file locally? Perhaps just run sed to replace the function name if GCC is 4.x?

It is unfortunate that gtest (and other google projects) are not really made for use outside of Google, and as such they don't consider portability and backwards compatibility to be as important (for example Snappy is rejecting patches that fix compilation on other platforms). Gtest does not support GCC older than 5.3, ref google/googletest#3444 and google/googletest#3387
Does anyone maintain a portability-focused fork of gtest?
Or perhaps we could point to an older version of gtest? Version 1.8.1 looks like it might be the last supported version.

@nmoinvaz
Copy link
Member Author

nmoinvaz commented Mar 7, 2022

I have pushed a commit that will use older version of Google test when GCC <= 5.3. @Dead2 can you give that a try?

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from 45e842a to daba3f9 Compare March 8, 2022 15:56
@nmoinvaz
Copy link
Member Author

nmoinvaz commented Mar 8, 2022

Rebased after #1161. Fixed crc32 pclmulqdq tests and fixed cpu check features not being called.

@Dead2
Copy link
Member

Dead2 commented Mar 10, 2022

Unfortunately this now fails with the following error. I assume it is a missing new feature in the older gtest..

/usr/src/github/zlib-ng/test/test_adler32.cc:354:25: error: expected constructor, destructor, or type conversion before ‘(’ token
 INSTANTIATE_TEST_SUITE_P(adler32, adler32_variant, testing::ValuesIn(tests));
                         ^
/usr/src/github/zlib-ng/test/test_adler32.cc: In member function ‘virtual void adler32_variant_c_Test::TestBody()’:
/usr/src/github/zlib-ng/test/test_adler32.cc:359:24: error: ‘GTEST_SKIP’ was not declared in this scope
             GTEST_SKIP(); \
                        ^
/usr/src/github/zlib-ng/test/test_adler32.cc:365:1: note: in expansion of macro ‘TEST_ADLER32’
 TEST_ADLER32(c, adler32_c, 1)
 ^

@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from daba3f9 to a4281c4 Compare March 10, 2022 16:32
@nmoinvaz
Copy link
Member Author

@Dead2 I tried to use a commit that contains the GTEST_SKIP in FetchContent but there is a bug in CMake that causes it not to work.

I have forked googletest into zlib-ng and pointed this PR to that.

Allow specifying alternative Google test repository and tag.
@nmoinvaz nmoinvaz force-pushed the improvements/google-test branch from a4281c4 to 3d420eb Compare March 10, 2022 16:36
@nmoinvaz
Copy link
Member Author

Actually, I think the only other release-1.10.0 might work. It doesn't look like it has that offending code and it does have GTEST_SKIP. So if it works then we don't need the forked googletest.

@Dead2
Copy link
Member

Dead2 commented Mar 11, 2022

@nmoinvaz Confirmed, 1.10.0 works just fine. Good find 👍

@nmoinvaz
Copy link
Member Author

That's great news. I have removed the googletest fork.

Copy link
Member

@Dead2 Dead2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@Dead2 Dead2 merged commit a5a9844 into zlib-ng:develop Mar 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cleanup Improving maintainability or removing code. Continuous Integration enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

adler32 unit test does not test all optimized functions
6 participants