CppAD: A C++ Algorithmic Differentiation Package  20171217
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
tape_link.hpp
Go to the documentation of this file.
1 # ifndef CPPAD_CORE_TAPE_LINK_HPP
2 # define CPPAD_CORE_TAPE_LINK_HPP
3 
4 /* --------------------------------------------------------------------------
5 CppAD: C++ Algorithmic Differentiation: Copyright (C) 2003-17 Bradley M. Bell
6 
7 CppAD is distributed under multiple licenses. This distribution is under
8 the terms of the
9  Eclipse Public License Version 1.0.
10 
11 A copy of this license is included in the COPYING file of this distribution.
12 Please visit http://www.coin-or.org/CppAD/ for information on other licenses.
13 -------------------------------------------------------------------------- */
14 
15 # include <cppad/core/define.hpp>
18 
19 // needed before one can use CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
21 
22 namespace CppAD { // BEGIN_CPPAD_NAMESPACE
23 /*!
24 \file tape_link.hpp
25 Routines that Link AD<Base> and local::ADTape<Base> Objects.
26 
27 The routines that connect the AD<Base> class to the corresponding tapes
28 (one for each thread).
29 */
30 
31 /*!
32 Handle to the tape identifier for this AD<Base> class and the specific thread.
33 
34 \tparam Base
35 is the base type for this AD<Base> class.
36 
37 \param thread
38 is the thread number. The following condition must hold
39 \code
40 (! thread_alloc::in_parallel()) || thread == thread_alloc::thread_num()
41 \endcode
42 
43 \return
44 is a handle to the tape identifier for this thread
45 and AD<Base> class.
46 */
47 template <class Base>
48 inline tape_id_t** AD<Base>::tape_id_handle(size_t thread)
50  static tape_id_t* tape_id_table[CPPAD_MAX_NUM_THREADS];
53  );
54 
55  return tape_id_table + thread;
56 }
57 
58 /*!
59 Pointer to the tape identifier for this AD<Base> class and the specific thread.
60 
61 \tparam Base
62 is the base type for this AD<Base> class.
63 
64 \param thread
65 is the thread number; i.e.,
66 \code
67 thread == thread_alloc::thread_num()
68 \endcode
69 If this condition is not satisfied, and \c NDEBUG is not defined,
70 a CPPAD_ASSERT_UNKNOWN is generated.
71 
72 \return
73 is a pointer to the tape identifier for this thread
74 and AD<Base> class.
75 
76 \par Restrictions
77 This routine should only be called if there was a tape created
78 for the specified thread (it may no longer be recording).
79 */
80 template <class Base>
81 inline tape_id_t* AD<Base>::tape_id_ptr(size_t thread)
82 { CPPAD_ASSERT_UNKNOWN( *tape_id_handle(thread) != CPPAD_NULL )
83  return *tape_id_handle(thread);
84 }
85 
86 /*!
87 Handle for the tape for this AD<Base> class and the specific thread.
88 
89 \tparam Base
90 is the base type for this AD<Base> class.
91 
92 
93 \param thread
94 is the thread number; i.e.,
95 \code
96 thread == thread_alloc::thread_num()
97 \endcode
98 If this condition is not satisfied, and \c NDEBUG is not defined,
99 a CPPAD_ASSERT_UNKNOWN is generated.
100 
101 \return
102 is a handle for the AD<Base> class and the specified thread.
103 */
104 template <class Base>
107  static local::ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS];
109 
110  return tape_table + thread;
111 }
112 
113 /*!
114 Pointer for the tape for this AD<Base> class and the current thread.
115 
116 \code
117 thread == thread_alloc::thread_num()
118 \endcode
119 
120 \tparam Base
121 is the base type corresponding to AD<Base> operations.
122 
123 \return
124 is a pointer to the tape that is currently recording AD<Base> operations
125 for the current thread.
126 If this value is \c CPPAD_NULL, there is no tape currently
127 recording AD<Base> operations for this thread.
128 */
129 template <class Base>
131 { size_t thread = thread_alloc::thread_num();
132  return *tape_handle(thread);
133 }
134 
135 /*!
136 Pointer for the tape for this AD<Base> class and the specified tape
137 identifier.
138 
139 \tparam Base
140 is the base type corresponding to AD<Base> operations.
141 
142 \param tape_id
143 is the identifier for the tape that is currently recording
144 AD<Base> operations for the current thread.
145 It must hold that the current thread is
146 \code
147  thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS )
148 \endcode
149 and that there is a tape recording AD<Base> operations
150 for this thread.
151 If this is not the currently executing thread,
152 a variable from a different thread is being recorded on the
153 tape for this thread which is a user error.
154 
155 \return
156 is a pointer to the tape that is currently recording AD<Base> operations
157 for the current thread (and it is not \c CPPAD_NULL).
158 
159 \par Restrictions
160 This routine should only be called if there is a tape recording operaitons
161 for the specified thread.
162 */
163 template <class Base>
165 { size_t thread = size_t( tape_id % CPPAD_MAX_NUM_THREADS );
167  thread == thread_alloc::thread_num(),
168  "Attempt to use an AD variable with two different threads."
169  );
170  CPPAD_ASSERT_UNKNOWN( tape_id == *tape_id_ptr(thread) );
171  CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL );
172  return *tape_handle(thread);
173 }
174 
175 /*!
176 Create and delete tapes that record AD<Base> operations for current thread.
177 
178 \par thread
179 the current thread is given by
180 \code
181 thread = thread_alloc::thread_num()
182 \endcode
183 
184 \tparam Base
185 is the base type corresponding to AD<Base> operations.
186 
187 \param job
188 This argument determines if we are creating a new tape, or deleting an
189 old one.
190 - \c tape_manage_new :
191 Creates and a new tape.
192 It is assumed that there is no tape recording AD<Base> operations
193 for this thread when \c tape_manage is called.
194 It the input value of <tt>*tape_id_handle(thread)</tt> is \c CPPAD_NULL,
195 it will be changed to a non-zero pointer and the corresponding value
196 of <tt>*tape_id_ptr(thread)</tt> will be set to
197 <tt>thread + CPPAD_MAX_NUM_THREADS</tt>.
198 - \c tape_manage_delete :
199 It is assumed that there is a tape recording AD<Base> operations
200 for this thread when \c tape_manage is called.
201 The value of <tt>*tape_id_ptr(thread)</tt> will be advanced by
202 \c CPPAD_MAX_NUM_THREADS.
203 
204 
205 \return
206 - <tt>job == tape_manage_new</tt>: a pointer to the new tape is returned.
207 - <tt>job == tape_manage_delete</tt>: the value \c CPPAD_NULL is returned.
208 */
209 template <class Base>
211 { // this routine has static variables so first call cannot be in parallel
213 
214  // The tape for the master thread
215  static local::ADTape<Base> tape_zero;
216 
217  // Pointer to the tape for each thread
218  static local::ADTape<Base>* tape_table[CPPAD_MAX_NUM_THREADS];
219 
220  // The id current being used for each of the tapes
221  static tape_id_t tape_id_save[CPPAD_MAX_NUM_THREADS];
222 
223  // Thread corresponding to this call
224  size_t thread = thread_alloc::thread_num();
225 
226  // tape_manage_clear
227  if( job == tape_manage_clear )
228  { // This operation cannot be done in parallel
229  CPPAD_ASSERT_UNKNOWN(thread == 0 && (! thread_alloc::in_parallel()));
230  for(thread = 0; thread < CPPAD_MAX_NUM_THREADS; thread++)
231  { // if this thread has a tape
232  if( tape_table[thread] != CPPAD_NULL )
233  { // id corresponding to this thread
234  tape_id_save[thread] = tape_table[thread]->id_;
235  *tape_id_handle(thread) = &tape_id_save[thread];
236 
237  // delete all but the master thread
238  if( thread != 0 )
239  delete( tape_table[thread] );
240 
241  // set the tape pointer to null
242  tape_table[thread] = CPPAD_NULL;
243  }
244  }
245  return CPPAD_NULL;
246  }
247 
248  // id and tape fpor this thread
249  tape_id_t** tape_id = tape_id_handle(thread);
250  local::ADTape<Base>** tape = tape_handle(thread);
251 
252  // check if there is no tape currently attached to this thread
253  if( tape_table[thread] == CPPAD_NULL )
254  { // allocate separate memroy to avoid false sharing
255  if( thread == 0 )
256  { // mastert tape is a static in this routine
257  tape_table[thread] = &tape_zero;
258  }
259  else
260  { // other tapes are allocated
261  tape_table[thread] = new local::ADTape<Base>();
262  }
263  // current id and pointer to this tape
264  tape_table[thread]->id_ = tape_id_save[thread];
265  *tape_id = &tape_table[thread]->id_;
266 
267  // if id is zero, initialize it so that
268  // thread == tape id % CPPAD_MAX_NUM_THREADS
269  if( **tape_id == 0 )
270  { size_t new_tape_id = thread + CPPAD_MAX_NUM_THREADS;
272  std::numeric_limits<tape_id_t>::max() >= new_tape_id,
273  "cppad_tape_id_type maximum value has been execeeded"
274  );
275  **tape_id = static_cast<tape_id_t>( new_tape_id );
276  }
277  }
278  // make sure tape_id_handle(thread) is pointing to the proper place
279  CPPAD_ASSERT_UNKNOWN( *tape_id == &tape_table[thread]->id_ );
280 
281  // make sure tape_id value is valid for this thread
283  size_t( **tape_id % CPPAD_MAX_NUM_THREADS ) == thread
284  );
285 
286  switch(job)
287  { case tape_manage_new:
288  // tape for this thread must be null at the start
289  CPPAD_ASSERT_UNKNOWN( *tape == CPPAD_NULL );
290  *tape = tape_table[thread];
291  break;
292 
293  case tape_manage_delete:
294  CPPAD_ASSERT_UNKNOWN( *tape == tape_table[thread] );
296  std::numeric_limits<CPPAD_TAPE_ID_TYPE>::max()
297  - CPPAD_MAX_NUM_THREADS > **tape_id,
298  "To many different tapes given the type used for "
299  "CPPAD_TAPE_ID_TYPE"
300  );
301  // advance tape identfier so all AD<Base> variables become parameters
302  **tape_id += CPPAD_MAX_NUM_THREADS;
303  // free memory corresponding to recording in the old tape
304  tape_table[thread]->Rec_.free();
305  // inform rest of CppAD that no tape recording for this thread
306  *tape = CPPAD_NULL;
307  break;
308 
309  case tape_manage_clear:
310  CPPAD_ASSERT_UNKNOWN(false);
311  }
312  return *tape;
313 }
314 
315 /*!
316 Get a pointer to tape that records AD<Base> operations for the current thread.
317 
318 \tparam Base
319 is the base type corresponding to AD<Base> operations.
320 
321 \par thread
322 The current thread must be given by
323 \code
324  thread = this->tape_id_ % CPPAD_MAX_NUM_THREADS
325 \endcode
326 
327 \return
328 is a pointer to the tape that is currently recording AD<Base> operations
329 for the current thread.
330 This value must not be \c CPPAD_NULL; i.e., there must be a tape currently
331 recording AD<Base> operations for this thread.
332 */
333 
334 template <class Base>
336 {
337  size_t thread = size_t( tape_id_ % CPPAD_MAX_NUM_THREADS );
338  CPPAD_ASSERT_UNKNOWN( tape_id_ == *tape_id_ptr(thread) );
339  CPPAD_ASSERT_UNKNOWN( *tape_handle(thread) != CPPAD_NULL );
340  return *tape_handle(thread);
341 }
342 
343 } // END_CPPAD_NAMESPACE
344 # endif
#define CPPAD_ASSERT_KNOWN(exp, msg)
Check that exp is true, if not print msg and terminate execution.
Define processor symbols and macros that are used by CppAD.
static tape_id_t * tape_id_ptr(size_t thread)
Pointer to the tape identifier for this AD&lt;Base&gt; class and the specific thread.
Definition: tape_link.hpp:81
static bool in_parallel(void)
Are we in a parallel execution state; i.e., is it possible that other threads are currently executing...
Define the CppAD error checking macros (all of which begin with CPPAD_ASSERT_)
static size_t thread_num(void)
Get current thread number.
#define CPPAD_ASSERT_FIRST_CALL_NOT_PARALLEL
Check that the first call to a routine is not during parallel execution mode.
static local::ADTape< Base > * tape_manage(tape_manage_job job)
Create and delete tapes that record AD&lt;Base&gt; operations for current thread.
Definition: tape_link.hpp:210
static local::ADTape< Base > ** tape_handle(size_t thread)
Handle for the tape for this AD&lt;Base&gt; class and the specific thread.
Definition: tape_link.hpp:105
static local::ADTape< Base > * tape_ptr(void)
Pointer for the tape for this AD&lt;Base&gt; class and the current thread.
Definition: tape_link.hpp:130
#define CPPAD_ASSERT_UNKNOWN(exp)
Check that exp is true, if not terminate execution.
local::recorder< Base > Rec_
This is where the information is recorded.
Definition: ad_tape.hpp:106
static tape_id_t ** tape_id_handle(size_t thread)
Handle to the tape identifier for this AD&lt;Base&gt; class and the specific thread.
Definition: tape_link.hpp:48
Class used to hold tape that records AD&lt;Base&gt; operations.
Definition: ad_tape.hpp:26
tape_manage_job
Definition: ad.hpp:27
File used to define the CppAD multi-threading allocator class.
tape_id_t id_
Unique identifier for this tape.
Definition: ad_tape.hpp:101
local::ADTape< Base > * tape_this(void) const
Get a pointer to tape that records AD&lt;Base&gt; operations for the current thread.
Definition: tape_link.hpp:335
CPPAD_TAPE_ID_TYPE tape_id_t
Definition: declare_ad.hpp:45