| /* |
| Copyright 2005-2010 Intel Corporation. All Rights Reserved. |
| |
| This file is part of Threading Building Blocks. |
| |
| Threading Building Blocks is free software; you can redistribute it |
| and/or modify it under the terms of the GNU General Public License |
| version 2 as published by the Free Software Foundation. |
| |
| Threading Building Blocks is distributed in the hope that it will be |
| useful, but WITHOUT ANY WARRANTY; without even the implied warranty |
| of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with Threading Building Blocks; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| |
| As a special exception, you may use this file as part of a free software |
| library without restriction. Specifically, if other files instantiate |
| templates or use macros or inline functions from this file, or you compile |
| this file and link it with other files to produce an executable, this |
| file does not by itself cause the resulting executable to be covered by |
| the GNU General Public License. This exception does not however |
| invalidate any other reasons why the executable file might be covered by |
| the GNU General Public License. |
| */ |
| |
| #define NOMINMAX |
| #include "tbb/tbb.h" |
| #include "tbb/combinable.h" |
| #include <cstdio> |
| |
| #if !TBB_USE_EXCEPTIONS && _MSC_VER |
| // Suppress "C++ exception handler used, but unwind semantics are not enabled" warning in STL headers |
| #pragma warning (push) |
| #pragma warning (disable: 4530) |
| #endif |
| |
| #include <list> |
| |
| #if !TBB_USE_EXCEPTIONS && _MSC_VER |
| #pragma warning (pop) |
| #endif |
| |
| using namespace std; |
| using namespace tbb; |
| |
| typedef pair<int,int> max_element_t; |
| |
| void f(int val, int *arr, int start, int stop) { |
| for (int i=start; i<=stop; ++i) { |
| arr[i] = val; |
| } |
| } |
| |
| #include "harness.h" |
| |
| int Fib(int n) { |
| if( n<2 ) { |
| return n; |
| } else { |
| int x=0, y=0; |
| task_group g; |
| #if __TBB_LAMBDAS_PRESENT |
| g.run( [&]{x=Fib(n-1);} ); // spawn a task |
| g.run( [&]{y=Fib(n-2);} ); // spawn another task |
| g.wait(); // wait for both tasks to complete |
| #endif |
| return x+y; |
| } |
| } |
| |
| #include "harness_report.h" |
| #include "harness_assert.h" |
| |
| int TestMain () { |
| #if __TBB_LAMBDAS_PRESENT |
| const int N = 1000; |
| const int Grainsize = N/1000; |
| int a[N]; |
| ASSERT( MinThread>=1, "Error: Number of threads must be positive.\n"); |
| |
| for(int p=MinThread; p<=MaxThread; ++p) { |
| task_scheduler_init init(p); |
| |
| REMARK("Running lambda expression tests on %d threads...\n", p); |
| |
| //test parallel_for |
| REMARK("Testing parallel_for... "); |
| parallel_for(blocked_range<int>(0,N,Grainsize), |
| [&] (blocked_range<int>& r) { |
| for (int i=r.begin(); i!=r.end(); ++i) a[i] = i; |
| }); |
| ASSERT(a[0]==0 && a[N-1]==N-1, "parallel_for w/lambdas failed.\n"); |
| REMARK("passed.\n"); |
| |
| //test parallel_reduce |
| REMARK("Testing parallel_reduce... "); |
| int sum = parallel_reduce(blocked_range<int>(0,N,Grainsize), int(0), |
| [&] (blocked_range<int>& r, int current_sum) -> int { |
| for (int i=r.begin(); i!=r.end(); ++i) |
| current_sum += a[i]*(1000-i); |
| return current_sum; |
| }, |
| [] (const int x1, const int x2) { |
| return x1+x2; |
| } ); |
| |
| max_element_t max_el = |
| parallel_reduce(blocked_range<int>(0,N,Grainsize), make_pair(a[0], 0), |
| [&] (blocked_range<int>& r, max_element_t current_max) |
| -> max_element_t { |
| for (int i=r.begin(); i!=r.end(); ++i) |
| if (a[i]>current_max.first) |
| current_max = make_pair(a[i], i); |
| return current_max; |
| }, |
| [] (const max_element_t x1, const max_element_t x2) { |
| return (x1.first>x2.first)?x1:x2; |
| }); |
| ASSERT(sum==166666500 && max_el.first==999 && max_el.second==999, |
| "parallel_reduce w/lambdas failed.\n"); |
| REMARK("passed.\n"); |
| |
| //test parallel_do |
| REMARK("Testing parallel_do... "); |
| list<int> s; |
| s.push_back(0); |
| |
| parallel_do(s.begin(), s.end(), |
| [&](int foo, parallel_do_feeder<int>& feeder) { |
| if (foo == 42) return; |
| else if (foo>42) { |
| s.push_back(foo-3); |
| feeder.add(foo-3); |
| } else { |
| s.push_back(foo+5); |
| feeder.add(foo+5); |
| } |
| }); |
| ASSERT(s.back()==42, "parallel_do w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| |
| //test parallel_invoke |
| REMARK("Testing parallel_invoke... "); |
| parallel_invoke([&]{ f(2, a, 0, N/3); }, |
| [&]{ f(1, a, N/3+1, 2*(N/3)); }, |
| [&]{ f(0, a, 2*(N/3)+1, N-1); }); |
| ASSERT(a[0]==2.0 && a[N-1]==0.0, "parallel_invoke w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| |
| //test tbb_thread |
| REMARK("Testing tbb_thread... "); |
| tbb_thread::id myId; |
| tbb_thread myThread([](int x, int y) { |
| ASSERT(x==42 && y==64, "tbb_thread w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| }, 42, 64); |
| myThread.join(); |
| |
| // test task_group |
| REMARK("Testing task_group... "); |
| int result; |
| result = Fib(32); |
| ASSERT(result==2178309, "task_group w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| |
| // Reset array a to index values |
| parallel_for(blocked_range<int>(0,N,Grainsize), |
| [&] (blocked_range<int>& r) { |
| for (int i=r.begin(); i!=r.end(); ++i) a[i] = i; |
| }); |
| // test parallel_sort |
| REMARK("Testing parallel_sort... "); |
| int pivot = 42; |
| |
| // sort nearest by increasing distance from pivot |
| parallel_sort(a, a+N, |
| [&](int x, int y) { return(abs(pivot-x) < abs(pivot-y)); }); |
| ASSERT(a[0]==42 && a[N-1]==N-1, "parallel_sort w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| |
| //test combinable |
| REMARK("Testing combinable... "); |
| combinable<std::pair<int,int> > minmax_c([&]() { return std::make_pair(a[0], a[0]); } ); |
| |
| parallel_for(blocked_range<int>(0,N), |
| [&] (const blocked_range<int> &r) { |
| std::pair<int,int>& mmr = minmax_c.local(); |
| for(int i=r.begin(); i!=r.end(); ++i) { |
| if (mmr.first > a[i]) mmr.first = a[i]; |
| if (mmr.second < a[i]) mmr.second = a[i]; |
| } |
| }); |
| minmax_c.combine_each([](std::pair<int,int> x) { |
| int sum; |
| sum = x.first + x.second; |
| }); |
| std::pair<int,int> minmax_result_c; |
| minmax_result_c = |
| minmax_c.combine([](std::pair<int,int> x, std::pair<int,int> y) { |
| return std::make_pair(x.first<y.first?x.first:y.first, |
| x.second>y.second?x.second:y.second); |
| }); |
| ASSERT(minmax_result_c.first==0 && minmax_result_c.second==999, |
| "combinable w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| |
| //test enumerable_thread_specific |
| REMARK("Testing enumerable_thread_specific... "); |
| enumerable_thread_specific< std::pair<int,int> > minmax_ets([&]() { return std::make_pair(a[0], a[0]); } ); |
| |
| parallel_for(blocked_range<int>(0,N), |
| [&] (const blocked_range<int> &r) { |
| std::pair<int,int>& mmr = minmax_ets.local(); |
| for(int i=r.begin(); i!=r.end(); ++i) { |
| if (mmr.first > a[i]) mmr.first = a[i]; |
| if (mmr.second < a[i]) mmr.second = a[i]; |
| } |
| }); |
| minmax_ets.combine_each([](std::pair<int,int> x) { |
| int sum; |
| sum = x.first + x.second; |
| }); |
| std::pair<int,int> minmax_result_ets; |
| minmax_result_ets = |
| minmax_ets.combine([](std::pair<int,int> x, std::pair<int,int> y) { |
| return std::make_pair(x.first<y.first?x.first:y.first, |
| x.second>y.second?x.second:y.second); |
| }); |
| ASSERT(minmax_result_ets.first==0 && minmax_result_ets.second==999, |
| "enumerable_thread_specific w/lambda failed.\n"); |
| REMARK("passed.\n"); |
| } |
| return Harness::Done; |
| #else |
| return Harness::Skipped; |
| #endif /* !__TBB_LAMBDAS_PRESENT */ |
| } |