1/*
2 Copyright (c) 2005-2019 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#define NOMINMAX
18
19#include "harness_defs.h"
20#if __TBB_TEST_SKIP_LAMBDA
21
22#include "harness.h"
23int TestMain() {
24 REPORT("Known issue: lambdas are not properly supported on the platform \n");
25 return Harness::Skipped;
26}
27
28#else /*__TBB_TEST_SKIP_LAMBDA*/
29
30#include "tbb/tbb.h"
31#include "tbb/combinable.h"
32#include <cstdio>
33#include <list>
34
35using namespace std;
36using namespace tbb;
37
38typedef pair<int,int> max_element_t;
39
40void f(int val, int *arr, int start, int stop) {
41 for (int i=start; i<=stop; ++i) {
42 arr[i] = val;
43 }
44}
45
46#include "harness.h"
47
48#if __TBB_TASK_GROUP_CONTEXT
49int Fib(int n) {
50 if( n<2 ) {
51 return n;
52 } else {
53 int x=0, y=0;
54 task_group g;
55 g.run( [&]{x=Fib(n-1);} ); // spawn a task
56 g.run( [&]{y=Fib(n-2);} ); // spawn another task
57 g.wait(); // wait for both tasks to complete
58 return x+y;
59 }
60}
61#endif /* !__TBB_TASK_GROUP_CONTEXT */
62
63#include "harness_report.h"
64#include "harness_assert.h"
65
66int TestMain () {
67 const int N = 1000;
68 const int Grainsize = N/1000;
69 int a[N];
70 int max_sum;
71 ASSERT( MinThread>=1, "Error: Number of threads must be positive.\n");
72
73 for(int p=MinThread; p<=MaxThread; ++p) {
74 task_scheduler_init init(p);
75
76 REMARK("Running lambda expression tests on %d threads...\n", p);
77
78 //test parallel_for
79 REMARK("Testing parallel_for... ");
80 parallel_for(blocked_range<int>(0,N,Grainsize),
81 [&] (blocked_range<int>& r) {
82 for (int i=r.begin(); i!=r.end(); ++i) a[i] = i;
83 });
84 ASSERT(a[0]==0 && a[N-1]==N-1, "parallel_for w/lambdas failed.\n");
85 REMARK("passed.\n");
86
87 //test parallel_reduce
88 REMARK("Testing parallel_reduce... ");
89 int sum = parallel_reduce(blocked_range<int>(0,N,Grainsize), int(0),
90 [&] (blocked_range<int>& r, int current_sum) -> int {
91 for (int i=r.begin(); i!=r.end(); ++i)
92 current_sum += a[i]*(1000-i);
93 return current_sum;
94 },
95 [] (const int x1, const int x2) {
96 return x1+x2;
97 } );
98
99 max_element_t max_el =
100 parallel_reduce(blocked_range<int>(0,N,Grainsize), make_pair(a[0], 0),
101 [&] (blocked_range<int>& r, max_element_t current_max)
102 -> max_element_t {
103 for (int i=r.begin(); i!=r.end(); ++i)
104 if (a[i]>current_max.first)
105 current_max = make_pair(a[i], i);
106 return current_max;
107 },
108 [] (const max_element_t x1, const max_element_t x2) {
109 return (x1.first>x2.first)?x1:x2;
110 });
111 ASSERT(sum==166666500 && max_el.first==999 && max_el.second==999,
112 "parallel_reduce w/lambdas failed.\n");
113 REMARK("passed.\n");
114
115 //test parallel_do
116 REMARK("Testing parallel_do... ");
117 list<int> s;
118 s.push_back(0);
119
120 parallel_do(s.begin(), s.end(),
121 [&](int foo, parallel_do_feeder<int>& feeder) {
122 if (foo == 42) return;
123 else if (foo>42) {
124 s.push_back(foo-3);
125 feeder.add(foo-3);
126 } else {
127 s.push_back(foo+5);
128 feeder.add(foo+5);
129 }
130 });
131 ASSERT(s.back()==42, "parallel_do w/lambda failed.\n");
132 REMARK("passed.\n");
133
134 //test parallel_invoke
135 REMARK("Testing parallel_invoke... ");
136 parallel_invoke([&]{ f(2, a, 0, N/3); },
137 [&]{ f(1, a, N/3+1, 2*(N/3)); },
138 [&]{ f(0, a, 2*(N/3)+1, N-1); });
139 ASSERT(a[0]==2.0 && a[N-1]==0.0, "parallel_invoke w/lambda failed.\n");
140 REMARK("passed.\n");
141
142 //test tbb_thread
143 REMARK("Testing tbb_thread... ");
144 tbb_thread::id myId;
145 tbb_thread myThread([](int x, int y) {
146 ASSERT(x==42 && y==64, "tbb_thread w/lambda failed.\n");
147 REMARK("passed.\n");
148 }, 42, 64);
149 myThread.join();
150
151#if __TBB_TASK_GROUP_CONTEXT
152 // test task_group
153 REMARK("Testing task_group... ");
154 int result;
155 result = Fib(32);
156 ASSERT(result==2178309, "task_group w/lambda failed.\n");
157 REMARK("passed.\n");
158#endif /* __TBB_TASK_GROUP_CONTEXT */
159
160 // Reset array a to index values
161 parallel_for(blocked_range<int>(0,N,Grainsize),
162 [&] (blocked_range<int>& r) {
163 for (int i=r.begin(); i!=r.end(); ++i) a[i] = i;
164 });
165 // test parallel_sort
166 REMARK("Testing parallel_sort... ");
167 int pivot = 42;
168
169 // sort nearest by increasing distance from pivot
170 parallel_sort(a, a+N,
171 [&](int x, int y) { return(abs(pivot-x) < abs(pivot-y)); });
172 ASSERT(a[0]==42 && a[N-1]==N-1, "parallel_sort w/lambda failed.\n");
173 REMARK("passed.\n");
174
175 //test combinable
176 REMARK("Testing combinable... ");
177 combinable<std::pair<int,int> > minmax_c([&]() { return std::make_pair(a[0], a[0]); } );
178
179 parallel_for(blocked_range<int>(0,N),
180 [&] (const blocked_range<int> &r) {
181 std::pair<int,int>& mmr = minmax_c.local();
182 for(int i=r.begin(); i!=r.end(); ++i) {
183 if (mmr.first > a[i]) mmr.first = a[i];
184 if (mmr.second < a[i]) mmr.second = a[i];
185 }
186 });
187 max_sum = 0;
188 minmax_c.combine_each([&max_sum](std::pair<int,int> x) {
189 int tsum = x.first + x.second;
190 if( tsum>max_sum ) max_sum = tsum;
191 });
192 ASSERT( (N-1)<=max_sum && max_sum<=a[0]+N-1, "combinable::combine_each /w lambda failed." );
193
194 std::pair<int,int> minmax_result_c;
195 minmax_result_c =
196 minmax_c.combine([](std::pair<int,int> x, std::pair<int,int> y) {
197 return std::make_pair(x.first<y.first?x.first:y.first,
198 x.second>y.second?x.second:y.second);
199 });
200 ASSERT(minmax_result_c.first==0 && minmax_result_c.second==999,
201 "combinable w/lambda failed.\n");
202 REMARK("passed.\n");
203
204 //test enumerable_thread_specific
205 REMARK("Testing enumerable_thread_specific... ");
206 enumerable_thread_specific< std::pair<int,int> > minmax_ets([&]() { return std::make_pair(a[0], a[0]); } );
207
208 max_sum = 0;
209 parallel_for(blocked_range<int>(0,N),
210 [&] (const blocked_range<int> &r) {
211 std::pair<int,int>& mmr = minmax_ets.local();
212 for(int i=r.begin(); i!=r.end(); ++i) {
213 if (mmr.first > a[i]) mmr.first = a[i];
214 if (mmr.second < a[i]) mmr.second = a[i];
215 }
216 });
217 minmax_ets.combine_each([&max_sum](std::pair<int,int> x) {
218 int tsum = x.first + x.second;
219 if( tsum>max_sum ) max_sum = tsum;
220 });
221 ASSERT( (N-1)<=max_sum && max_sum<=a[0]+N-1, "enumerable_thread_specific::combine_each /w lambda failed." );
222
223 std::pair<int,int> minmax_result_ets;
224 minmax_result_ets =
225 minmax_ets.combine([](std::pair<int,int> x, std::pair<int,int> y) {
226 return std::make_pair(x.first<y.first?x.first:y.first,
227 x.second>y.second?x.second:y.second);
228 });
229 ASSERT(minmax_result_ets.first==0 && minmax_result_ets.second==999,
230 "enumerable_thread_specific w/lambda failed.\n");
231 REMARK("passed.\n");
232 }
233 return Harness::Done;
234}
235#endif /* __TBB_TEST_SKIP_LAMBDA */
236