1 /*
2 Copyright (c) 2020-2023 Intel Corporation
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 #include "common/test.h"
18 #include "common/utils.h"
19 #include "common/cpu_usertime.h"
20 #include "common/utils_concurrency_limit.h"
21 #include "common/parallel_invoke_common.h"
22 #include "common/memory_usage.h"
23
24 #include <cstddef>
25 #include <atomic>
26
27 //! \file test_parallel_invoke.cpp
28 //! \brief Test for [algorithms.parallel_invoke]
29
30 #if !EMSCRIPTEN
31 //! Emscripten requires preloading of the file used to determine memory usage, hence disabled.
32 //! Testing parallel_invoke memory usage
33 //! \brief \ref resource_usage \ref stress
34 TEST_CASE("Test memory leaks") {
35 std::size_t number_of_measurements = 500;
36 std::size_t current_memory_usage = 0, max_memory_usage = 0, stability_counter=0;
37
38 // Limit concurrency to prevent extra allocations not dependent on algorithm behavior
39 auto concurrency_limit = utils::get_platform_max_threads() < 8 ? utils::get_platform_max_threads() : 8;
40 tbb::global_control control(tbb::global_control::max_allowed_parallelism, concurrency_limit);
41
42 for (std::size_t i = 0; i < number_of_measurements; i++) {
43 {
44 // ~45000 workload tasks
45 invoke_tree</*LevelTaskCount*/6, /*Depth*/6, /*WorkSize*/10>::generate_and_run();
46 }
47
48 current_memory_usage = utils::GetMemoryUsage();
49 if (current_memory_usage > max_memory_usage) {
50 stability_counter = 0;
51 max_memory_usage = current_memory_usage;
52 } else {
53 stability_counter++;
54 }
55 // If the amount of used memory has not changed during 10% of executions,
56 // then we can assume that the check was successful
57 if (stability_counter > number_of_measurements / 10) return;
58 }
59 REQUIRE_MESSAGE(false, "Seems like we get memory leak here.");
60 }
61 #endif
62
63 template<typename Body>
test_from_2_to_10_arguments(const Body & body,const std::atomic<std::size_t> & counter)64 void test_from_2_to_10_arguments(const Body& body, const std::atomic<std::size_t>& counter) {
65 tbb::parallel_invoke(body, body);
66 tbb::parallel_invoke(body, body, body);
67 tbb::parallel_invoke(body, body, body, body);
68 tbb::parallel_invoke(body, body, body, body, body);
69 tbb::parallel_invoke(body, body, body, body, body, body);
70 tbb::parallel_invoke(body, body, body, body, body, body, body);
71 tbb::parallel_invoke(body, body, body, body, body, body, body, body);
72 tbb::parallel_invoke(body, body, body, body, body, body, body, body, body);
73 tbb::parallel_invoke(body, body, body, body, body, body, body, body, body, body);
74
75 REQUIRE_MESSAGE(counter == (2 + 10) * 9 / 2,
76 "Parallel invoke correctness was broken during lambda support test execution.");
77 }
78
79 //! Testing lambdas support
80 //! \brief \ref error_guessing
81 TEST_CASE("Test lambda support") {
82 std::atomic<std::size_t> lambda_counter{0};
__anon420e3b420102null83 auto body = [&]{ lambda_counter++; };
84
85 test_from_2_to_10_arguments(body, lambda_counter);
86 }
87
88 std::atomic<std::size_t> func_counter{0};
func()89 void func() { func_counter++; };
90
91 //! Testing function pointers support
92 //! \brief \ref error_guessing
93 TEST_CASE("Test function pointers support") {
94 auto func_ptr = &func;
95 test_from_2_to_10_arguments(func_ptr, func_counter);
96 }
97
98 //! Testing workers going to sleep
99 //! \brief \ref error_guessing
100 TEST_CASE("Test that all workers sleep when no work") {
101 invoke_tree</*LevelTaskCount*/9, /*Depth*/6, /*WorkSize*/10>::generate_and_run();
102 TestCPUUserTime(utils::get_platform_max_threads());
103 }
104