http://trac2.assembla.com/hoomd/browser/branches/gpu-iface-rewrite/src/utils/GPUWorker.h?rev=994

1 /*
2 Highly Optimized Object-Oriented Molecular Dynamics (HOOMD) Open
3 Source Software License
4 Copyright (c) 2008 Ames Laboratory Iowa State University
5 All rights reserved.
6
7 Redistribution and use of HOOMD, in source and binary forms, with or
8 without modification, are permitted, provided that the following
9 conditions are met:
10
11 * Redistributions of source code must retain the above copyright notice,
12 this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in the
16 documentation and/or other materials provided with the distribution.
17
18 * Neither the name of the copyright holder nor the names HOOMD's
19 contributors may be used to endorse or promote products derived from this
20 software without specific prior written permission.
21
22 Disclaimer
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND
25 CONTRIBUTORS ``AS IS''  AND ANY EXPRESS OR IMPLIED WARRANTIES,
26 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
27 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS  BE LIABLE
30 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
36 THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 // $Id$
40 // $URL$
41
42 /*! \file GPUWorker.h
43         \brief Defines the GPUWorker class
44 */
45
46 // only compile if USE_CUDA is enabled
47 #ifdef USE_CUDA
48
49 #ifndef __GPUWORKER_H__
50 #define __GPUWORKER_H__
51
52 #include <deque>
53 #include <stdexcept>
54
55 #include <boost/function.hpp>
56 #include <boost/thread/thread.hpp>
57 #include <boost/thread/mutex.hpp>
58 #include <boost/thread/condition.hpp>
59 #include <boost/scoped_ptr.hpp>
60
61 #include <cuda_runtime_api.h>
62
63 //! Implements a worker thread controlling a single GPU
64 /*! CUDA requires one thread per GPU in multiple GPU code. It is not always
65         convenient to write multiple-threaded code where all threads are peers.
66         Sometimes, a master/slave approach can be the simplest and quickest to write.
67         
68         GPUWorker provides the underlying worker threads that a master/slave
69         approach needs to execute on multiple GPUs. It is designed so that
70         a \b single thread can own multiple GPUWorkers, each of whom execute on
71         their own GPU. The master thread can call any CUDA function on that GPU
72         by passing a bound boost::function into call() or callAsync(). Internally, these
73         calls are executed inside the worker thread so that they all share the same
74         CUDA context.
75         
76         On construction, a GPUWorker is automatically associated with a device. You
77         pass in an integer device number which is used to call cudaSetDevice()
78         in the worker thread.
79         
80         After the GPUWorker is constructed, you can make calls on the GPU
81         by submitting them with call(). To queue calls, use callAsync(), but
82         please read carefully and understand the race condition warnings before
83         using callAsync(). sync() can be used to synchronize the master thread
84         with the worker thread. If any called GPU function returns an error,
85         call() (or the sync() after a callAsync()) will throw a std::runtime_error.
86         
87         To share a single GPUWorker with multiple objects, use boost::shared_ptr.
88 \code
89 boost::shared_ptr<GPUWorker> gpu(new GPUWorker(dev));
90 gpu->call(whatever...)
91 SomeClass cls(gpu);
92 // now cls can use gpu to execute in the same worker thread as everybody else
93 \endcode       
94         
95         \warning A single GPUWorker is intended to be used by a \b single master thread
96         (though master threads can use multiple GPUWorkers). If a single GPUWorker is
97         shared amoung multiple threads then ther \e should not be any horrible consequences.
98         All tasks will still be exected in the order in which they
99         are recieved, but sync() becomes ill-defined (how can one synchronize with a worker that
100         may be receiving commands from another master thread?) and consequently all synchronous
101         calls via call() \b may not actually be synchronous leading to weird race conditions for the
102         caller. Then againm calls via call() \b might work due to the inclusion of a mutex lock:
103         still, multiple threads calling a single GPUWorker is an untested configuration.
104         Use at your own risk.
105
106         \note GPUWorker works in both Linux and Windows (tested with VS2005). However,
107         in Windows, you need to define BOOST_BIND_ENABLE_STDCALL in your project options
108         in order to be able to call CUDA runtime API functions with boost::bind.
109 */
110 class GPUWorker
111         {
112         public:
113                 //! Creates a worker thread and ties it to a particular gpu \a dev
114                 GPUWorker(int dev);
115                
116                 //! Destructor
117                 ~GPUWorker();
118                
119                 //! Makes a synchronous function call executed by the worker thread
120                 void call(const boost::function< cudaError_t (void) > &func);
121                
122                 //! Queues an asynchronous function call to be executed by the worker thread
123                 void callAsync(const boost::function< cudaError_t (void) > &func);
124
125                 //! Blocks the calling thread until all queued calls have been executed
126                 void sync();
127        
128         private:
129                 //! Flag to indicate the worker thread is to exit
130                 bool m_exit;
131                
132                 //! Flag to indicate there is work to do
133                 bool m_work_to_do;
134                
135                 //! Error from last cuda call
136                 cudaError_t m_last_error;
137                
138                 //! The queue of function calls to make
139                 std::deque< boost::function< cudaError_t (void) > > m_work_queue;
140                
141                 //! Mutex for accessing m_exit, m_work_queue, m_work_to_do, and m_last_error
142                 boost::mutex m_mutex;
143                
144                 //! Mutex for syncing after every operation
145                 boost::mutex m_call_mutex;
146                
147                 //! Condition variable to signal m_work_to_do = true
148                 boost::condition m_cond_work_to_do;
149                
150                 //! Condition variable to signal m_work_to_do = false (work is complete)
151                 boost::condition m_cond_work_done;
152                
153                 //! Thread
154                 boost::scoped_ptr<boost::thread> m_thread;
155                
156                 //! Worker thread loop
157                 void performWorkLoop();
158         };
159                
160                
161 #endif
162 #endif

Reply via email to