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