1 /*
2     Copyright (c) 2005-2020 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"
TestMain()23 int 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 
35 using namespace std;
36 using namespace tbb;
37 
38 typedef pair<int,int> max_element_t;
39 
f(int val,int * arr,int start,int stop)40 void 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
Fib(int n)49 int 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 
TestMain()66 int 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