Cache.hpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. /*
  2. * Cache.hpp
  3. *
  4. * Created on: Feb 24, 2009
  5. * Author: benoit tbolsee
  6. */
  7. #ifndef CACHE_HPP_
  8. #define CACHE_HPP_
  9. #include <map>
  10. namespace iTaSC {
  11. #define CACHE_LOOKUP_TABLE_SIZE 128
  12. #define CACHE_DEFAULT_BUFFER_SIZE 32768
  13. #define CACHE_CHANNEL_EXTEND_SIZE 10
  14. #define CACHE_MAX_ITEM_SIZE 0x3FFF0
  15. /* macro to get the alignement gap after an item header */
  16. #define CACHE_ITEM_GAPB(item) (unsigned int)(((size_t)item+sizeof(CacheItem))&(sizeof(void*)-1))
  17. /* macro to get item data position, item=CacheItem pointer */
  18. #define CACHE_ITEM_DATA_POINTER(item) (void*)((unsigned char*)item+sizeof(CacheItem)+CACHE_ITEM_GAPB(item))
  19. /* macro to get item size in 32bit words from item address and length, item=CacheItem pointer */
  20. #define CACHE_ITEM_SIZEW(item,length) (unsigned int)((sizeof(CacheItem)+CACHE_ITEM_GAPB(item)+(((length)+3)&~0x3))>>2)
  21. /* macto to move from one item to the next, item=CacheItem pointer, updated by the macro */
  22. #define CACHE_NEXT_ITEM(item) ((item)+(item)->m_sizeW)
  23. #define CACHE_BLOCK_ITEM_ADDR(chan,buf,block) (&(buf)->m_firstItem+(((unsigned int)(block)<<chan->m_positionToBlockShiftW)+(buf)->lookup[block].m_offsetW))
  24. #define CACHE_ITEM_ADDR(buf,pos) (&(buf)->m_firstItem+(pos))
  25. #define CACHE_ITEM_POSITIONW(buf,item) (unsigned int)(item-&buf->m_firstItem)
  26. typedef unsigned int CacheTS;
  27. struct Timestamp
  28. {
  29. double realTimestamp;
  30. double realTimestep;
  31. CacheTS cacheTimestamp;
  32. unsigned int numstep:8;
  33. unsigned int substep:1;
  34. unsigned int reiterate:1;
  35. unsigned int cache:1;
  36. unsigned int update:1;
  37. unsigned int interpolate:1;
  38. unsigned int dummy:19;
  39. Timestamp() { memset(this, 0, sizeof(Timestamp)); }
  40. };
  41. /* utility function to return second timestamp to millisecond */
  42. inline void setCacheTimestamp(Timestamp& timestamp)
  43. {
  44. if (timestamp.realTimestamp < 0.0 || timestamp.realTimestamp > 4294967.295)
  45. timestamp.cacheTimestamp = 0;
  46. else
  47. timestamp.cacheTimestamp = (CacheTS)(timestamp.realTimestamp*1000.0+0.5);
  48. }
  49. /*
  50. class Cache:
  51. Top level class, only one instance of this class should exists.
  52. A device (=constraint, object) uses this class to create a cache entry for its data.
  53. A cache entry is divided into cache channels, each providing a separate buffer for cache items.
  54. The cache channels must be declared by the devices before they can be used.
  55. The device must specify the largest cache item (limited to 256Kb) so that the cache
  56. buffer can be organized optimally.
  57. Cache channels are identified by small number (starting from 0) allocated by the cache system.
  58. Cache items are inserted into cache channels ordered by timestamp. Writing is always done
  59. at the end of the cache buffer: writing an item automatically clears all items with
  60. higher timestamp.
  61. A cache item is an array of bytes provided by the device; the format of the cache item is left
  62. to the device.
  63. The device can retrieve a cache item associated with a certain timestamp. The cache system
  64. returns a pointer that points directly in the cache buffer to avoid unnecessary copy.
  65. The pointer is guaranteed to be pointer aligned so that direct mapping to C structure is possible
  66. (=32 bit aligned on 32 systems and 64 bit aligned on 64 bits system).
  67. Timestamp = rounded time in millisecond.
  68. */
  69. struct CacheEntry;
  70. struct CacheBuffer;
  71. struct CacheItem;
  72. struct CacheChannel;
  73. class Cache
  74. {
  75. private:
  76. /* map between device and cache entry.
  77. Dynamically updated when more devices create cache channels */
  78. typedef std::map<const void *, struct CacheEntry*> CacheMap;
  79. CacheMap m_cache;
  80. const CacheItem *getCurrentCacheItemInternal(const void *device, int channel, CacheTS timestamp);
  81. public:
  82. Cache();
  83. ~Cache();
  84. /* add a cache channel, maxItemSize must be < 256k.
  85. name : channel name, truncated at 31 characters
  86. msxItemSize : maximum size of item in bytes, items of larger size will be rejected
  87. return value >= 0: channel id, -1: error */
  88. int addChannel(const void *device, const char *name, unsigned int maxItemSize);
  89. /* delete a cache channel (and all associated buffers and items) */
  90. int deleteChannel(const void *device, int channel);
  91. /* delete all channels of a device and remove the device from the map */
  92. int deleteDevice(const void *device);
  93. /* removes all cache items, leaving the special item at timestamp=0.
  94. if device=NULL, apply to all devices. */
  95. void clearCacheFrom(const void *device, CacheTS timestamp);
  96. /* add a new cache item
  97. channel: the cache channel (as returned by AddChannel
  98. data, length: the cache item and length in bytes
  99. If data is NULL, the memory is allocated in the cache but not writen
  100. return: error: NULL, success: pointer to item in cache */
  101. void *addCacheItem(const void *device, int channel, CacheTS timestamp, void *data, unsigned int length);
  102. /* specialized function to add a vector of double in the cache
  103. It will first check if a vector exist already in the cache for the same timestamp
  104. and compared the cached vector with the new values.
  105. If all values are within threshold, the vector is updated but the cache is not deleted
  106. for the future timestamps. */
  107. double *addCacheVectorIfDifferent(const void *device, int channel, CacheTS timestamp, double *data, unsigned int length, double threshold);
  108. /* returns the cache item with timestamp that is just before the given timestamp.
  109. returns the data pointer or NULL if there is no cache item before timestamp.
  110. On return, timestamp is updated with the actual timestamp of the item being returned.
  111. Note that the length of the item is not returned, it is up to the device to organize
  112. the data so that length can be retrieved from the data if needed.
  113. Device can NULL, it will then just look the first channel available, useful to
  114. test the status of the cache. */
  115. const void *getPreviousCacheItem(const void *device, int channel, CacheTS *timestamp);
  116. /* returns the cache item with the timestamp that is exactly equal to the given timestamp
  117. If there is no cache item for this timestamp, returns NULL.*/
  118. const void *getCurrentCacheItem(const void *device, int channel, CacheTS timestamp);
  119. };
  120. /* the following structures are not internal use only, they should not be used directly */
  121. struct CacheEntry
  122. {
  123. CacheChannel *m_channelArray; // array of channels, automatically resized if more channels are created
  124. unsigned int m_count; // number of channel in channelArray
  125. CacheEntry() : m_channelArray(NULL), m_count(0) {}
  126. ~CacheEntry();
  127. };
  128. struct CacheChannel
  129. {
  130. CacheItem* initItem; // item corresponding to timestamp=0
  131. struct CacheBuffer *m_firstBuffer; // first buffer of list
  132. struct CacheBuffer *m_lastBuffer; // last buffer of list to which an item was written
  133. char m_name[32]; // channel name
  134. unsigned char m_busy; // =0 if channel is free, !=0 when channel is in use
  135. unsigned char m_positionToBlockShiftW; // number of bits to shift a position in word to get the block number
  136. unsigned short m_positionToOffsetMaskW; // bit mask to apply on a position in word to get offset in a block
  137. unsigned int m_maxItemSizeB; // maximum item size in bytes
  138. unsigned int m_bufferSizeW; // size of item buffer in word to allocate when a new buffer must be created
  139. unsigned int m_blockSizeW; // block size in words of the lookup table
  140. unsigned int m_lastTimestamp; // timestamp of the last item that was written
  141. unsigned int m_lastItemPositionW; // position in words in lastBuffer of the last item written
  142. void clear();
  143. CacheBuffer* allocBuffer();
  144. CacheItem* findItemOrLater(unsigned int timestamp, CacheBuffer **rBuffer);
  145. CacheItem* findItemEarlier(unsigned int timestamp, CacheBuffer **rBuffer);
  146. // Internal function: finds an item in a buffer that is < timeOffset
  147. // timeOffset must be a valid offset for the buffer and the buffer must not be empty
  148. // on return highBlock contains the block with items above or equal to timeOffset
  149. CacheItem *_findBlock(CacheBuffer *buffer, unsigned short timeOffset, unsigned int *highBlock);
  150. };
  151. struct CacheBlock {
  152. unsigned short m_timeOffset; // timestamp relative to m_firstTimestamp
  153. unsigned short m_offsetW; // position in words of item relative to start of block
  154. };
  155. /* CacheItem is the header of each item in the buffer, must be 32bit
  156. Items are always 32 bits aligned and size is the number of 32 bit words until the
  157. next item header, including an eventual pre and post padding gap for pointer alignment */
  158. struct CacheItem
  159. {
  160. unsigned short m_timeOffset; // timestamp relative to m_firstTimestamp
  161. unsigned short m_sizeW; // size of item in 32 bit words
  162. // item data follows header immediately or after a gap if position is not pointer aligned
  163. };
  164. // Buffer header
  165. // Defined in a macro to avoid sizeof() potential problem.
  166. // next for linked list. = NULL for last buffer
  167. // m_firstTimestamp timestamp of first item in this buffer
  168. // m_lastTimestamp timestamp of last item in this buffer
  169. // m_lastTimestamp must be < m_firstTimestamp+65536
  170. // m_lastItemPositionW position in word of last item written
  171. // m_firstFreePositionW position in word where a new item can be written, 0 if buffer is empty
  172. // lookup lookup table for fast access to item by timestamp
  173. // The buffer is divided in blocks of 2**n bytes with n chosen so that
  174. // there are no more than CACHE_LOOKUP_TABLE_SIZE blocks and that each
  175. // block will contain at least one item.
  176. // Each element of the lookup table gives the timestamp and offset
  177. // of the last cache item occupying (=starting in) the corresponding block.
  178. #define CACHE_HEADER \
  179. struct CacheBuffer *m_next; \
  180. unsigned int m_firstTimestamp; \
  181. unsigned int m_lastTimestamp; \
  182. \
  183. unsigned int m_lastItemPositionW; \
  184. unsigned int m_firstFreePositionW;\
  185. struct CacheBlock lookup[CACHE_LOOKUP_TABLE_SIZE]
  186. struct CacheBufferHeader {
  187. CACHE_HEADER;
  188. };
  189. #define CACHE_BUFFER_HEADER_SIZE (sizeof(struct CacheBufferHeader))
  190. struct CacheBuffer
  191. {
  192. CACHE_HEADER;
  193. struct CacheItem m_firstItem; // the address of this field marks the start of the buffer
  194. };
  195. }
  196. #endif /* CACHE_HPP_ */