Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ArrayData.H

Go to the documentation of this file.
00001 /*!@file Image/ArrayData.H The guts of the 2D ref-counted copy-on-write array
00002     implementation */
00003 
00004 // //////////////////////////////////////////////////////////////////// //
00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the //
00006 // University of Southern California (USC) and the iLab at USC.         //
00007 // See http://iLab.usc.edu for information about this project.          //
00008 // //////////////////////////////////////////////////////////////////// //
00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00011 // in Visual Environments, and Applications'' by Christof Koch and      //
00012 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00013 // pending; application number 09/912,225 filed July 23, 2001; see      //
00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00015 // //////////////////////////////////////////////////////////////////// //
00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00017 //                                                                      //
00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00019 // redistribute it and/or modify it under the terms of the GNU General  //
00020 // Public License as published by the Free Software Foundation; either  //
00021 // version 2 of the License, or (at your option) any later version.     //
00022 //                                                                      //
00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00026 // PURPOSE.  See the GNU General Public License for more details.       //
00027 //                                                                      //
00028 // You should have received a copy of the GNU General Public License    //
00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00031 // Boston, MA 02111-1307 USA.                                           //
00032 // //////////////////////////////////////////////////////////////////// //
00033 //
00034 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu>
00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/ArrayData.H $
00036 // $Id: ArrayData.H 11860 2009-10-16 23:27:33Z dparks $
00037 //
00038 
00039 #ifndef ARRAYDATA_H_DEFINED
00040 #define ARRAYDATA_H_DEFINED
00041 
00042 #include "Image/Dims.H"
00043 #include "Util/Alloc.H" // for invt_allocate()/invt_deallocate()
00044 #include "Util/TypeTraits.H"
00045 #include "Util/log.H"
00046 #include "rutz/atomic.h"
00047 
00048 #include <cstring> // for memset() and memcpy()
00049 #include <new> // for placement new, in ArrayData's ctors
00050 
00051 #ifdef INVT_USE_CUDA
00052 #include "CUDA/CudaAlloc.H"
00053 #include "CUDA/CudaDevices.H"
00054 #endif
00055 
00056 //! Specifies what to do with the T* used to init an ArrayData.
00057 enum StoragePolicy
00058   {
00059     //! Make an initial copy of the data, then copy-on-write as usual.
00060     MAKE_OWN_COPY,
00061 
00062     //! Borrow the data, with write-through.
00063     /*! Writing to the Array will modify the T[] that initialized it. */
00064     WRITE_THRU
00065   };
00066 
00067 //! Specifies how to initialize the pixels of a new image.
00068 enum InitPolicy
00069   {
00070     //! All elements are initialized to the pixel type's zero or default value.
00071     ZEROS,
00072 
00073     //! Pixels are only minimally initialized.
00074     /*! For trivial types, this means the pixel values are not
00075         initialized at all; for non-trivial user-defined types, this
00076         means each pixel is copy-constructed from the type's default
00077         value. */
00078     NO_INIT
00079   };
00080 
00081 //! Specifies where on a particular device the memory is stored
00082 enum MemoryPolicy
00083   {
00084     //! On GPU, global (to a particular set of kernels on a single device)
00085     GLOBAL_DEVICE_MEMORY,
00086     //! On GPU, located in texture memory
00087     TEXTURE_DEVICE_MEMORY,
00088     //! On CPU/Host
00089     HOST_MEMORY,
00090   };
00091 
00092 //! Device id for the host, to distinguish from CUDA devices
00093 #define CUDA_HOST_DEVICE_NUM -1
00094 
00095 
00096 //! Function to wrap use of invt_allocate to allow for CUDA memory policies
00097 inline void* wrap_invt_allocate(size_t user_nbytes, const MemoryPolicy mp, const int dev)
00098   {
00099 #ifdef INVT_USE_CUDA
00100     switch(mp)
00101     {
00102     case GLOBAL_DEVICE_MEMORY:
00103     case TEXTURE_DEVICE_MEMORY:
00104       return cuda_invt_allocate(user_nbytes,dev);
00105     case HOST_MEMORY:
00106       return invt_allocate(user_nbytes);
00107     default:
00108       LFATAL("Invalid memory policy %d",mp);
00109       return NULL;
00110     }
00111     LFATAL("Should be impossible to get here");
00112     return NULL;
00113 #else
00114     // Optimization, don't look at memory policy
00115     return invt_allocate(user_nbytes);
00116 #endif    
00117   }
00118 
00119 //! Function to wrap use of invt_deallocate to allow for CUDA memory policies
00120 inline void wrap_invt_deallocate(void *mem, const MemoryPolicy mp, const int dev, const size_t nBytes)
00121   {
00122 #ifdef INVT_USE_CUDA
00123     switch(mp)
00124     {
00125     case GLOBAL_DEVICE_MEMORY:
00126     case TEXTURE_DEVICE_MEMORY:
00127       cuda_invt_deallocate(mem, dev,nBytes);
00128       return;
00129     case HOST_MEMORY:
00130       invt_deallocate(mem);
00131       return;
00132     }
00133 #else
00134     // Optimization, don't look at memory policy
00135     invt_deallocate(mem);
00136 #endif    
00137   }
00138 
00139 
00140 void check_acquisition(StoragePolicy s, int count) throw();
00141 
00142 
00143 
00144 //! Implements a ref-counted 2-D array, should only be used via ArrayHandle.
00145 /*! ArrayData implements a 2-D array, by storing:
00146       - a Dims representing the width+height of the array,
00147       - a pointer to the dynamically allocated memory where the array
00148         data are stored,
00149       - a reference count, and
00150       - a StoragePolicy, indicating whether the ArrayData object
00151         "owns" the memory and should delete[] it eventually (in the
00152         case of MAKE_OWN_COPY), or whether someone else "owns" the
00153         memory and will eventually delete[] it themselves (in the case
00154         of WRITE_THRU)
00155 
00156     All of these data members are immutable, with the exception of the
00157     reference count. This reflects the semantics that an ArrayData
00158     object is a fixed-size block of data; if a higher-level clients
00159     wants to resize(), it does so by creating a new ArrayData of the
00160     desired size, and releasing the old ArrayData. This simplifies the
00161     memory management: within ArrayData, memory is new[]'ed only in
00162     the constructor(s), and delete[]'ed only in the destructor.
00163 
00164     ArrayData provides the basics needed to use STL-style iterator
00165     algorithms.  In particular it offers two pairs of functions to get
00166     half-open iterator ranges:
00167 
00168       - data() and end() for read-only iteration, and
00169       - dataw() and endw() for read-write iteration (where the "w"
00170         means "write" or "writable").
00171 */
00172 template <class T>
00173 class ArrayData
00174 {
00175 private:
00176   ArrayData(const ArrayData&); // not allowed; use clone() instead
00177   ArrayData& operator=(const ArrayData&); // not allowed; use clone() instead
00178 
00179 public:
00180 
00181   // ############################################################
00182   // ##### Constructors
00183   // ############################################################
00184 
00185   //! Default construct an empty (i.e. 0-by-0) array.
00186   inline ArrayData();
00187 
00188   //! Construct with the specified dimensions and InitPolicy.
00189   inline ArrayData(const Dims& dims, const InitPolicy ip = NO_INIT);
00190 
00191   //! Construct with the specified dimensions and InitPolicy and Memory Policy
00192   inline ArrayData(const Dims& dims, const InitPolicy ip, const MemoryPolicy mp, const int device);
00193 
00194   //! Construct with the specified dimensions.
00195   /*! If the passed-in T* array is non-null, copy that data into the
00196       constructed object. */
00197   inline ArrayData(const Dims& dims, const T* aa);
00198 
00199   //! Construct with the specified dimensions, input data, and memory policy
00200   /*! If the passed-in T* array is non-null, copy that data into the
00201       constructed object.  Use the given memory policy */
00202   inline ArrayData(const Dims& dims, const T* aa, const MemoryPolicy mp, const int device, const MemoryPolicy srcmp, const int srcdevice);
00203 
00204   //! Construct with the specified dimensions and storage policy.
00205   /*! If the passed-in T* array is non-null, then if the storage
00206       policy is MAKE_OWN_COPY we make a copy of the data, but if the
00207       storage policy is WRITE_THRU then we "borrow" the data. */
00208   inline ArrayData(const Dims& dims, T* aa, const StoragePolicy s);
00209 
00210   //! Construct with the specified dimensions, storage and memory policies.
00211   /*! If the passed-in T* array is non-null, then if the storage
00212       policy is MAKE_OWN_COPY we make a copy of the data, but if the
00213       storage policy is WRITE_THRU then we "borrow" the data. */
00214   inline ArrayData(const Dims& dims, T* aa, const StoragePolicy s, const MemoryPolicy mp, const int device, const MemoryPolicy srcmp, const int srcdevice);
00215 
00216   //! Return a new'ed copy of *this.
00217   /*! The cloned copy will always be MAKE_OWN_COPY, even if *this is
00218       WRITE_THRU. */
00219   inline ArrayData* clone() const;
00220 
00221   //! Return a new'ed copy of *this using the given memory policy
00222   /*! The cloned copy will always be MAKE_OWN_COPY, even if *this is
00223       WRITE_THRU. */
00224   inline ArrayData* clone(const MemoryPolicy mp, const int device) const;
00225 
00226   //! Release the pointed-to data if our storage policy is MAKE_OWN_COPY.
00227   inline ~ArrayData() throw();
00228 
00229   // ############################################################
00230   // ##### Accessors
00231   // ############################################################
00232 
00233   //! Returns a read-only pointer to the data array.
00234   /*! With end(), forms an STL-style half-open const_iterator range. */
00235   inline const T* data() const throw();
00236 
00237   //! Returns a read-only pointer to one-past-the-end of the data array.
00238   /*! With data(), forms an STL-style half-open const_iterator range. */
00239   inline const T* end() const throw();
00240 
00241   //! Returns a read-write pointer to the data array (the "w" means "write").
00242   /*! With endw(), forms an STL-style half-open iterator range. */
00243   inline T* dataw() throw();
00244 
00245   //! Returns a read-write pointer to one-past-the-end of the data array.
00246   /*! With dataw(), forms an STL-style half-open iterator range. */
00247   inline T* endw() throw();
00248 
00249   //! Returns the dimensions (i.e. width, height) of the 2-D data array.
00250   inline const Dims& dims() const throw();
00251 
00252   //! Returns the width of the data array (i.e. the number of columns).
00253   inline int w() const throw();
00254 
00255   //! Returns the height of the data array (i.e. the number of rows).
00256   inline int h() const throw();
00257 
00258   // ############################################################
00259   // ##### Reference count manipulation
00260   // ############################################################
00261 
00262   //! Increment the reference count.
00263   inline void acquire() throw();
00264 
00265   //! Decrement the reference count and delete self if the count goes to zero.
00266   inline void release() throw();
00267 
00268   //! Query whether this object is shared (i.e. ref count > 1).
00269   inline bool isShared() const throw();
00270 
00271   //! For debugging/testing only.
00272   /*! Returns the current reference count. */
00273   inline int refCount() const throw();
00274 
00275   //! Return memory policy of underlying array data
00276   inline MemoryPolicy getMemoryPolicy() const;
00277 
00278   //! Return memory policy of underlying array data
00279   inline int getMemoryDevice() const;
00280 
00281 
00282 private:
00283   rutz::atomic_int_t itsRefCount;
00284   MemoryPolicy const itsMemoryPolicy;  // Type of memory that is being used (global,texture,host)
00285   StoragePolicy const itsStoragePolicy;
00286   int const itsDevice;          // CUDA device (or host) where memory is located
00287 
00288   Dims const itsDims;           // width+height of data array
00289   T* const itsData;             // data array
00290 };
00291 
00292 
00293 //! This class provides ref-counting and copy-on-write for ArrayData's.
00294 /*! NOTE: Most clients will not need to use ArrayHandle<T> directly,
00295     but can rather use Image<T>, which wraps and expands the
00296     ArrayHandle interface. Nevertheless, these notes may be of
00297     interest because the ref-counting and copy-on-write semantics that
00298     ArrayHandle<T> offers are transferred through to Image<T>.
00299 
00300     As long as clients access ArrayData<T> through an ArrayHandle<T>,
00301     the proper copy-on-write semantics are guaranteed. This is by
00302     virtue of the fact that the only way to extract a non-const
00303     ArrayData<T>& from an ArrayHandle<T> is to call uniq(), which in
00304     turn checks to see if the ArrayData is shared (i.e. ref count >
00305     1). If it is shared, then that ArrayData is clone()'d before
00306     returning a reference to it.
00307 
00308     The only caveat: you should not store non-const references to an
00309     ArrayData or to the elements of an ArrayData object for "long"
00310     periods of time. In this case, "long" means "longer than you are
00311     sure you have a unique reference", which in practice means "you
00312     can keep such references up until a new copy of the ArrayHandle<T>
00313     is made". This goes along with sensible coding practices anyway; a
00314     typical usage pattern would be:
00315 
00316       -# you have an ArrayHandle<T> (or an Image<T>, which holds an
00317          ArrayHandle<T>) that you want to modify
00318       -# get a pair of iterator's for that object so that you can
00319          perform your series of write operations
00320       -# don't use those iterators anymore, and then you can safely
00321          make copies of the freshly-modified ArrayHandle<T> or
00322          Image<T> object (for example to return a copy of it as the
00323          return value from a function)
00324 */
00325 template<class T>
00326 class ArrayHandle
00327 {
00328 public:
00329   //! Default construct with an empty array (i.e. 0-by-0).
00330   inline ArrayHandle();
00331 
00332   //! Construct with a new ArrayData, which the ArrayHandle now owns.
00333   inline explicit ArrayHandle(const ArrayData<T>* p) throw();
00334   
00335   //! Construct with a new ArrayData, which the ArrayHandle now owns.
00336   inline explicit ArrayHandle(const ArrayData<T>* p, const MemoryPolicy mp, const int dev) throw();
00337 
00338   //! Copy construct; no deep-copy is incurred, just bumps the ref-count.
00339   inline ArrayHandle(const ArrayHandle& r) throw();
00340 
00341   //! Destruct; delete's the ArrayData<T> if its ref count goes to zero.
00342   inline ~ArrayHandle() throw();
00343 
00344   //! Swap contents with another ArrayHandle.
00345   inline void swap(ArrayHandle<T>& other) throw();
00346 
00347   //! Assignment; no deep-copy is incurred, just bumps the ref-count.
00348   inline ArrayHandle& operator=(const ArrayHandle& r) throw();
00349 
00350   //! Get a read-only reference to the ArrayData object.
00351   /*! This is a "cheap" operation, since the ArrayData will never be
00352       copied in this operation. */
00353   inline const ArrayData<T>& get() const throw();
00354 
00355   //! Get a unique read-write reference to the ArrayData object.
00356   /*! This is a potentially "expensive" operation, since in order to
00357       get a unique ArrayData object, the current one may have to be
00358       clone()'d if it is shared (i.e. ref-count > 1). */
00359   inline ArrayData<T>& uniq(const MemoryPolicy mp, const int dev);
00360 
00361   //! Get a unique read-write reference to the ArrayData object.
00362   /*! This is a potentially "expensive" operation, since in order to
00363       get a unique ArrayData object, the current one may have to be
00364       clone()'d if it is shared (i.e. ref-count > 1). */
00365   inline ArrayData<T>& uniq();
00366 
00367   //! See if the ArrayData object is shared (i.e. ref-count > 1).
00368   inline bool isShared() const throw();
00369 
00370   //! For testing/debugging only.
00371   /*! See if we are pointing to the same ArrayData<T> as is the other
00372       ArrayHandle<T>. */
00373   inline bool hasSameData(const ArrayHandle<T>& b) const throw();
00374 
00375   //! For testing/debugging only.
00376   /*! Returns the current reference count of the our ArrayData<T>. */
00377   inline int refCount() const throw();
00378 
00379 private:
00380   ArrayData<T>* px;     // contained pointer
00381 };
00382 
00383 
00384 
00385 // ######################################################################
00386 // ######################################################################
00387 // INLINE FUNCTIONS for ArrayData:
00388 // ######################################################################
00389 // ######################################################################
00390 
00391 //! This is a helper template struct for ArrayData's constructors.
00392 /*! It exposes functions for initializing raw memory in different
00393     ways. These functions can then be specialized for builtin or
00394     trivial types (i.e., types for which TypeTraits<T>::isTrivial is
00395     true) for maximum efficiency. We get this specialization by having
00396     an extra bool isTrivial template parameter for ArrayHelper, which
00397     allows us to select at compile-time based on the complexity of
00398     T. This is much better than using a run-time "if" statement in the
00399     constructors, since that incurs both a time cost (to evaluate an
00400     "if" statement) and a code space cost (since we're then including
00401     code that won't be used). */
00402 template <class T, bool isTrivial = TypeTraits<T>::isTrivial>
00403 struct ArrayHelper
00404 {
00405   //! Construct \a n copies of \a val at \a space using placement new.
00406   /*! For general types, the minimal initialization that we can do is
00407       to zero_initialize() (i.e., unlike for builtin or trivial types,
00408       we can't just leave the memory sitting as it is,
00409       uninitialized). */
00410   static void minimal_initialize(T* trg, int n)
00411   {
00412     zero_initialize(trg, n);
00413   }
00414 
00415   static void minimal_initialize(T* trg, int n, const MemoryPolicy mp, const int dev)
00416   {
00417     zero_initialize(trg, n, mp, dev);
00418   }
00419 
00420   //! Initialize the memory to T's default or zero value.
00421   /*! For general types, the best way to do this is to make one
00422       default T object, and then copy construct each element of the
00423       array from that object using placement new. */
00424   static inline void zero_initialize(T* trg, int n)
00425   {
00426     T zero = T();
00427     T* cur = trg;
00428     try
00429       {
00430         for (; n > 0; --n, ++cur)
00431           new (cur) T(zero); // placement new
00432       }
00433     // if a constructor call throws, we have to clean up manually:
00434     catch (...)
00435       {
00436         while (cur != trg) (cur--)->~T(); // explicit destructor call
00437         invt_deallocate(trg);
00438         throw; // rethrow the exception
00439       }
00440   }
00441 
00442   static void zero_initialize(T* trg, int n, const MemoryPolicy mp, const int dev)
00443   {
00444 #ifdef INVT_USE_CUDA
00445     T* tmp;
00446     switch(mp)
00447     {
00448     case GLOBAL_DEVICE_MEMORY:
00449     case TEXTURE_DEVICE_MEMORY:
00450       // Is there a better way to do this?
00451       tmp = new T[n];
00452       CudaDevices::memcpyHostToDevice(trg,tmp,n*sizeof(T),dev);
00453       delete tmp;
00454       break;    
00455     case HOST_MEMORY:
00456       zero_initialize(trg,n);
00457       break;
00458     }
00459 #else
00460     // Optimization, just assume the memory policy
00461     zero_initialize(trg,n);
00462 #endif
00463     
00464   }
00465 
00466   //! Initialize the memory by copying elements from the \a src array.
00467   /*! For general types, we just copy construct each element in the
00468       target array from the corresponding element in the \a src array,
00469       using placement new. */
00470   static inline void copy_initialize(T* trg, int n, const T*src)
00471   {
00472         T* cur = trg;
00473         try
00474         {
00475           for (; n > 0; --n, ++cur)
00476             new (cur) T(*src++); // placement new
00477         }
00478         // if a constructor call throws, we have to clean up manually:
00479         catch (...)
00480         {
00481           while (cur != trg) (cur--)->~T(); // explicit destructor call
00482           invt_deallocate(trg);
00483           throw; // rethrow the exception
00484         }
00485   }
00486 
00487   // THIS IS AN UNSAFE DESIGN!  Complex types that allocate/deallocate resources in their constructors/destructors
00488   // are not properly handled when sent/received from CUDA devices under this framework.
00489   // The reason that non-primitive types are supported for CUDA right now, is because PixRGB and its ilk 
00490   // are very useful, non-primitive type that will work with CUDA.
00491   // Maybe we should add a complext template or some other intelligence to demarcate the line between simple and complex classes
00492   // to fix this problem.  -- DFP 082009
00493   static void copy_initialize(T* trg, int n, const T*src, const MemoryPolicy trgmp, const int trgdev, 
00494                               const MemoryPolicy srcmp, const int srcdev)
00495   {
00496 #ifdef INVT_USE_CUDA
00497     T *tmp;
00498     switch(srcmp)
00499     {
00500     case GLOBAL_DEVICE_MEMORY:
00501     case TEXTURE_DEVICE_MEMORY:
00502       switch(trgmp)
00503       {
00504       case GLOBAL_DEVICE_MEMORY:
00505       case TEXTURE_DEVICE_MEMORY:
00506         // These types *SHOULD* be semi-trivial since they are going to the CUDA device
00507         CudaDevices::memcpyDeviceToDevice(trg,src,n*sizeof(T),trgdev,srcdev);
00508         break;
00509       case HOST_MEMORY:
00510         // Very inefficient, have to copy whole block from device to host, and then
00511         // call the constructor for each item in array using a new block of mem
00512         tmp = new T[n];
00513         CudaDevices::memcpyDeviceToHost(tmp,src,n*sizeof(T),srcdev);
00514         copy_initialize(trg,n,tmp);
00515         delete tmp;
00516         break;
00517       }
00518 
00519       break;    
00520     case HOST_MEMORY:
00521       switch(trgmp)
00522       {
00523       case GLOBAL_DEVICE_MEMORY:
00524       case TEXTURE_DEVICE_MEMORY:
00525         CudaDevices::memcpyHostToDevice(trg,src,n*sizeof(T),trgdev);
00526         break;
00527       case HOST_MEMORY:
00528         copy_initialize(trg,n,src);
00529         break;
00530       }
00531       break;
00532     }
00533 #else
00534     // Optimization, just assume the memory policy
00535     copy_initialize(trg,n,src);
00536 #endif
00537   }
00538 
00539 
00540 
00541   //! Call destructors on the \a n objects stored in \a space.
00542   static inline void destruct(T* trg, int n)
00543   {
00544     while (--n >= 0)
00545       (trg+n)->~T(); // explicit destructor call
00546   }
00547   
00548   static void destruct(T* trg, int n, const MemoryPolicy mp, const int dev)
00549   {
00550 #ifdef INVT_USE_CUDA
00551     switch(mp)
00552     {
00553     case GLOBAL_DEVICE_MEMORY:
00554     case TEXTURE_DEVICE_MEMORY:
00555       // What can we do here?
00556       break;
00557     case HOST_MEMORY:
00558       destruct(trg,n);
00559       break;      
00560     }
00561 #else
00562     // Optimization, just assume the memory policy
00563     destruct(trg,n);
00564 #endif
00565   } 
00566 
00567 };
00568 
00569 //! Specialization of ArrayHelper for builtin/trivial types.
00570 /*! We can do things much faster with these kinds of types, using
00571     e.g. memset() and memcpy(), and we don't have to do default
00572     initialization at all. */
00573 template <class T>
00574 struct ArrayHelper<T, true>
00575 {
00576   //! For trivial types, we don't have to do anything here.
00577   static void minimal_initialize(T* /*trg*/, int /*n*/) {}
00578 
00579   //! For trivial types, we don't have to do anything here.
00580   static void minimal_initialize(T* /*trg*/, int /*n*/, const MemoryPolicy /*mp*/, const int /*dev*/) {}
00581 
00582   //! For trivial types, we just memset() all the memory to zero.
00583   static inline void zero_initialize(T* trg, int n)
00584   {
00585     memset(trg, 0, n * sizeof(T));
00586   }
00587 
00588   static void zero_initialize(T* trg, int n, const MemoryPolicy mp, const int device)
00589   {
00590 #ifdef INVT_USE_CUDA
00591     switch(mp)
00592     {
00593     case GLOBAL_DEVICE_MEMORY:
00594     case TEXTURE_DEVICE_MEMORY:
00595       CudaDevices::memset(trg,0,n*sizeof(T),device);
00596       break;    
00597     case HOST_MEMORY:
00598       zero_initialize(trg, n);
00599       break;
00600     }
00601 #else
00602     // Optimization, just assume the memory policy
00603     zero_initialize(trg, n);
00604 #endif
00605   } 
00606 
00607   //! For trivial types, we just memcpy() into the destination.
00608   static inline void copy_initialize(T* space, int n, const T* src)
00609   {
00610     memcpy(space, src, n * sizeof(T));
00611   }
00612 
00613   static void copy_initialize(T* trg, int n, const T*src, const MemoryPolicy trgmp, const int trgdev, 
00614                               const MemoryPolicy srcmp, const int srcdev)
00615   {
00616 #ifdef INVT_USE_CUDA
00617     switch(srcmp)
00618     {
00619     case GLOBAL_DEVICE_MEMORY:
00620     case TEXTURE_DEVICE_MEMORY:
00621       switch(trgmp)
00622       {
00623       case GLOBAL_DEVICE_MEMORY:
00624       case TEXTURE_DEVICE_MEMORY:
00625         CudaDevices::memcpyDeviceToDevice(trg,src,n*sizeof(T),trgdev,srcdev);
00626         break;
00627       case HOST_MEMORY:
00628         CudaDevices::memcpyDeviceToHost(trg,src,n*sizeof(T),srcdev);
00629         break;
00630       }
00631       break;    
00632     case HOST_MEMORY:
00633       switch(trgmp)
00634       {
00635       case GLOBAL_DEVICE_MEMORY:
00636       case TEXTURE_DEVICE_MEMORY:
00637         CudaDevices::memcpyHostToDevice(trg,src,n*sizeof(T),trgdev);
00638         break;
00639       case HOST_MEMORY:
00640         copy_initialize(trg, n, src);
00641         break;
00642       }
00643       break;
00644     }
00645 #else
00646     // Optimization, just assume the memory policy
00647     copy_initialize(trg, n, src);
00648 #endif
00649   }
00650 
00651   //! For trivial types, no destruction is needed.
00652   static void destruct(T* /*space*/, int /*n*/) {}
00653 
00654   //! For trivial types, no destruction is needed.
00655   static void destruct(T* /*space*/, int /*n*/, const MemoryPolicy /*mp*/, const int /*dev*/) {}
00656 
00657 };
00658 
00659 // ######################################################################
00660 template <class T> inline
00661 ArrayData<T>::ArrayData() :
00662   itsRefCount(),
00663   itsMemoryPolicy(HOST_MEMORY),
00664   itsStoragePolicy(MAKE_OWN_COPY),
00665   itsDevice(CUDA_HOST_DEVICE_NUM),
00666   itsDims(0, 0),
00667   itsData(static_cast<T*>(wrap_invt_allocate(1,itsMemoryPolicy,itsDevice))) // just ask for one byte
00668 {
00669   itsRefCount.atomic_set(0);
00670 }
00671 
00672 // ######################################################################
00673 template <class T> inline
00674 //inline ArrayData(const Dims& dims, const InitPolicy ip = NO_INIT, const MemoryPolicy mp = HOST_MEMORY, const int device = CUDA_HOST_DEVICE_NUM);
00675 ArrayData<T>::ArrayData(const Dims& d, const InitPolicy ip) :
00676   itsRefCount(),
00677   itsMemoryPolicy(HOST_MEMORY),
00678   itsStoragePolicy(MAKE_OWN_COPY),
00679   itsDevice(CUDA_HOST_DEVICE_NUM),
00680   itsDims(d),
00681   itsData(static_cast<T*>(wrap_invt_allocate(itsDims.sz() * sizeof(T),itsMemoryPolicy,itsDevice)))
00682 {
00683   if (ip == ZEROS)
00684     ArrayHelper<T>::zero_initialize(itsData, itsDims.sz(), itsMemoryPolicy, itsDevice);
00685   else
00686     ArrayHelper<T>::minimal_initialize(itsData, itsDims.sz(), itsMemoryPolicy, itsDevice);
00687   itsRefCount.atomic_set(0);
00688 }
00689 
00690 
00691 // ######################################################################
00692 template <class T> inline
00693 //inline ArrayData(const Dims& dims, const InitPolicy ip = NO_INIT, const MemoryPolicy mp = HOST_MEMORY, const int device = CUDA_HOST_DEVICE_NUM);
00694 ArrayData<T>::ArrayData(const Dims& d, const InitPolicy ip, const MemoryPolicy mp, const int device) :
00695   itsRefCount(),
00696   itsMemoryPolicy(mp),
00697   itsStoragePolicy(MAKE_OWN_COPY),
00698   itsDevice(device),
00699   itsDims(d),
00700   itsData(static_cast<T*>(wrap_invt_allocate(itsDims.sz() * sizeof(T),itsMemoryPolicy,itsDevice)))
00701 {
00702   if (ip == ZEROS)
00703     ArrayHelper<T>::zero_initialize(itsData, itsDims.sz(), itsMemoryPolicy, itsDevice);
00704   else
00705     ArrayHelper<T>::minimal_initialize(itsData, itsDims.sz(), itsMemoryPolicy, itsDevice);
00706   itsRefCount.atomic_set(0);
00707 }
00708 
00709 // ######################################################################
00710 template <class T> inline
00711 ArrayData<T>::ArrayData(const Dims& d, const T* aa) :
00712   itsRefCount(),
00713   itsMemoryPolicy(HOST_MEMORY),
00714   itsStoragePolicy(MAKE_OWN_COPY),
00715   itsDevice(CUDA_HOST_DEVICE_NUM),
00716   itsDims(d),
00717   itsData(static_cast<T*>(wrap_invt_allocate(itsDims.sz() * sizeof(T),itsMemoryPolicy,itsDevice)))
00718 {
00719   ArrayHelper<T>::copy_initialize(itsData, itsDims.sz(), aa);
00720 
00721   itsRefCount.atomic_set(0);
00722 }
00723 
00724 // ######################################################################
00725 template <class T> inline
00726 ArrayData<T>::ArrayData(const Dims& d, const T* aa, const MemoryPolicy mp, const int device, const MemoryPolicy srcmp, const int srcdevice) :
00727   itsRefCount(),
00728   itsMemoryPolicy(mp),
00729   itsStoragePolicy(MAKE_OWN_COPY),
00730   itsDevice(device),
00731   itsDims(d),
00732   itsData(static_cast<T*>(wrap_invt_allocate(itsDims.sz() * sizeof(T),itsMemoryPolicy,itsDevice)))
00733 {
00734   ArrayHelper<T>::copy_initialize(itsData, itsDims.sz(), aa, itsMemoryPolicy, itsDevice, srcmp, srcdevice);
00735 
00736   itsRefCount.atomic_set(0);
00737 }
00738 
00739 // ######################################################################
00740 template <class T> inline
00741 ArrayData<T>::ArrayData(const Dims& d, T* aa, const StoragePolicy s) :
00742   itsRefCount(),
00743   itsMemoryPolicy(HOST_MEMORY),
00744   itsStoragePolicy(s),
00745   itsDevice(CUDA_HOST_DEVICE_NUM),
00746   itsDims(d),
00747   itsData(s == MAKE_OWN_COPY
00748           ? static_cast<T*>(wrap_invt_allocate(itsDims.sz() * sizeof(T),itsMemoryPolicy,itsDevice))
00749           : aa)
00750 {
00751   if (s == MAKE_OWN_COPY)
00752     {
00753       if (itsDims.sz() != 0 && aa != 0)
00754         ArrayHelper<T>::copy_initialize(itsData, itsDims.sz(), aa);
00755       else
00756         ArrayHelper<T>::minimal_initialize(itsData, itsDims.sz());
00757     }
00758 
00759   itsRefCount.atomic_set(0);
00760 }
00761 
00762 
00763 // ######################################################################
00764 template <class T> inline
00765 ArrayData<T>::ArrayData(const Dims& d, T* aa, const StoragePolicy s, const MemoryPolicy mp, const int device, const MemoryPolicy srcmp, const int srcdevice) : 
00766   itsRefCount(),
00767   itsMemoryPolicy(mp),
00768   itsStoragePolicy(s),
00769   itsDevice(device),
00770   itsDims(d),
00771   itsData((s == MAKE_OWN_COPY)
00772           ? static_cast<T*>(wrap_invt_allocate(itsDims.sz() * sizeof(T),itsMemoryPolicy,itsDevice))
00773           : aa)
00774 {
00775   if (s == MAKE_OWN_COPY)
00776     {
00777       if (itsDims.sz() != 0 && aa != 0)
00778         ArrayHelper<T>::copy_initialize(itsData, itsDims.sz(), aa, itsMemoryPolicy, itsDevice, srcmp, srcdevice);
00779       else
00780         ArrayHelper<T>::minimal_initialize(itsData, itsDims.sz(), itsMemoryPolicy, itsDevice);
00781     }
00782   else
00783     {
00784       if(itsMemoryPolicy!=srcmp || itsDevice!=srcdevice)
00785         LFATAL("WriteThru for ArrayData must be done using the same memory policy on the same device");
00786     }
00787 
00788   itsRefCount.atomic_set(0);
00789 }
00790 
00791 // ######################################################################
00792 template <class T> inline
00793 ArrayData<T>* ArrayData<T>::clone() const
00794 {
00795   // When the new memory policy is not specified, we should either default to keeping it 
00796   // in the same location, or default to the host. Currently, all memcpy's have to go 
00797   // from dev->host->dev even if it is to/from the same device so it seems like 
00798   // defaulting to the host makes sense for now
00799   return new ArrayData(itsDims, itsData, HOST_MEMORY, CUDA_HOST_DEVICE_NUM, itsMemoryPolicy, itsDevice);
00800 }
00801 
00802 
00803 // ######################################################################
00804 template <class T> inline
00805 ArrayData<T>* ArrayData<T>::clone(const MemoryPolicy mp, const int dev) const
00806 {
00807   return new ArrayData(itsDims, itsData, mp, dev, itsMemoryPolicy, itsDevice);
00808 }
00809 
00810 // ######################################################################
00811 template <class T> inline
00812 ArrayData<T>::~ArrayData() throw()
00813 {
00814   if (itsStoragePolicy == MAKE_OWN_COPY)
00815     {
00816       ArrayHelper<T>::destruct(itsData, itsDims.sz());
00817       wrap_invt_deallocate(itsData,itsMemoryPolicy,itsDevice,itsDims.sz()*sizeof(T));
00818     }
00819 }
00820 
00821 // ######################################################################
00822 template <class T> inline
00823 const T* ArrayData<T>::data() const throw()
00824 { return itsData; }
00825 
00826 // ######################################################################
00827 template <class T> inline
00828 const T* ArrayData<T>::end() const throw()
00829 { return itsData + itsDims.sz(); }
00830 
00831 // ######################################################################
00832 template <class T> inline
00833 T* ArrayData<T>::dataw() throw()
00834 { return itsData; }
00835 
00836 // ######################################################################
00837 template <class T> inline
00838 T* ArrayData<T>::endw() throw()
00839 { return itsData + itsDims.sz(); }
00840 
00841 // ######################################################################
00842 template <class T> inline
00843 const Dims& ArrayData<T>::dims() const throw()
00844 { return itsDims; }
00845 
00846 // ######################################################################
00847 template <class T> inline
00848 int ArrayData<T>::w() const throw()
00849 { return itsDims.w(); }
00850 
00851 // ######################################################################
00852 template <class T> inline
00853 int ArrayData<T>::h() const throw()
00854 { return itsDims.h(); }
00855 
00856 // ######################################################################
00857 template <class T> inline
00858 void ArrayData<T>::acquire() throw()
00859 {
00860   itsRefCount.atomic_incr();
00861 
00862   check_acquisition(itsStoragePolicy, itsRefCount.atomic_get());
00863 }
00864 
00865 // ######################################################################
00866 template <class T> inline
00867 void ArrayData<T>::release() throw()
00868 {
00869   if ( itsRefCount.atomic_decr_test_zero() ) delete this;
00870 }
00871 
00872 // ######################################################################
00873 template <class T> inline
00874 bool ArrayData<T>::isShared() const throw()
00875 {
00876   return (itsRefCount.atomic_get() > 1);
00877 }
00878 
00879 // ######################################################################
00880 template <class T> inline
00881 int ArrayData<T>::refCount() const throw()
00882 {
00883   return itsRefCount.atomic_get();
00884 }
00885 
00886 // ######################################################################
00887 template <class T> inline
00888 MemoryPolicy ArrayData<T>::getMemoryPolicy() const
00889 {
00890   return itsMemoryPolicy;
00891 }
00892 
00893 // ######################################################################
00894 template <class T> inline
00895 int ArrayData<T>::getMemoryDevice() const
00896 {
00897   return itsDevice;
00898 }
00899 
00900 
00901 // ######################################################################
00902 // ######################################################################
00903 // INLINE FUNCTIONS for ArrayHandle:
00904 // ######################################################################
00905 // ######################################################################
00906 
00907 // ######################################################################
00908 template <class T> inline
00909 ArrayHandle<T>::ArrayHandle() : px(new ArrayData<T>)
00910 {
00911   px->acquire();
00912 }
00913 
00914 
00915 // ######################################################################
00916 template <class T> inline
00917 ArrayHandle<T>::ArrayHandle(const ArrayData<T>* p) throw() :
00918   // this cast is OK because we maintain const-correctness through
00919   // copy-on-write
00920   px(const_cast<ArrayData<T>*>(p))
00921 {
00922   px->acquire();
00923 }
00924 
00925 // ######################################################################
00926 template <class T> inline
00927 ArrayHandle<T>::ArrayHandle(const ArrayData<T>* p, const MemoryPolicy mp, const int dev) throw() :
00928   // this cast is OK because we maintain const-correctness through
00929   // copy-on-write
00930   px(const_cast<ArrayData<T>*>(p->clone(mp,dev)))
00931 {
00932   px->acquire();
00933 }
00934 
00935 
00936 // ######################################################################
00937 template <class T> inline
00938 ArrayHandle<T>::ArrayHandle(const ArrayHandle& r) throw() :
00939   px(r.px)
00940 {
00941   px->acquire();
00942 }
00943 
00944 // ######################################################################
00945 template <class T> inline
00946 ArrayHandle<T>::~ArrayHandle() throw()
00947 {
00948   px->release();
00949 }
00950 
00951 // ######################################################################
00952 template <class T> inline
00953 void ArrayHandle<T>::swap(ArrayHandle<T>& other) throw()
00954 {
00955   ArrayData<T>* other_px = other.px;
00956   other.px = this->px;
00957   this->px = other_px;
00958 }
00959 
00960 // ######################################################################
00961 template <class T> inline
00962 ArrayHandle<T>& ArrayHandle<T>::operator=(const ArrayHandle& r) throw()
00963 {
00964   ArrayHandle tmp(r); this->swap(tmp); return *this;
00965 }
00966 
00967 // ######################################################################
00968 template <class T> inline
00969 const ArrayData<T>& ArrayHandle<T>::get() const throw()
00970 { return *px; }
00971 
00972 // ######################################################################
00973 template <class T> inline
00974 ArrayData<T>& ArrayHandle<T>::uniq(const MemoryPolicy mp, const int dev)
00975 {
00976   if (px->isShared())
00977     {
00978       ArrayHandle copy(px->clone(mp,dev));
00979       this->swap(copy);
00980     }
00981 
00982   return *px;
00983 }
00984 
00985 // ######################################################################
00986 template <class T> inline
00987 ArrayData<T>& ArrayHandle<T>::uniq()
00988 {
00989   if (px->isShared())
00990     {
00991       ArrayHandle copy(px->clone());
00992       this->swap(copy);
00993     }
00994 
00995   return *px;
00996 }
00997 
00998 // ######################################################################
00999 template <class T> inline
01000 bool ArrayHandle<T>::isShared() const throw()
01001 { return px->isShared(); }
01002 
01003 // ######################################################################
01004 template <class T> inline
01005 bool ArrayHandle<T>::hasSameData(const ArrayHandle<T>& b) const throw()
01006 { return px==b.px; }
01007 
01008 // ######################################################################
01009 template <class T> inline
01010 int ArrayHandle<T>::refCount() const throw()
01011 { return px->refCount(); }
01012 
01013 // ######################################################################
01014 /* So things look consistent in everyone's emacs... */
01015 /* Local Variables: */
01016 /* indent-tabs-mode: nil */
01017 /* End: */
01018 
01019 #endif // !ARRAY_IMPL_H_DEFINED

Generated on Sun Nov 22 13:42:24 2009 for iLab Neuromorphic Vision Toolkit by  doxygen 1.4.4