/* Self tests for parallel_for_each Copyright (C) 2021-2025 Free Software Foundation, Inc. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "gdbsupport/selftest.h" #include "gdbsupport/parallel-for.h" #if CXX_STD_THREAD #include "gdbsupport/thread-pool.h" namespace selftests { namespace parallel_for { struct save_restore_n_threads { save_restore_n_threads () : n_threads (gdb::thread_pool::g_thread_pool->thread_count ()) { } ~save_restore_n_threads () { gdb::thread_pool::g_thread_pool->set_thread_count (n_threads); } int n_threads; }; using foreach_callback_t = gdb::function_view; using do_foreach_t = gdb::function_view; static void test_one (int n_threads, do_foreach_t do_foreach) { save_restore_n_threads saver; gdb::thread_pool::g_thread_pool->set_thread_count (n_threads); { constexpr int upper_bound = 1000; std::atomic counter (0); do_foreach (0, upper_bound, [&] (int start, int end) { counter += end - start; }); SELF_CHECK (counter == upper_bound); } { std::atomic counter (0); do_foreach (0, 0, [&] (int start, int end) { counter += end - start; }); SELF_CHECK (counter == 0); } { /* Check that if there are fewer tasks than threads, then we won't end up with a null result. */ std::vector> intresults; std::atomic any_empty_tasks (false); do_foreach (0, 1, [&] (int start, int end) { if (start == end) any_empty_tasks = true; return std::make_unique (end - start); }); SELF_CHECK (!any_empty_tasks); SELF_CHECK (std::all_of (intresults.begin (), intresults.end (), [] (const std::unique_ptr &entry) { return entry != nullptr; })); } } static void test_parallel_for_each () { const std::vector for_each_functions { [] (int start, int end, foreach_callback_t callback) { gdb::parallel_for_each<1> (start, end, callback); }, [] (int start, int end, foreach_callback_t callback) { gdb::sequential_for_each (start, end, callback);} }; for (int n_threads : { 0, 1, 3 }) for (const auto &for_each_function : for_each_functions) test_one (n_threads, for_each_function); } } /* namespace parallel_for */ } /* namespace selftests */ #endif /* CXX_STD_THREAD */ INIT_GDB_FILE (parallel_for_selftests) { #ifdef CXX_STD_THREAD selftests::register_test ("parallel_for", selftests::parallel_for::test_parallel_for_each); #endif /* CXX_STD_THREAD */ }