1 /* --------------------------------------------------------------------------
2 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-20 Bradley M. Bell
3 
4 CppAD is distributed under the terms of the
5              Eclipse Public License Version 2.0.
6 
7 This Source Code may also be made available under the following
8 Secondary License when the conditions for such availability set forth
9 in the Eclipse Public License, Version 2.0 are satisfied:
10       GNU General Public License, Version 2.0 or later.
11 ---------------------------------------------------------------------------- */
12 
13 /*
14 $begin team_example.cpp$$
15 $spell
16     CppAD
17 $$
18 
19 $section Using a Team of AD Threads: Example and Test$$
20 
21 
22 $head Purpose$$
23 This example demonstrates how use a team of threads with CppAD.
24 
25 $head thread_team$$
26 The following three implementations of the
27 $cref team_thread.hpp$$ specifications are included:
28 $table
29 $rref team_openmp.cpp$$
30 $rref team_bthread.cpp$$
31 $rref team_pthread.cpp$$
32 $tend
33 
34 $head Source Code$$
35 $srcthisfile%0%// BEGIN C++%// END C++%1%$$
36 
37 $end
38 ------------------------------------------------------------------------------
39 */
40 // BEGIN C++
41 # include <cppad/cppad.hpp>
42 # include "team_thread.hpp"
43 # define NUMBER_THREADS  4
44 
45 namespace {
46     using CppAD::thread_alloc;
47 
48     // structure with information for one thread
49     typedef struct {
50         // function argument (worker input)
51         double          x;
52         // false if an error occurs, true otherwise (worker output)
53         bool            ok;
54     } work_one_t;
55     // vector with information for all threads
56     // (use pointers instead of values to avoid false sharing)
57     work_one_t* work_all_[NUMBER_THREADS];
58     // --------------------------------------------------------------------
59     // function that does the work for one thread
worker(void)60     void worker(void)
61     {   using CppAD::NearEqual;
62         using CppAD::AD;
63         bool ok = true;
64         size_t thread_num = thread_alloc::thread_num();
65 
66         // CppAD::vector uses the CppAD fast multi-threading allocator
67         CppAD::vector< AD<double> > ax(1), ay(1);
68         ax[0] = work_all_[thread_num]->x;
69         Independent(ax);
70         ay[0] = sqrt( ax[0] * ax[0] );
71         CppAD::ADFun<double> f(ax, ay);
72 
73         // Check function value corresponds to the identity
74         double eps = 10. * CppAD::numeric_limits<double>::epsilon();
75         ok        &= NearEqual(ay[0], ax[0], eps, eps);
76 
77         // Check derivative value corresponds to the identity.
78         CppAD::vector<double> d_x(1), d_y(1);
79         d_x[0] = 1.;
80         d_y    = f.Forward(1, d_x);
81         ok    &= NearEqual(d_x[0], 1., eps, eps);
82 
83         // pass back ok information for this thread
84         work_all_[thread_num]->ok = ok;
85     }
86 }
87 
88 // This test routine is only called by the master thread (thread_num = 0).
team_example(void)89 bool team_example(void)
90 {   bool ok = true;
91 
92     size_t num_threads = NUMBER_THREADS;
93 
94     // Check that no memory is in use or avialable at start
95     // (using thread_alloc in sequential mode)
96     size_t thread_num;
97     for(thread_num = 0; thread_num < num_threads; thread_num++)
98     {   ok &= thread_alloc::inuse(thread_num) == 0;
99         ok &= thread_alloc::available(thread_num) == 0;
100     }
101 
102     // initialize work_all_
103     for(thread_num = 0; thread_num < num_threads; thread_num++)
104     {   // allocate separate memory for this thread to avoid false sharing
105         size_t min_bytes(sizeof(work_one_t)), cap_bytes;
106         void*  v_ptr = thread_alloc::get_memory(min_bytes, cap_bytes);
107         work_all_[thread_num]     = static_cast<work_one_t*>(v_ptr);
108         // in case this thread's worker does not get called
109         work_all_[thread_num]->ok = false;
110         // parameter that defines the work for this thread
111         work_all_[thread_num]->x  = double(thread_num) + 1.;
112     }
113 
114     ok &= team_create(num_threads);
115     ok &= team_work(worker);
116     ok &= team_destroy();
117 
118     // go down so that free memrory for other threads before memory for master
119     thread_num = num_threads;
120     while(thread_num--)
121     {   // check that this thread was ok with the work it did
122         ok &= work_all_[thread_num]->ok;
123         // delete problem specific information
124         void* v_ptr = static_cast<void*>( work_all_[thread_num] );
125         thread_alloc::return_memory( v_ptr );
126         // check that there is no longer any memory inuse by this thread
127         // (for general applications, the master might still be using memory)
128         ok &= thread_alloc::inuse(thread_num) == 0;
129         // return all memory being held for future use by this thread
130         thread_alloc::free_available(thread_num);
131     }
132     return ok;
133 }
134 // END C++
135