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