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.

381 lines
8.5 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. pplasl9x.c
  5. Abstract:
  6. This file contains the implementation of lookaside
  7. list manager.
  8. Author:
  9. Scott Holden (sholden) 14-Apr-2000
  10. --*/
  11. #include "wdm.h"
  12. #include "ndis.h"
  13. #include "cxport.h"
  14. #include "pplasl.h"
  15. // Keep scan period at one second -- this will make TCP/IP more responsive to
  16. // short bursts.
  17. #define MAXIMUM_SCAN_PERIOD 1
  18. #define MINIMUM_ALLOCATION_THRESHOLD 25
  19. #define MINIMUM_LOOKASIDE_DEPTH 10
  20. LIST_ENTRY PplLookasideListHead;
  21. KSPIN_LOCK PplLookasideLock;
  22. CTETimer PplTimer;
  23. ULONG PplCurrentScanPeriod = 1;
  24. VOID PplTimeout(CTEEvent * Timer, PVOID Context);
  25. BOOLEAN
  26. PplInit(VOID)
  27. {
  28. InitializeListHead(&PplLookasideListHead);
  29. CTEInitTimer(&PplTimer);
  30. KeInitializeSpinLock(&PplLookasideLock);
  31. CTEStartTimer(&PplTimer, 1000L, PplTimeout, NULL);
  32. return TRUE;
  33. }
  34. VOID
  35. PplDeinit(VOID)
  36. {
  37. CTEStopTimer(&PplTimer);
  38. return;
  39. }
  40. HANDLE
  41. PplCreatePool(
  42. IN PALLOCATE_FUNCTION Allocate,
  43. IN PFREE_FUNCTION Free,
  44. IN ULONG Flags,
  45. IN SIZE_T Size,
  46. IN ULONG Tag,
  47. IN USHORT Depth
  48. )
  49. {
  50. HANDLE PoolHandle;
  51. SIZE_T PoolSize;
  52. PNPAGED_LOOKASIDE_LIST Lookaside;
  53. PoolSize = sizeof(NPAGED_LOOKASIDE_LIST);
  54. PoolHandle = ExAllocatePoolWithTag(NonPagedPool, PoolSize, Tag);
  55. if (PoolHandle) {
  56. Lookaside = (PNPAGED_LOOKASIDE_LIST)PoolHandle;
  57. ExInitializeSListHead(&Lookaside->L.ListHead);
  58. Lookaside->L.Depth = MINIMUM_LOOKASIDE_DEPTH;
  59. Lookaside->L.MaximumDepth = Depth;
  60. Lookaside->L.TotalAllocates = 0;
  61. Lookaside->L.AllocateMisses = 0;
  62. Lookaside->L.TotalFrees = 0;
  63. Lookaside->L.FreeMisses = 0;
  64. Lookaside->L.Type = NonPagedPool | Flags;
  65. Lookaside->L.Tag = Tag;
  66. Lookaside->L.Size = Size;
  67. if (Allocate == NULL) {
  68. Lookaside->L.Allocate = ExAllocatePoolWithTag;
  69. } else {
  70. Lookaside->L.Allocate = Allocate;
  71. }
  72. if (Free == NULL) {
  73. Lookaside->L.Free = ExFreePool;
  74. } else {
  75. Lookaside->L.Free = Free;
  76. }
  77. Lookaside->L.LastTotalAllocates = 0;
  78. Lookaside->L.LastAllocateMisses = 0;
  79. KeInitializeSpinLock(&Lookaside->Lock);
  80. //
  81. // Insert the lookaside list structure the PPL lookaside list.
  82. //
  83. ExInterlockedInsertTailList(&PplLookasideListHead,
  84. &Lookaside->L.ListEntry,
  85. &PplLookasideLock);
  86. }
  87. return PoolHandle;
  88. }
  89. VOID
  90. PplDestroyPool(
  91. IN HANDLE PoolHandle
  92. )
  93. {
  94. PNPAGED_LOOKASIDE_LIST Lookaside;
  95. PVOID Entry;
  96. KIRQL OldIrql;
  97. if (PoolHandle == NULL) {
  98. return;
  99. }
  100. Lookaside = (PNPAGED_LOOKASIDE_LIST)PoolHandle;
  101. //
  102. // Acquire the nonpaged system lookaside list lock and remove the
  103. // specified lookaside list structure from the list.
  104. //
  105. ExAcquireSpinLock(&PplLookasideLock, &OldIrql);
  106. RemoveEntryList(&Lookaside->L.ListEntry);
  107. ExReleaseSpinLock(&PplLookasideLock, OldIrql);
  108. //
  109. // Remove all pool entries from the specified lookaside structure
  110. // and free them.
  111. //
  112. while ((Entry = ExAllocateFromNPagedLookasideList(Lookaside)) != NULL) {
  113. (Lookaside->L.Free)(Entry);
  114. }
  115. ExFreePool(PoolHandle);
  116. return;
  117. }
  118. PVOID
  119. PplAllocate(
  120. IN HANDLE PoolHandle,
  121. OUT LOGICAL *FromList
  122. )
  123. {
  124. PNPAGED_LOOKASIDE_LIST Lookaside;
  125. PVOID Entry;
  126. // Assume we'll get the item from the lookaside list.
  127. //
  128. *FromList = TRUE;
  129. Lookaside = (PNPAGED_LOOKASIDE_LIST)PoolHandle;
  130. Lookaside->L.TotalAllocates += 1;
  131. Entry = ExInterlockedPopEntrySList(&Lookaside->L.ListHead, &Lookaside->Lock);
  132. if (Entry == NULL) {
  133. Lookaside->L.AllocateMisses += 1;
  134. Entry = (Lookaside->L.Allocate)(Lookaside->L.Type,
  135. Lookaside->L.Size,
  136. Lookaside->L.Tag);
  137. *FromList = FALSE;
  138. }
  139. return Entry;
  140. }
  141. VOID
  142. PplFree(
  143. IN HANDLE PoolHandle,
  144. IN PVOID Entry
  145. )
  146. {
  147. PNPAGED_LOOKASIDE_LIST Lookaside = (PNPAGED_LOOKASIDE_LIST)PoolHandle;
  148. Lookaside->L.TotalFrees += 1;
  149. if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) {
  150. Lookaside->L.FreeMisses += 1;
  151. (Lookaside->L.Free)(Entry);
  152. } else {
  153. ExInterlockedPushEntrySList(&Lookaside->L.ListHead,
  154. (PSINGLE_LIST_ENTRY)Entry,
  155. &Lookaside->Lock);
  156. }
  157. return;
  158. }
  159. LOGICAL
  160. PplComputeLookasideDepth (
  161. IN ULONG Allocates,
  162. IN ULONG Misses,
  163. IN USHORT MaximumDepth,
  164. IN OUT PUSHORT Depth
  165. )
  166. /*++
  167. Routine Description:
  168. This function computes the target depth of a lookaside list given the
  169. total allocations and misses during the last scan period and the current
  170. depth.
  171. Arguments:
  172. Allocates - Supplies the total number of allocations during the last
  173. scan period.
  174. Misses - Supplies the total number of allocate misses during the last
  175. scan period.
  176. MaximumDepth - Supplies the maximum depth the lookaside list is allowed
  177. to reach.
  178. Depth - Supplies a pointer to the current lookaside list depth which
  179. receives the target depth.
  180. Return Value:
  181. If the target depth is greater than the current depth, then a value of
  182. TRUE is returned as the function value. Otherwise, a value of FALSE is
  183. returned.
  184. --*/
  185. {
  186. LOGICAL Changes;
  187. ULONG Ratio;
  188. ULONG Target;
  189. //
  190. // If the allocate rate is less than the mimimum threshold, then lower
  191. // the maximum depth of the lookaside list. Otherwise, if the miss rate
  192. // is less than .5%, then lower the maximum depth. Otherwise, raise the
  193. // maximum depth based on the miss rate.
  194. //
  195. Changes = FALSE;
  196. if (Misses >= Allocates) {
  197. Misses = Allocates;
  198. }
  199. if (Allocates == 0) {
  200. Allocates = 1;
  201. }
  202. Ratio = (Misses * 1000) / Allocates;
  203. Target = *Depth;
  204. if ((Allocates / PplCurrentScanPeriod) < MINIMUM_ALLOCATION_THRESHOLD) {
  205. if (Target > (MINIMUM_LOOKASIDE_DEPTH + 10)) {
  206. Target -= 10;
  207. } else {
  208. Target = MINIMUM_LOOKASIDE_DEPTH;
  209. }
  210. } else if (Ratio < 5) {
  211. if (Target > (MINIMUM_LOOKASIDE_DEPTH + 1)) {
  212. Target -= 1;
  213. } else {
  214. Target = MINIMUM_LOOKASIDE_DEPTH;
  215. }
  216. } else {
  217. Changes = TRUE;
  218. Target += ((Ratio * MaximumDepth) / (1000 * 2)) + 5;
  219. if (Target > MaximumDepth) {
  220. Target = MaximumDepth;
  221. }
  222. }
  223. *Depth = (USHORT)Target;
  224. return Changes;
  225. }
  226. LOGICAL
  227. PplScanLookasideList(
  228. PNPAGED_LOOKASIDE_LIST Lookaside
  229. )
  230. {
  231. LOGICAL Changes;
  232. ULONG Allocates;
  233. ULONG Misses;
  234. Allocates = Lookaside->L.TotalAllocates - Lookaside->L.LastTotalAllocates;
  235. Lookaside->L.LastTotalAllocates = Lookaside->L.TotalAllocates;
  236. Misses = Lookaside->L.AllocateMisses - Lookaside->L.LastAllocateMisses;
  237. Lookaside->L.LastAllocateMisses = Lookaside->L.AllocateMisses;
  238. Changes = PplComputeLookasideDepth(
  239. Allocates,
  240. Misses,
  241. Lookaside->L.MaximumDepth,
  242. &Lookaside->L.Depth);
  243. return Changes;
  244. }
  245. VOID
  246. PplTimeout(
  247. CTEEvent * Timer,
  248. PVOID Context)
  249. {
  250. LOGICAL Changes;
  251. KIRQL OldIrql;
  252. PLIST_ENTRY Entry;
  253. PNPAGED_LOOKASIDE_LIST Lookaside;
  254. //
  255. // Decrement the scan period and check if it is time to dynamically
  256. // adjust the maximum depth of lookaside lists.
  257. //
  258. Changes = FALSE;
  259. //
  260. // Scan our Ppl lists.
  261. //
  262. ExAcquireSpinLock(&PplLookasideLock, &OldIrql);
  263. Entry = PplLookasideListHead.Flink;
  264. while (Entry != &PplLookasideListHead) {
  265. Lookaside = CONTAINING_RECORD(Entry,
  266. NPAGED_LOOKASIDE_LIST,
  267. L.ListEntry);
  268. Changes |= PplScanLookasideList(Lookaside);
  269. Entry = Entry->Flink;
  270. }
  271. //
  272. // If any changes were made to the depth of any lookaside list during
  273. // this scan period, then lower the scan period to the minimum value.
  274. // Otherwise, attempt to raise the scan period.
  275. //
  276. if (Changes != FALSE) {
  277. PplCurrentScanPeriod = 1;
  278. } else {
  279. if (PplCurrentScanPeriod != MAXIMUM_SCAN_PERIOD) {
  280. PplCurrentScanPeriod += 1;
  281. }
  282. }
  283. ExReleaseSpinLock(&PplLookasideLock, OldIrql);
  284. //
  285. // Restart the timer.
  286. //
  287. CTEStartTimer(&PplTimer, PplCurrentScanPeriod * 1000L, PplTimeout, NULL);
  288. return;
  289. }