Blender V2.61 - r43446

Cache.hpp

Go to the documentation of this file.
00001 /*
00002  * Cache.hpp
00003  *
00004  *  Created on: Feb 24, 2009
00005  *      Author: benoit tbolsee
00006  */
00007 
00008 #ifndef CACHE_HPP_
00009 #define CACHE_HPP_
00010 
00011 #include <map>
00012 
00013 namespace iTaSC {
00014 
00015 #define CACHE_LOOKUP_TABLE_SIZE             128
00016 #define CACHE_DEFAULT_BUFFER_SIZE           32768
00017 #define CACHE_CHANNEL_EXTEND_SIZE           10
00018 #define CACHE_MAX_ITEM_SIZE                 0x3FFF0
00019 
00020 /* macro to get the alignement gap after an item header */
00021 #define CACHE_ITEM_GAPB(item)               (unsigned int)(((size_t)item+sizeof(CacheItem))&(sizeof(void*)-1))
00022 /* macro to get item data position, item=CacheItem pointer */
00023 #define CACHE_ITEM_DATA_POINTER(item)       (void*)((unsigned char*)item+sizeof(CacheItem)+CACHE_ITEM_GAPB(item))
00024 /* macro to get item size in 32bit words from item address and length, item=CacheItem pointer */
00025 #define CACHE_ITEM_SIZEW(item,length)       (unsigned int)((sizeof(CacheItem)+CACHE_ITEM_GAPB(item)+(((length)+3)&~0x3))>>2)
00026 /* macto to move from one item to the next, item=CacheItem pointer, updated by the macro */
00027 #define CACHE_NEXT_ITEM(item)               ((item)+(item)->m_sizeW)
00028 #define CACHE_BLOCK_ITEM_ADDR(chan,buf,block)   (&(buf)->m_firstItem+(((unsigned int)(block)<<chan->m_positionToBlockShiftW)+(buf)->lookup[block].m_offsetW))
00029 #define CACHE_ITEM_ADDR(buf,pos)            (&(buf)->m_firstItem+(pos))
00030 #define CACHE_ITEM_POSITIONW(buf,item)      (unsigned int)(item-&buf->m_firstItem)
00031 
00032 typedef unsigned int CacheTS;
00033 
00034 struct Timestamp 
00035 {
00036     double realTimestamp;
00037     double realTimestep;
00038     CacheTS cacheTimestamp;
00039     unsigned int numstep:8;
00040     unsigned int substep:1;
00041     unsigned int reiterate:1;
00042     unsigned int cache:1;
00043     unsigned int update:1;
00044     unsigned int interpolate:1;
00045     unsigned int dummy:19;
00046 
00047     Timestamp() { memset(this, 0, sizeof(Timestamp)); }
00048 };
00049 
00050 /* utility function to return second timestamp to millisecond */
00051 inline void setCacheTimestamp(Timestamp& timestamp)
00052 {
00053     if (timestamp.realTimestamp < 0.0 || timestamp.realTimestamp > 4294967.295)
00054         timestamp.cacheTimestamp = 0;
00055     else
00056         timestamp.cacheTimestamp = (CacheTS)(timestamp.realTimestamp*1000.0+0.5);
00057 }
00058 
00059 
00060 /*
00061 class Cache:
00062 Top level class, only one instance of this class should exists.
00063 A device (=constraint, object) uses this class to create a cache entry for its data.
00064 A cache entry is divided into cache channels, each providing a separate buffer for cache items.
00065 The cache channels must be declared by the devices before they can be used.
00066 The device must specify the largest cache item (limited to 256Kb) so that the cache
00067 buffer can be organized optimally.
00068 Cache channels are identified by small number (starting from 0) allocated by the cache system.
00069 Cache items are inserted into cache channels ordered by timestamp. Writing is always done
00070 at the end of the cache buffer: writing an item automatically clears all items with 
00071 higher timestamp.
00072 A cache item is an array of bytes provided by the device; the format of the cache item is left 
00073 to the device. 
00074 The device can retrieve a cache item associated with a certain timestamp. The cache system
00075 returns a pointer that points directly in the cache buffer to avoid unnecessary copy. 
00076 The pointer is guaranteed to be pointer aligned so that direct mapping to C structure is possible 
00077 (=32 bit aligned on 32 systems and 64 bit aligned on 64 bits system).
00078 
00079 Timestamp = rounded time in millisecond.
00080 */
00081 
00082 struct CacheEntry;
00083 struct CacheBuffer;
00084 struct CacheItem;
00085 struct CacheChannel;
00086 
00087 class Cache 
00088 {
00089 private:
00090     /* map between device and cache entry.
00091        Dynamically updated when more devices create cache channels */
00092     typedef std::map<const void *, struct CacheEntry*> CacheMap;
00093     CacheMap  m_cache;
00094     const CacheItem *getCurrentCacheItemInternal(const void *device, int channel, CacheTS timestamp);
00095    
00096 public:
00097     Cache();
00098     ~Cache();
00099     /* add a cache channel, maxItemSize must be < 256k.
00100        name : channel name, truncated at 31 characters
00101        msxItemSize : maximum size of item in bytes, items of larger size will be rejected
00102        return value >= 0: channel id, -1: error */
00103     int addChannel(const void *device, const char *name, unsigned int maxItemSize);
00104 
00105     /* delete a cache channel (and all associated buffers and items) */
00106     int deleteChannel(const void *device, int channel);
00107     /* delete all channels of a device and remove the device from the map */
00108     int deleteDevice(const void *device);
00109     /* removes all cache items, leaving the special item at timestamp=0. 
00110        if device=NULL, apply to all devices. */
00111     void clearCacheFrom(const void *device, CacheTS timestamp);
00112 
00113     /* add a new cache item
00114        channel: the cache channel (as returned by AddChannel
00115        data, length: the cache item and length in bytes
00116                      If data is NULL, the memory is allocated in the cache but not writen
00117        return: error: NULL, success: pointer to item in cache */
00118     void *addCacheItem(const void *device, int channel, CacheTS timestamp, void *data, unsigned int length);
00119 
00120     /* specialized function to add a vector of double in the cache
00121        It will first check if a vector exist already in the cache for the same timestamp
00122        and compared the cached vector with the new values. 
00123        If all values are within threshold, the vector is updated but the cache is not deleted
00124        for the future timestamps. */
00125     double *addCacheVectorIfDifferent(const void *device, int channel, CacheTS timestamp, double *data, unsigned int length, double threshold);
00126 
00127     /* returns the cache item with timestamp that is just before the given timestamp.
00128        returns the data pointer or NULL if there is no cache item before timestamp.
00129        On return, timestamp is updated with the actual timestamp of the item being returned.
00130        Note that the length of the item is not returned, it is up to the device to organize
00131        the data so that length can be retrieved from the data if needed.
00132        Device can NULL, it will then just look the first channel available, useful to 
00133        test the status of the cache. */
00134     const void *getPreviousCacheItem(const void *device, int channel, CacheTS *timestamp);
00135 
00136     /* returns the cache item with the timestamp that is exactly equal to the given timestamp
00137        If there is no cache item for this timestamp, returns NULL.*/
00138     const void *getCurrentCacheItem(const void *device, int channel, CacheTS timestamp);
00139 
00140 };
00141 
00142 /* the following structures are not internal use only, they should not be used directly */
00143 
00144 struct CacheEntry 
00145 {
00146     CacheChannel *m_channelArray;       // array of channels, automatically resized if more channels are created
00147     unsigned int m_count;               // number of channel in channelArray
00148     CacheEntry() : m_channelArray(NULL), m_count(0) {}
00149     ~CacheEntry();
00150 };
00151 
00152 struct CacheChannel
00153 {
00154     CacheItem* initItem;                // item corresponding to timestamp=0
00155     struct CacheBuffer *m_firstBuffer;  // first buffer of list
00156     struct CacheBuffer *m_lastBuffer;       // last buffer of list to which an item was written
00157     char m_name[32];                        // channel name
00158     unsigned char m_busy;                   // =0 if channel is free, !=0 when channel is in use
00159     unsigned char m_positionToBlockShiftW;  // number of bits to shift a position in word to get the block number
00160     unsigned short m_positionToOffsetMaskW;   // bit mask to apply on a position in word to get offset in a block
00161     unsigned int m_maxItemSizeB;            // maximum item size in bytes
00162     unsigned int m_bufferSizeW;         // size of item buffer in word to allocate when a new buffer must be created
00163     unsigned int m_blockSizeW;          // block size in words of the lookup table
00164     unsigned int m_lastTimestamp;           // timestamp of the last item that was written
00165     unsigned int m_lastItemPositionW;       // position in words in lastBuffer of the last item written
00166     void clear();
00167     CacheBuffer* allocBuffer();
00168     CacheItem* findItemOrLater(unsigned int timestamp, CacheBuffer **rBuffer);
00169     CacheItem* findItemEarlier(unsigned int timestamp, CacheBuffer **rBuffer);
00170     // Internal function: finds an item in a buffer that is < timeOffset
00171     // timeOffset must be a valid offset for the buffer and the buffer must not be empty
00172     // on return highBlock contains the block with items above or equal to timeOffset
00173     CacheItem *_findBlock(CacheBuffer *buffer, unsigned short timeOffset, unsigned int *highBlock);
00174 };
00175 
00176 struct CacheBlock {
00177     unsigned short m_timeOffset;        // timestamp relative to m_firstTimestamp
00178     unsigned short m_offsetW;           // position in words of item relative to start of block
00179 };
00180 
00181 /* CacheItem is the header of each item in the buffer, must be 32bit
00182    Items are always 32 bits aligned and size is the number of 32 bit words until the
00183    next item header, including an eventual pre and post padding gap for pointer alignment */
00184 struct CacheItem
00185 {
00186     unsigned short m_timeOffset;        // timestamp relative to m_firstTimestamp
00187     unsigned short m_sizeW;         // size of item in 32 bit words
00188     // item data follows header immediately or after a gap if position is not pointer aligned
00189 };
00190 
00191 // Buffer header
00192 // Defined in a macro to avoid sizeof() potential problem.
00193 //  next                for linked list. = NULL for last buffer
00194 //  m_firstTimestamp        timestamp of first item in this buffer
00195 //  m_lastTimestamp     timestamp of last item in this buffer
00196 //                      m_lastTimestamp must be < m_firstTimestamp+65536
00197 //  m_lastItemPositionW position in word of last item written
00198 //  m_firstFreePositionW    position in word where a new item can be written, 0 if buffer is empty
00199 //  lookup              lookup table for fast access to item by timestamp
00200 //                      The buffer is divided in blocks of 2**n bytes with n chosen so that 
00201 //                      there are no more than CACHE_LOOKUP_TABLE_SIZE blocks and that each 
00202 //                      block will contain at least one item. 
00203 //                      Each element of the lookup table gives the timestamp and offset 
00204 //                      of the last cache item occupying (=starting in) the corresponding block.
00205 #define CACHE_HEADER \
00206     struct CacheBuffer *m_next;     \
00207     unsigned int m_firstTimestamp;  \
00208     unsigned int m_lastTimestamp;       \
00209                                     \
00210     unsigned int m_lastItemPositionW;   \
00211     unsigned int m_firstFreePositionW;\
00212     struct CacheBlock lookup[CACHE_LOOKUP_TABLE_SIZE]
00213 
00214 struct CacheBufferHeader {
00215     CACHE_HEADER;
00216 };
00217 #define CACHE_BUFFER_HEADER_SIZE    (sizeof(struct CacheBufferHeader))
00218 struct CacheBuffer
00219 {
00220     CACHE_HEADER;
00221     struct CacheItem m_firstItem;           // the address of this field marks the start of the buffer
00222 };
00223 
00224 
00225 }
00226 
00227 #endif /* CACHE_HPP_ */