xref: /oneTBB/test/tbb/test_parallel_invoke.cpp (revision 7cee2251)
151c0b2f7Stbbdev /*
2*7cee2251SJhaShweta1     Copyright (c) 2020-2023 Intel Corporation
351c0b2f7Stbbdev 
451c0b2f7Stbbdev     Licensed under the Apache License, Version 2.0 (the "License");
551c0b2f7Stbbdev     you may not use this file except in compliance with the License.
651c0b2f7Stbbdev     You may obtain a copy of the License at
751c0b2f7Stbbdev 
851c0b2f7Stbbdev         http://www.apache.org/licenses/LICENSE-2.0
951c0b2f7Stbbdev 
1051c0b2f7Stbbdev     Unless required by applicable law or agreed to in writing, software
1151c0b2f7Stbbdev     distributed under the License is distributed on an "AS IS" BASIS,
1251c0b2f7Stbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1351c0b2f7Stbbdev     See the License for the specific language governing permissions and
1451c0b2f7Stbbdev     limitations under the License.
1551c0b2f7Stbbdev */
1651c0b2f7Stbbdev 
1751c0b2f7Stbbdev #include "common/test.h"
1851c0b2f7Stbbdev #include "common/utils.h"
1951c0b2f7Stbbdev #include "common/cpu_usertime.h"
2051c0b2f7Stbbdev #include "common/utils_concurrency_limit.h"
2151c0b2f7Stbbdev #include "common/parallel_invoke_common.h"
2251c0b2f7Stbbdev #include "common/memory_usage.h"
2351c0b2f7Stbbdev 
2451c0b2f7Stbbdev #include <cstddef>
2551c0b2f7Stbbdev #include <atomic>
2651c0b2f7Stbbdev 
2751c0b2f7Stbbdev //! \file test_parallel_invoke.cpp
2851c0b2f7Stbbdev //! \brief Test for [algorithms.parallel_invoke]
2951c0b2f7Stbbdev 
30*7cee2251SJhaShweta1 #if !EMSCRIPTEN
31*7cee2251SJhaShweta1 //! Emscripten requires preloading of the file used to determine memory usage, hence disabled.
3251c0b2f7Stbbdev //! Testing parallel_invoke memory usage
3351c0b2f7Stbbdev //! \brief \ref resource_usage \ref stress
3451c0b2f7Stbbdev TEST_CASE("Test memory leaks") {
3551c0b2f7Stbbdev     std::size_t number_of_measurements = 500;
3651c0b2f7Stbbdev     std::size_t current_memory_usage = 0, max_memory_usage = 0, stability_counter=0;
3751c0b2f7Stbbdev 
3851c0b2f7Stbbdev     // Limit concurrency to prevent extra allocations not dependent on algorithm behavior
3951c0b2f7Stbbdev     auto concurrency_limit = utils::get_platform_max_threads() < 8 ? utils::get_platform_max_threads() : 8;
4051c0b2f7Stbbdev     tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_limit);
4151c0b2f7Stbbdev 
4251c0b2f7Stbbdev     for (std::size_t i = 0; i < number_of_measurements; i++) {
4351c0b2f7Stbbdev         {
4451c0b2f7Stbbdev             // ~45000 workload tasks
4551c0b2f7Stbbdev             invoke_tree</*LevelTaskCount*/6, /*Depth*/6, /*WorkSize*/10>::generate_and_run();
4651c0b2f7Stbbdev         }
4751c0b2f7Stbbdev 
4851c0b2f7Stbbdev         current_memory_usage = utils::GetMemoryUsage();
4951c0b2f7Stbbdev         if (current_memory_usage > max_memory_usage) {
5051c0b2f7Stbbdev             stability_counter = 0;
5151c0b2f7Stbbdev             max_memory_usage = current_memory_usage;
5251c0b2f7Stbbdev         } else {
5351c0b2f7Stbbdev             stability_counter++;
5451c0b2f7Stbbdev         }
5551c0b2f7Stbbdev         // If the amount of used memory has not changed during 10% of executions,
5651c0b2f7Stbbdev         // then we can assume that the check was successful
5751c0b2f7Stbbdev         if (stability_counter > number_of_measurements / 10) return;
5851c0b2f7Stbbdev     }
5951c0b2f7Stbbdev     REQUIRE_MESSAGE(false, "Seems like we get memory leak here.");
6051c0b2f7Stbbdev }
61*7cee2251SJhaShweta1 #endif
6251c0b2f7Stbbdev 
6351c0b2f7Stbbdev template<typename Body>
test_from_2_to_10_arguments(const Body & body,const std::atomic<std::size_t> & counter)6451c0b2f7Stbbdev void test_from_2_to_10_arguments(const Body& body, const std::atomic<std::size_t>& counter) {
6551c0b2f7Stbbdev     tbb::parallel_invoke(body, body);
6651c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body);
6751c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body);
6851c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body, body);
6951c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body, body, body);
7051c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body, body, body, body);
7151c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body, body, body, body, body);
7251c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body, body, body, body, body, body);
7351c0b2f7Stbbdev     tbb::parallel_invoke(body, body, body, body, body, body, body, body, body, body);
7451c0b2f7Stbbdev 
7551c0b2f7Stbbdev     REQUIRE_MESSAGE(counter == (2 + 10) * 9 / 2,
7651c0b2f7Stbbdev         "Parallel invoke correctness was broken during lambda support test execution.");
7751c0b2f7Stbbdev }
7851c0b2f7Stbbdev 
7951c0b2f7Stbbdev //! Testing lambdas support
8051c0b2f7Stbbdev //! \brief \ref error_guessing
8151c0b2f7Stbbdev TEST_CASE("Test lambda support") {
8251c0b2f7Stbbdev     std::atomic<std::size_t> lambda_counter{0};
__anon420e3b420102null8351c0b2f7Stbbdev     auto body = [&]{ lambda_counter++; };
8451c0b2f7Stbbdev 
8551c0b2f7Stbbdev     test_from_2_to_10_arguments(body, lambda_counter);
8651c0b2f7Stbbdev }
8751c0b2f7Stbbdev 
8851c0b2f7Stbbdev std::atomic<std::size_t> func_counter{0};
func()8951c0b2f7Stbbdev void func() { func_counter++; };
9051c0b2f7Stbbdev 
9151c0b2f7Stbbdev //! Testing function pointers support
9251c0b2f7Stbbdev //! \brief \ref error_guessing
9351c0b2f7Stbbdev TEST_CASE("Test function pointers support") {
9451c0b2f7Stbbdev     auto func_ptr = &func;
9551c0b2f7Stbbdev     test_from_2_to_10_arguments(func_ptr, func_counter);
9651c0b2f7Stbbdev }
9751c0b2f7Stbbdev 
9851c0b2f7Stbbdev //! Testing workers going to sleep
9951c0b2f7Stbbdev //! \brief \ref error_guessing
10051c0b2f7Stbbdev TEST_CASE("Test that all workers sleep when no work") {
10151c0b2f7Stbbdev     invoke_tree</*LevelTaskCount*/9, /*Depth*/6, /*WorkSize*/10>::generate_and_run();
10251c0b2f7Stbbdev     TestCPUUserTime(utils::get_platform_max_threads());
10351c0b2f7Stbbdev }
104