From: Joel Rosdahl Date: Wed, 15 Jul 2026 14:39:42 +0000 (+0200) Subject: test: Test both scalar and AVX2 source code scanning implementations X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fb572380b4ced443759be0979df8d7ec27903d03;p=thirdparty%2Fccache.git test: Test both scalar and AVX2 source code scanning implementations --- diff --git a/src/ccache/hashutil.cpp b/src/ccache/hashutil.cpp index ead716b2..16032944 100644 --- a/src/ccache/hashutil.cpp +++ b/src/ccache/hashutil.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2025 Joel Rosdahl and other contributors +// Copyright (C) 2009-2026 Joel Rosdahl and other contributors // // See doc/authors.adoc for a complete list of contributors. // @@ -167,6 +167,17 @@ check_for_temporal_macros_avx2(std::string_view str) } #endif +HashSourceCodeResult +check_for_source_code_patterns(std::string_view str) +{ +#ifdef HAVE_AVX2 + if (util::cpu_supports_avx2()) { + return check_for_temporal_macros_avx2(str); + } +#endif + return check_for_temporal_macros_bmh(str); +} + HashSourceCodeResult do_hash_file(const Context& ctx, Hash::Digest& digest, @@ -197,7 +208,7 @@ do_hash_file(const Context& ctx, HashSourceCodeResult result; if (check_temporal_macros) { - result.insert(check_for_temporal_macros(util::to_string_view(*data))); + result.insert(check_for_source_code_patterns(util::to_string_view(*data))); } Hash hash; @@ -213,14 +224,17 @@ do_hash_file(const Context& ctx, } // namespace +#ifdef HAVE_AVX2 HashSourceCodeResult -check_for_temporal_macros(std::string_view str) +check_for_source_code_patterns_avx2(std::string_view str) { -#ifdef HAVE_AVX2 - if (util::cpu_supports_avx2()) { - return check_for_temporal_macros_avx2(str); - } + return check_for_temporal_macros_avx2(str); +} #endif + +HashSourceCodeResult +check_for_source_code_patterns_scalar(std::string_view str) +{ return check_for_temporal_macros_bmh(str); } diff --git a/src/ccache/hashutil.hpp b/src/ccache/hashutil.hpp index 5f94d8b6..a1030205 100644 --- a/src/ccache/hashutil.hpp +++ b/src/ccache/hashutil.hpp @@ -1,4 +1,4 @@ -// Copyright (C) 2009-2024 Joel Rosdahl and other contributors +// Copyright (C) 2009-2026 Joel Rosdahl and other contributors // // See doc/authors.adoc for a complete list of contributors. // @@ -39,8 +39,14 @@ enum class HashSourceCode { using HashSourceCodeResult = util::BitSet; -// Search for tokens (described in HashSourceCode) in `str`. -HashSourceCodeResult check_for_temporal_macros(std::string_view str); +#ifdef HAVE_AVX2 +// Search for source code patterns in `str`, AVX2 version. +HashSourceCodeResult check_for_source_code_patterns_avx2(std::string_view str); +#endif + +// Search for source code patterns in `str`, non-SIMD version. +HashSourceCodeResult +check_for_source_code_patterns_scalar(std::string_view str); // Hash a source code file using the inode cache if enabled. HashSourceCodeResult hash_source_code_file(const Context& ctx, diff --git a/unittest/test_hashutil.cpp b/unittest/test_hashutil.cpp index 4dc945ed..32f28947 100644 --- a/unittest/test_hashutil.cpp +++ b/unittest/test_hashutil.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2010-2025 Joel Rosdahl and other contributors +// Copyright (C) 2010-2026 Joel Rosdahl and other contributors // // See doc/authors.adoc for a complete list of contributors. // @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -42,112 +43,11 @@ hco(Hash& hash, const std::string& command, const std::string& compiler) #endif } -TEST_SUITE_BEGIN("hashutil"); - -TEST_CASE("hash_command_output_simple") -{ - TestContext test_context; - - Hash h1; - Hash h2; - - CHECK(hco(h1, "echo", "not used")); - CHECK(hco(h2, "echo", "not used")); - CHECK(h1.digest() == h2.digest()); -} - -TEST_CASE("hash_command_output_space_removal") -{ - TestContext test_context; - - Hash h1; - Hash h2; - - CHECK(hco(h1, "echo", "not used")); - CHECK(hco(h2, " echo ", "not used")); - CHECK(h1.digest() == h2.digest()); -} +using SourceCodePatternChecker = HashSourceCodeResult (*)(std::string_view); -TEST_CASE("hash_command_output_hash_inequality") -{ - TestContext test_context; - - Hash h1; - Hash h2; - - CHECK(hco(h1, "echo foo", "not used")); - CHECK(hco(h2, "echo bar", "not used")); - CHECK(h1.digest() != h2.digest()); -} - -TEST_CASE("hash_command_output_compiler_substitution") -{ - TestContext test_context; - - Hash h1; - Hash h2; - - CHECK(hco(h1, "echo foo", "not used")); -#ifdef _WIN32 - REQUIRE(util::write_file("command.bat", "@echo off\r\necho foo\r\n")); - CHECK(hash_command_output(h2, "%compiler%", "command.bat")); -#else - CHECK(hash_command_output(h2, "%compiler% foo", "echo")); -#endif - CHECK(h1.digest() == h2.digest()); -} - -TEST_CASE("hash_command_output_stdout_versus_stderr") +static void +check_temporal_macros(SourceCodePatternChecker check) { - TestContext test_context; - - Hash h1; - Hash h2; - -#ifdef _WIN32 - REQUIRE(util::write_file("stderr.bat", "@echo off\r\necho foo>&2\r\n")); - CHECK(hco(h1, "echo foo", "not used")); - CHECK(hco(h2, "stderr.bat", "not used")); -#else - CHECK(hco(h1, "echo foo", "not used")); - CHECK(hco(h2, "echo foo >&2", "not used")); -#endif - CHECK(h1.digest() == h2.digest()); -} - -TEST_CASE("hash_multicommand_output") -{ - TestContext test_context; - - Hash h1; - Hash h2; - -#ifdef _WIN32 - h2.hash("foo\r\nbar\r\n"); - REQUIRE(util::write_file("foo.bat", "@echo off\r\necho foo\r\n")); - REQUIRE(util::write_file("bar.bat", "@echo off\r\necho bar\r\n")); - CHECK(hash_multicommand_output(h1, "foo.bat; bar.bat", "not used")); -#else - h2.hash("foo\nbar\n"); - CHECK(hash_multicommand_output(h1, "echo foo; echo bar", "not used")); - CHECK(h1.digest() == h2.digest()); -#endif -} - -TEST_CASE("hash_multicommand_output_error_handling") -{ - TestContext test_context; - - Hash h1; - Hash h2; - - CHECK(!hash_multicommand_output(h2, "false; true", "not used")); -} - -TEST_CASE("check_for_temporal_macros") -{ - TestContext test_context; - const std::string_view time_start = "__TIME__\n" "int a;\n"; @@ -203,8 +103,6 @@ TEST_CASE("check_for_temporal_macros") "#define alphabet abcdefghijklmnopqrstuvwxyz\n" "a__DATE__"; - auto check = check_for_temporal_macros; - CHECK(check(time_start).contains(HashSourceCode::found_time)); CHECK(check(time_start.substr(1)).empty()); @@ -280,4 +178,125 @@ TEST_CASE("check_for_temporal_macros") } } +TEST_SUITE_BEGIN("hashutil"); + +TEST_CASE("hash_command_output_simple") +{ + TestContext test_context; + + Hash h1; + Hash h2; + + CHECK(hco(h1, "echo", "not used")); + CHECK(hco(h2, "echo", "not used")); + CHECK(h1.digest() == h2.digest()); +} + +TEST_CASE("hash_command_output_space_removal") +{ + TestContext test_context; + + Hash h1; + Hash h2; + + CHECK(hco(h1, "echo", "not used")); + CHECK(hco(h2, " echo ", "not used")); + CHECK(h1.digest() == h2.digest()); +} + +TEST_CASE("hash_command_output_hash_inequality") +{ + TestContext test_context; + + Hash h1; + Hash h2; + + CHECK(hco(h1, "echo foo", "not used")); + CHECK(hco(h2, "echo bar", "not used")); + CHECK(h1.digest() != h2.digest()); +} + +TEST_CASE("hash_command_output_compiler_substitution") +{ + TestContext test_context; + + Hash h1; + Hash h2; + + CHECK(hco(h1, "echo foo", "not used")); +#ifdef _WIN32 + REQUIRE(util::write_file("command.bat", "@echo off\r\necho foo\r\n")); + CHECK(hash_command_output(h2, "%compiler%", "command.bat")); +#else + CHECK(hash_command_output(h2, "%compiler% foo", "echo")); +#endif + CHECK(h1.digest() == h2.digest()); +} + +TEST_CASE("hash_command_output_stdout_versus_stderr") +{ + TestContext test_context; + + Hash h1; + Hash h2; + +#ifdef _WIN32 + REQUIRE(util::write_file("stderr.bat", "@echo off\r\necho foo>&2\r\n")); + CHECK(hco(h1, "echo foo", "not used")); + CHECK(hco(h2, "stderr.bat", "not used")); +#else + CHECK(hco(h1, "echo foo", "not used")); + CHECK(hco(h2, "echo foo >&2", "not used")); +#endif + CHECK(h1.digest() == h2.digest()); +} + +TEST_CASE("hash_multicommand_output") +{ + TestContext test_context; + + Hash h1; + Hash h2; + +#ifdef _WIN32 + h2.hash("foo\r\nbar\r\n"); + REQUIRE(util::write_file("foo.bat", "@echo off\r\necho foo\r\n")); + REQUIRE(util::write_file("bar.bat", "@echo off\r\necho bar\r\n")); + CHECK(hash_multicommand_output(h1, "foo.bat; bar.bat", "not used")); +#else + h2.hash("foo\nbar\n"); + CHECK(hash_multicommand_output(h1, "echo foo; echo bar", "not used")); + CHECK(h1.digest() == h2.digest()); +#endif +} + +TEST_CASE("hash_multicommand_output_error_handling") +{ + TestContext test_context; + + Hash h1; + Hash h2; + + CHECK(!hash_multicommand_output(h2, "false; true", "not used")); +} + +TEST_CASE("check_for_temporal_macros") +{ + TestContext test_context; + + SUBCASE("scalar") + { + check_temporal_macros(check_for_source_code_patterns_scalar); + } + +#ifdef HAVE_AVX2 + if (util::cpu_supports_avx2()) { + SUBCASE("avx2") + { + check_temporal_macros(check_for_source_code_patterns_avx2); + } + } +#endif +} + TEST_SUITE_END();