Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

265 lines
6.4 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1997 - 1999
  3. Module Name:
  4. bcache.hxx
  5. Abstract:
  6. RPC's buffer cache class
  7. Author:
  8. Mario Goertzel [MarioGo]
  9. Revision History:
  10. MarioGo 9/25/1997 Bits 'n pieces
  11. --*/
  12. /*++
  13. Copyright (C) Microsoft Corporation, 1997 - 1999
  14. Module Name:
  15. bcache.hxx
  16. Abstract:
  17. Cached buffer allocation class
  18. Author:
  19. Mario Goertzel [MarioGo]
  20. Revision History:
  21. MarioGo 9/7/1997 Bits 'n pieces
  22. --*/
  23. #ifndef __BCACHE_HXX
  24. #define __BCACHE_HXX
  25. //
  26. // The RPC buffer cache uses several levels of caching to improve
  27. // performance. The cache has either 2 or 4 fixed buffer sizes that
  28. // it caches. The first level of cache is per-thread. The second
  29. // level is process wide.
  30. //
  31. // Their are two performance goals: make a single alloc/free loop
  32. // execute with a minimum of cycles and scale well on MP machines.
  33. // This implementation can do 8000000 allocs in 761ms using 8 threads
  34. // on a 4xPPro 200.
  35. //
  36. // In the default mode, elements which are the right size for various
  37. // runtime allocations as cached.
  38. //
  39. // In paged bcache mode (used for testing) 1 and 2 page buffers are cached.
  40. // In this mode we allocate each buffer at the end of the page, and we
  41. // add a read only page after that. This allows NDR to temporarily read
  42. // past the end of the buffer without raising exceptions, but writes
  43. // will AV. That's we we can't use paged heap BTW - we need a page
  44. // after the buffer with RO access, not without any access.
  45. //
  46. struct BUFFER_CACHE_HINTS
  47. {
  48. // When the thread cache is empty, this many blocks are moved
  49. // from the global cache (if possible) to the thread cache.
  50. // When freeing from the thread cache, this many buffers
  51. // are left in the thread cache.
  52. UINT cLowWatermark;
  53. // When per thread cache will reach mark due to a free, blocks
  54. // will be moved to the global cache.
  55. UINT cHighWatermark;
  56. // Summary: The difference between high and low is the number
  57. // of blocks allocated/freed from the global cache at a time.
  58. //
  59. // Lowwater should be the average number of free buffers - 1
  60. // you expect a thread to have. Highwater should be the
  61. // maximum number of free buffers + 1 you expect a thread
  62. // to need.
  63. //
  64. // **** Note: The difference must be two or more. ***
  65. // Example: 1 3
  66. // Alloc called with the thread cache empty, two blocks are removed
  67. // from the global list. One is saved the thread list. The other
  68. // is returned.
  69. //
  70. // Free called with two free buffers in the thread list. A total
  71. // of three buffers. Two buffers are moved to the global cache, one
  72. // stays in the thread cache.
  73. //
  74. //
  75. // The size of the buffers
  76. UINT cSize;
  77. };
  78. extern CONST BUFFER_CACHE_HINTS gCacheHints[4];
  79. extern BUFFER_CACHE_HINTS gPagedBCacheHints[4];
  80. extern BUFFER_CACHE_HINTS *pHints;
  81. struct PAGED_BCACHE_SECTION_MANAGER
  82. {
  83. ULONG NumberOfSegments;
  84. ULONG NumberOfUsedSegments;
  85. ULONG SegmentSize; // doesn't include guard page. In bytes. I.e. size
  86. // of read-write committed segment
  87. void *VirtualMemorySection;
  88. LIST_ENTRY SectionList; // all sections are chained. This both makes leak
  89. // tracking easier and it allows us to maintain
  90. // good locality by allocating off the first section
  91. // first.
  92. BOOLEAN SegmentBusy[1]; // actually the array size is the number of segments
  93. // we use boolean as arbitrary tradeoff b/n speed (ULONG)
  94. // and size (true bit vector).
  95. };
  96. // Used in all modes, sits at the front of the buffer allocation.
  97. struct BUFFER_HEAD
  98. {
  99. union {
  100. BUFFER_HEAD *pNext; // Valid only in free lists
  101. INT index; // Valid only when allocated
  102. // 1-4 for cachable, -1 for big
  103. };
  104. union {
  105. // Used in paged bcache mode only.
  106. SIZE_T size; // if index == -1, this is the size. Used only
  107. // for debugging.
  108. PAGED_BCACHE_SECTION_MANAGER *SectionManager; // points to a small heap block
  109. // containing control information
  110. };
  111. };
  112. typedef BUFFER_HEAD *PBUFFER;
  113. // This structure is imbedded into the RPC thread object
  114. struct BCACHE_STATE
  115. {
  116. BUFFER_HEAD *pList;
  117. ULONG cBlocks;
  118. };
  119. // The strucutre parrallels the global cache
  120. struct BCACHE_STATS
  121. {
  122. UINT cBufferCacheCap;
  123. UINT cAllocationHits;
  124. UINT cAllocationMisses;
  125. };
  126. class THREAD;
  127. class BCACHE
  128. {
  129. private:
  130. BCACHE_STATE _bcGlobalState[4];
  131. BCACHE_STATS _bcGlobalStats[4];
  132. MUTEX _csBufferCacheLock;
  133. LIST_ENTRY Sections; // used in guard page mode only
  134. PVOID AllocHelper(size_t, INT, BCACHE_STATE *);
  135. VOID FreeHelper(PVOID, INT, BCACHE_STATE *);
  136. VOID FreeBuffers(PBUFFER, INT, UINT);
  137. PBUFFER AllocBigBlock(IN size_t);
  138. VOID FreeBigBlock(IN PBUFFER);
  139. PBUFFER
  140. BCACHE::AllocPagedBCacheSection (
  141. IN UINT size,
  142. IN ULONG OriginalSize
  143. );
  144. ULONG
  145. GetSegmentIndexFromBuffer (
  146. IN PBUFFER pBuffer,
  147. IN PVOID Allocation
  148. );
  149. #if DBG
  150. void
  151. VerifyPagedBCacheState (
  152. void
  153. );
  154. void
  155. VerifySectionState (
  156. IN PAGED_BCACHE_SECTION_MANAGER *Section
  157. );
  158. void
  159. VerifySegmentState (
  160. IN PVOID Segment,
  161. IN BOOL IsSegmentBusy,
  162. IN ULONG SegmentSize,
  163. IN PAGED_BCACHE_SECTION_MANAGER *OwningSection
  164. );
  165. #endif
  166. PVOID
  167. PutBufferAtEndOfAllocation (
  168. IN PVOID Allocation,
  169. IN ULONG AllocationSize,
  170. IN ULONG BufferSize
  171. );
  172. PVOID
  173. ConvertBufferToAllocation (
  174. IN PBUFFER Buffer,
  175. IN BOOL IsBufferInitialized
  176. );
  177. PVOID
  178. CommitSegment (
  179. IN PVOID SegmentStart,
  180. IN ULONG SegmentSize
  181. );
  182. public:
  183. BCACHE(RPC_STATUS &);
  184. ~BCACHE();
  185. PVOID Allocate(CONST size_t cSize);
  186. VOID Free(PVOID);
  187. VOID ThreadDetach(THREAD *);
  188. };
  189. extern BCACHE *gBufferCache;
  190. // Helper APIs
  191. inline PVOID
  192. RpcAllocateBuffer(CONST size_t cSize)
  193. {
  194. return(gBufferCache->Allocate(cSize));
  195. }
  196. inline VOID
  197. RpcFreeBuffer(PVOID pBuffer)
  198. {
  199. if (pBuffer == 0)
  200. {
  201. return;
  202. }
  203. gBufferCache->Free(pBuffer);
  204. }
  205. #endif // __BCACHE_HXX