File: team_example.cpp

package info (click to toggle)
cppad 2025.00.00.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 11,552 kB
  • sloc: cpp: 112,594; sh: 5,972; ansic: 179; python: 71; sed: 12; makefile: 10
file content (137 lines) | stat: -rw-r--r-- 4,388 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
// SPDX-FileCopyrightText: Bradley M. Bell <bradbell@seanet.com>
// SPDX-FileContributor: 2003-24 Bradley M. Bell
// ----------------------------------------------------------------------------

/*
{xrst_begin team_example.cpp}
{xrst_spell
  bthread
  openmp
  pthread
}

Using a Team of AD Threads: Example and Test
############################################

Purpose
*******
This example demonstrates how use a team of threads with CppAD.

thread_team
***********
The following three implementations of the
:ref:`team_thread.hpp-name` specifications are included:

.. csv-table::
   :widths: auto

   team_openmp.cpp,:ref:`team_openmp.cpp-title`
   team_bthread.cpp,:ref:`team_bthread.cpp-title`
   team_pthread.cpp,:ref:`team_pthread.cpp-title`

Source Code
***********
{xrst_literal
   // BEGIN C++
   // END C++
}

{xrst_end team_example.cpp}
------------------------------------------------------------------------------
*/
// BEGIN C++
# include <cppad/cppad.hpp>
# include "team_thread.hpp"
# define NUMBER_THREADS  4

namespace {
   using CppAD::thread_alloc;

   // structure with information for one thread
   typedef struct {
      // function argument (worker input)
      double          x;
      // false if an error occurs, true otherwise (worker output)
      bool            ok;
   } work_one_t;
   // vector with information for all threads
   // (use pointers instead of values to avoid false sharing)
   work_one_t* work_all_[NUMBER_THREADS];
   // --------------------------------------------------------------------
   // function that does the work for one thread
   void worker(void)
   {  using CppAD::NearEqual;
      using CppAD::AD;
      bool ok = true;
      size_t thread_num = thread_alloc::thread_num();

      // CppAD::vector uses the CppAD fast multi-threading allocator
      CppAD::vector< AD<double> > ax(1), ay(1);
      ax[0] = work_all_[thread_num]->x;
      Independent(ax);
      ay[0] = sqrt( ax[0] * ax[0] );
      CppAD::ADFun<double> f(ax, ay);

      // Check function value corresponds to the identity
      double eps = 10. * CppAD::numeric_limits<double>::epsilon();
      ok        &= NearEqual(ay[0], ax[0], eps, eps);

      // Check derivative value corresponds to the identity.
      CppAD::vector<double> d_x(1), d_y(1);
      d_x[0] = 1.;
      d_y    = f.Forward(1, d_x);
      ok    &= NearEqual(d_x[0], 1., eps, eps);

      // pass back ok information for this thread
      work_all_[thread_num]->ok = ok;
   }
}

// This test routine is only called by the master thread (thread_num = 0).
bool team_example(void)
{  bool ok = true;

   size_t num_threads = NUMBER_THREADS;

   // Check that no memory is in use or avialable at start
   // (using thread_alloc in sequential mode)
   size_t thread_num;
   for(thread_num = 0; thread_num < num_threads; thread_num++)
   {  ok &= thread_alloc::inuse(thread_num) == 0;
      ok &= thread_alloc::available(thread_num) == 0;
   }

   // initialize work_all_
   for(thread_num = 0; thread_num < num_threads; thread_num++)
   {  // allocate separate memory for this thread to avoid false sharing
      size_t min_bytes(sizeof(work_one_t)), cap_bytes;
      void*  v_ptr = thread_alloc::get_memory(min_bytes, cap_bytes);
      work_all_[thread_num]     = static_cast<work_one_t*>(v_ptr);
      // in case this thread's worker does not get called
      work_all_[thread_num]->ok = false;
      // parameter that defines the work for this thread
      work_all_[thread_num]->x  = double(thread_num) + 1.;
   }

   ok &= team_create(num_threads);
   ok &= team_work(worker);
   ok &= team_destroy();

   // go down so that free memrory for other threads before memory for master
   thread_num = num_threads;
   while(thread_num--)
   {  // check that this thread was ok with the work it did
      ok &= work_all_[thread_num]->ok;
      // delete problem specific information
      void* v_ptr = static_cast<void*>( work_all_[thread_num] );
      thread_alloc::return_memory( v_ptr );
      // check that there is no longer any memory inuse by this thread
      // (for general applications, the master might still be using memory)
      ok &= thread_alloc::inuse(thread_num) == 0;
      // return all memory being held for future use by this thread
      thread_alloc::free_available(thread_num);
   }
   return ok;
}
// END C++