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.

845 lines
19 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. lookasid.c
  5. Abstract:
  6. This module implements lookaside list function.
  7. Author:
  8. David N. Cutler (davec) 19-Feb-1995
  9. Revision History:
  10. --*/
  11. #include "exp.h"
  12. #pragma alloc_text(PAGE, ExInitializePagedLookasideList)
  13. //
  14. // Define Minimum lookaside list depth.
  15. //
  16. #define MINIMUM_LOOKASIDE_DEPTH 4
  17. //
  18. // Define minimum allocation threshold.
  19. //
  20. #define MINIMUM_ALLOCATION_THRESHOLD 25
  21. //
  22. // Define forward referenced function prototypes.
  23. //
  24. PVOID
  25. ExpDummyAllocate (
  26. IN POOL_TYPE PoolType,
  27. IN SIZE_T NumberOfBytes,
  28. IN ULONG Tag
  29. );
  30. VOID
  31. ExpScanGeneralLookasideList (
  32. IN PLIST_ENTRY ListHead,
  33. IN PKSPIN_LOCK SpinLock
  34. );
  35. VOID
  36. ExpScanSystemLookasideList (
  37. VOID
  38. );
  39. //
  40. // Define the global nonpaged and paged lookaside list data.
  41. //
  42. LIST_ENTRY ExNPagedLookasideListHead;
  43. KSPIN_LOCK ExNPagedLookasideLock;
  44. LIST_ENTRY ExPagedLookasideListHead;
  45. KSPIN_LOCK ExPagedLookasideLock;
  46. LIST_ENTRY ExPoolLookasideListHead;
  47. LIST_ENTRY ExSystemLookasideListHead;
  48. //
  49. // Define lookaside list dynamic adjustment data.
  50. //
  51. ULONG ExpPoolScanCount = 0;
  52. ULONG ExpScanCount = 0;
  53. VOID
  54. ExAdjustLookasideDepth (
  55. VOID
  56. )
  57. /*++
  58. Routine Description:
  59. This function is called periodically to adjust the maximum depth of
  60. all lookaside lists.
  61. Arguments:
  62. None.
  63. Return Value:
  64. None.
  65. --*/
  66. {
  67. //
  68. // Switch on the current scan count.
  69. //
  70. switch (ExpScanCount) {
  71. //
  72. // Scan the general nonpaged lookaside lists.
  73. //
  74. case 0:
  75. ExpScanGeneralLookasideList(&ExNPagedLookasideListHead,
  76. &ExNPagedLookasideLock);
  77. break;
  78. //
  79. // Scan the general paged lookaside lists.
  80. //
  81. case 1:
  82. ExpScanGeneralLookasideList(&ExPagedLookasideListHead,
  83. &ExPagedLookasideLock);
  84. break;
  85. //
  86. // Scan the pool paged and nonpaged lookaside lists.
  87. //
  88. // N.B. Only one set of pool paged and nonpaged lookaside lists
  89. // are scanned each scan period.
  90. //
  91. case 2:
  92. ExpScanSystemLookasideList();
  93. break;
  94. }
  95. //
  96. // Increment the scan count. If a complete cycles has been completed,
  97. // then zero the scan count and check if any changes occurred during
  98. // the complete scan.
  99. //
  100. ExpScanCount += 1;
  101. if (ExpScanCount == 3) {
  102. ExpScanCount = 0;
  103. }
  104. return;
  105. }
  106. FORCEINLINE
  107. VOID
  108. ExpComputeLookasideDepth (
  109. IN PGENERAL_LOOKASIDE Lookaside,
  110. IN ULONG Misses,
  111. IN ULONG ScanPeriod
  112. )
  113. /*++
  114. Routine Description:
  115. This function computes the target depth of a lookaside list given the
  116. total allocations and misses during the last scan period and the current
  117. depth.
  118. Arguments:
  119. Lookaside - Supplies a pointer to a lookaside list descriptor.
  120. Misses - Supllies the total number of allocate misses.
  121. ScanPeriod - Supplies the scan period in seconds.
  122. Return Value:
  123. None.
  124. --*/
  125. {
  126. ULONG Allocates;
  127. ULONG Delta;
  128. USHORT MaximumDepth;
  129. ULONG Ratio;
  130. LONG Target;
  131. //
  132. // Compute the total number of allocations and misses per second for
  133. // this scan period.
  134. //
  135. Allocates = Lookaside->TotalAllocates - Lookaside->LastTotalAllocates;
  136. Lookaside->LastTotalAllocates = Lookaside->TotalAllocates;
  137. MaximumDepth = Lookaside->MaximumDepth;
  138. //
  139. // If the allocate rate is less than the mimimum threshold, then lower
  140. // the maximum depth of the lookaside list. Otherwise, if the miss rate
  141. // is less than .5%, then lower the maximum depth. Otherwise, raise the
  142. // maximum depth based on the miss rate.
  143. //
  144. Target = Lookaside->Depth;
  145. if (Allocates < (ScanPeriod * MINIMUM_ALLOCATION_THRESHOLD)) {
  146. if ((Target -= 10) < MINIMUM_LOOKASIDE_DEPTH) {
  147. Target = MINIMUM_LOOKASIDE_DEPTH;
  148. }
  149. } else {
  150. //
  151. // N.B. The number of allocates is guaranteed to be greater than
  152. // zero because of the above test.
  153. //
  154. // N.B. It is possible that the number of misses are greater than the
  155. // number of allocates, but this won't cause the an incorrect
  156. // computation of the depth adjustment.
  157. //
  158. Ratio = (Misses * 1000) / Allocates;
  159. if (Ratio < 5) {
  160. if ((Target -= 1) < MINIMUM_LOOKASIDE_DEPTH) {
  161. Target = MINIMUM_LOOKASIDE_DEPTH;
  162. }
  163. } else {
  164. if ((Delta = ((Ratio * (MaximumDepth - Target)) / (1000 * 2)) + 5) > 30) {
  165. Delta = 30;
  166. }
  167. if ((Target += Delta) > MaximumDepth) {
  168. Target = MaximumDepth;
  169. }
  170. }
  171. }
  172. Lookaside->Depth = (USHORT)Target;
  173. return;
  174. }
  175. VOID
  176. ExpScanGeneralLookasideList (
  177. IN PLIST_ENTRY ListHead,
  178. IN PKSPIN_LOCK SpinLock
  179. )
  180. /*++
  181. Routine Description:
  182. This function scans the specified list of general lookaside descriptors
  183. and adjusts the maximum depth as necessary.
  184. Arguments:
  185. ListHead - Supplies the address of the listhead for a list of lookaside
  186. descriptors.
  187. SpinLock - Supplies the address of the spinlock to be used to synchronize
  188. access to the list of lookaside descriptors.
  189. Return Value:
  190. None.
  191. --*/
  192. {
  193. PLIST_ENTRY Entry;
  194. PPAGED_LOOKASIDE_LIST Lookaside;
  195. ULONG Misses;
  196. KIRQL OldIrql;
  197. #ifdef NT_UP
  198. UNREFERENCED_PARAMETER (SpinLock);
  199. #endif
  200. //
  201. // Raise IRQL and acquire the specified spinlock.
  202. //
  203. ExAcquireSpinLock(SpinLock, &OldIrql);
  204. //
  205. // Scan the specified list of lookaside descriptors and adjust the
  206. // maximum depth as necessary.
  207. //
  208. // N.B. All lookaside list descriptor are treated as if they were
  209. // paged descriptor even though they may be nonpaged descriptors.
  210. // This is possible since both structures are identical except
  211. // for the locking fields which are the last structure fields.
  212. //
  213. Entry = ListHead->Flink;
  214. while (Entry != ListHead) {
  215. Lookaside = CONTAINING_RECORD(Entry,
  216. PAGED_LOOKASIDE_LIST,
  217. L.ListEntry);
  218. //
  219. // Compute target depth of lookaside list.
  220. //
  221. Misses = Lookaside->L.AllocateMisses - Lookaside->L.LastAllocateMisses;
  222. Lookaside->L.LastAllocateMisses = Lookaside->L.AllocateMisses;
  223. ExpComputeLookasideDepth(&Lookaside->L, Misses, 3);
  224. Entry = Entry->Flink;
  225. }
  226. //
  227. // Release spinlock, lower IRQL, and return function value.
  228. //
  229. ExReleaseSpinLock(SpinLock, OldIrql);
  230. return;
  231. }
  232. VOID
  233. ExpScanSystemLookasideList (
  234. VOID
  235. )
  236. /*++
  237. Routine Description:
  238. This function scans the current set of paged and nonpaged pool lookaside
  239. descriptors and adjusts the maximum depth as necessary.
  240. Arguments:
  241. None.
  242. Return Value:
  243. A value of TRUE is returned if the maximum depth of any lookaside list
  244. is changed. Otherwise, a value of FALSE is returned.
  245. --*/
  246. {
  247. ULONG Hits;
  248. ULONG Index;
  249. PGENERAL_LOOKASIDE Lookaside;
  250. ULONG Misses;
  251. PKPRCB Prcb;
  252. ULONG ScanPeriod;
  253. //
  254. // Scan the current set of lookaside descriptors and adjust the maximum
  255. // depth as necessary. Either a set of per processor small pool lookaside
  256. // lists or the global small pool lookaside lists are scanned during a
  257. // scan period.
  258. //
  259. // N.B. All lookaside list descriptor are treated as if they were
  260. // paged descriptor even though they may be nonpaged descriptors.
  261. // This is possible since both structures are identical except
  262. // for the locking fields which are the last structure fields.
  263. //
  264. ScanPeriod = (1 + 1 + 1) * KeNumberProcessors;
  265. if (ExpPoolScanCount == (ULONG)KeNumberProcessors) {
  266. //
  267. // Adjust the maximum depth for the global set of system lookaside
  268. // descriptors.
  269. //
  270. Prcb = KeGetCurrentPrcb();
  271. for (Index = 0; Index < LookasideMaximumList; Index += 1) {
  272. Lookaside = Prcb->PPLookasideList[Index].L;
  273. if (Lookaside != NULL) {
  274. Misses = Lookaside->AllocateMisses - Lookaside->LastAllocateMisses;
  275. Lookaside->LastAllocateMisses = Lookaside->AllocateMisses;
  276. ExpComputeLookasideDepth(Lookaside, Misses, ScanPeriod);
  277. }
  278. }
  279. //
  280. // Adjust the maximum depth for the global set of small pool lookaside
  281. // descriptors.
  282. //
  283. for (Index = 0; Index < POOL_SMALL_LISTS; Index += 1) {
  284. //
  285. // Compute target depth of nonpaged lookaside list.
  286. //
  287. Lookaside = &ExpSmallNPagedPoolLookasideLists[Index];
  288. Hits = Lookaside->AllocateHits - Lookaside->LastAllocateHits;
  289. Lookaside->LastAllocateHits = Lookaside->AllocateHits;
  290. Misses =
  291. Lookaside->TotalAllocates - Lookaside->LastTotalAllocates - Hits;
  292. ExpComputeLookasideDepth(Lookaside, Misses, ScanPeriod);
  293. //
  294. // Compute target depth of paged lookaside list.
  295. //
  296. Lookaside = &ExpSmallPagedPoolLookasideLists[Index];
  297. Hits = Lookaside->AllocateHits - Lookaside->LastAllocateHits;
  298. Lookaside->LastAllocateHits = Lookaside->AllocateHits;
  299. Misses =
  300. Lookaside->TotalAllocates - Lookaside->LastTotalAllocates - Hits;
  301. ExpComputeLookasideDepth(Lookaside, Misses, ScanPeriod);
  302. }
  303. } else {
  304. //
  305. // Adjust the maximum depth for the global set of per processor
  306. // system lookaside descriptors.
  307. //
  308. Prcb = KiProcessorBlock[ExpPoolScanCount];
  309. for (Index = 0; Index < LookasideMaximumList; Index += 1) {
  310. Lookaside = Prcb->PPLookasideList[Index].P;
  311. if (Lookaside != NULL) {
  312. Misses = Lookaside->AllocateMisses - Lookaside->LastAllocateMisses;
  313. Lookaside->LastAllocateMisses = Lookaside->AllocateMisses;
  314. ExpComputeLookasideDepth(Lookaside, Misses, ScanPeriod);
  315. }
  316. }
  317. //
  318. // Adjust the maximum depth for a set of per processor small pool
  319. // lookaside descriptors.
  320. //
  321. for (Index = 0; Index < POOL_SMALL_LISTS; Index += 1) {
  322. //
  323. // Compute target depth of nonpaged lookaside list.
  324. //
  325. Lookaside = Prcb->PPNPagedLookasideList[Index].P;
  326. Hits = Lookaside->AllocateHits - Lookaside->LastAllocateHits;
  327. Lookaside->LastAllocateHits = Lookaside->AllocateHits;
  328. Misses =
  329. Lookaside->TotalAllocates - Lookaside->LastTotalAllocates - Hits;
  330. ExpComputeLookasideDepth(Lookaside, Misses, ScanPeriod);
  331. //
  332. // Compute target depth of paged lookaside list.
  333. //
  334. Lookaside = Prcb->PPPagedLookasideList[Index].P;
  335. Hits = Lookaside->AllocateHits - Lookaside->LastAllocateHits;
  336. Lookaside->LastAllocateHits = Lookaside->AllocateHits;
  337. Misses =
  338. Lookaside->TotalAllocates - Lookaside->LastTotalAllocates - Hits;
  339. ExpComputeLookasideDepth(Lookaside, Misses, ScanPeriod);
  340. }
  341. }
  342. ExpPoolScanCount += 1;
  343. if (ExpPoolScanCount > (ULONG)KeNumberProcessors) {
  344. ExpPoolScanCount = 0;
  345. }
  346. return;
  347. }
  348. VOID
  349. ExInitializeNPagedLookasideList (
  350. IN PNPAGED_LOOKASIDE_LIST Lookaside,
  351. IN PALLOCATE_FUNCTION Allocate,
  352. IN PFREE_FUNCTION Free,
  353. IN ULONG Flags,
  354. IN SIZE_T Size,
  355. IN ULONG Tag,
  356. IN USHORT Depth
  357. )
  358. /*++
  359. Routine Description:
  360. This function initializes a nonpaged lookaside list structure and inserts
  361. the structure in the system nonpaged lookaside list.
  362. Arguments:
  363. Lookaside - Supplies a pointer to a nonpaged lookaside list structure.
  364. Allocate - Supplies an optional pointer to an allocate function.
  365. Free - Supplies an optional pointer to a free function.
  366. Flags - Supplies the pool allocation flags which are merged with the
  367. pool allocation type (NonPagedPool) to control pool allocation.
  368. Size - Supplies the size for the lookaside list entries.
  369. Tag - Supplies the pool tag for the lookaside list entries.
  370. Depth - Supplies the maximum depth of the lookaside list.
  371. Return Value:
  372. None.
  373. --*/
  374. {
  375. #ifdef _IA64_
  376. PVOID Entry;
  377. #endif
  378. UNREFERENCED_PARAMETER (Depth);
  379. //
  380. // Initialize the lookaside list structure.
  381. //
  382. InitializeSListHead(&Lookaside->L.ListHead);
  383. Lookaside->L.Depth = MINIMUM_LOOKASIDE_DEPTH;
  384. Lookaside->L.MaximumDepth = 256; //Depth;
  385. Lookaside->L.TotalAllocates = 0;
  386. Lookaside->L.AllocateMisses = 0;
  387. Lookaside->L.TotalFrees = 0;
  388. Lookaside->L.FreeMisses = 0;
  389. Lookaside->L.Type = NonPagedPool | Flags;
  390. Lookaside->L.Tag = Tag;
  391. Lookaside->L.Size = (ULONG)Size;
  392. if (Allocate == NULL) {
  393. Lookaside->L.Allocate = ExAllocatePoolWithTag;
  394. } else {
  395. Lookaside->L.Allocate = Allocate;
  396. }
  397. if (Free == NULL) {
  398. Lookaside->L.Free = ExFreePool;
  399. } else {
  400. Lookaside->L.Free = Free;
  401. }
  402. Lookaside->L.LastTotalAllocates = 0;
  403. Lookaside->L.LastAllocateMisses = 0;
  404. //
  405. // For IA-64 we have to correctly initialize the region field in the S-list.
  406. // This might be in a different region than the head of the S-list. We get
  407. // correct one by doing a allocation to getting the region and then saving it.
  408. //
  409. #ifdef _IA64_
  410. Entry = (Lookaside->L.Allocate)(Lookaside->L.Type,
  411. Lookaside->L.Size,
  412. Lookaside->L.Tag);
  413. if (Entry != NULL) {
  414. Lookaside->L.ListHead.Region = (ULONG_PTR)Entry & VRN_MASK;
  415. //
  416. // Free the memory.
  417. //
  418. (Lookaside->L.Free)(Entry);
  419. }
  420. #endif
  421. //
  422. // Insert the lookaside list structure is the system nonpaged lookaside
  423. // list.
  424. //
  425. ExInterlockedInsertTailList(&ExNPagedLookasideListHead,
  426. &Lookaside->L.ListEntry,
  427. &ExNPagedLookasideLock);
  428. return;
  429. }
  430. VOID
  431. ExDeleteNPagedLookasideList (
  432. IN PNPAGED_LOOKASIDE_LIST Lookaside
  433. )
  434. /*++
  435. Routine Description:
  436. This function removes a paged lookaside structure from the system paged
  437. lookaside list and frees any entries specified by the lookaside structure.
  438. Arguments:
  439. Lookaside - Supplies a pointer to a nonpaged lookaside list structure.
  440. Return Value:
  441. None.
  442. --*/
  443. {
  444. PVOID Entry;
  445. KIRQL OldIrql;
  446. //
  447. // Acquire the nonpaged system lookaside list lock and remove the
  448. // specified lookaside list structure from the list.
  449. //
  450. ExAcquireSpinLock(&ExNPagedLookasideLock, &OldIrql);
  451. RemoveEntryList(&Lookaside->L.ListEntry);
  452. ExReleaseSpinLock(&ExNPagedLookasideLock, OldIrql);
  453. //
  454. // Remove all pool entries from the specified lookaside structure
  455. // and free them.
  456. //
  457. Lookaside->L.Allocate = ExpDummyAllocate;
  458. while ((Entry = ExAllocateFromNPagedLookasideList(Lookaside)) != NULL) {
  459. (Lookaside->L.Free)(Entry);
  460. }
  461. return;
  462. }
  463. VOID
  464. ExInitializePagedLookasideList (
  465. IN PPAGED_LOOKASIDE_LIST Lookaside,
  466. IN PALLOCATE_FUNCTION Allocate,
  467. IN PFREE_FUNCTION Free,
  468. IN ULONG Flags,
  469. IN SIZE_T Size,
  470. IN ULONG Tag,
  471. IN USHORT Depth
  472. )
  473. /*++
  474. Routine Description:
  475. This function initializes a paged lookaside list structure and inserts
  476. the structure in the system paged lookaside list.
  477. Arguments:
  478. Lookaside - Supplies a pointer to a paged lookaside list structure.
  479. Allocate - Supplies an optional pointer to an allocate function.
  480. Free - Supplies an optional pointer to a free function.
  481. Flags - Supplies the pool allocation flags which are merged with the
  482. pool allocation type (NonPagedPool) to control pool allocation.
  483. Size - Supplies the size for the lookaside list entries.
  484. Tag - Supplies the pool tag for the lookaside list entries.
  485. Depth - Supplies the maximum depth of the lookaside list.
  486. Return Value:
  487. None.
  488. --*/
  489. {
  490. #ifdef _IA64_
  491. PVOID Entry;
  492. #endif
  493. UNREFERENCED_PARAMETER (Depth);
  494. PAGED_CODE()
  495. //
  496. // Initialize the lookaside list structure.
  497. //
  498. InitializeSListHead(&Lookaside->L.ListHead);
  499. Lookaside->L.Depth = MINIMUM_LOOKASIDE_DEPTH;
  500. Lookaside->L.MaximumDepth = 256; //Depth;
  501. Lookaside->L.TotalAllocates = 0;
  502. Lookaside->L.AllocateMisses = 0;
  503. Lookaside->L.TotalFrees = 0;
  504. Lookaside->L.FreeMisses = 0;
  505. Lookaside->L.Type = PagedPool | Flags;
  506. Lookaside->L.Tag = Tag;
  507. Lookaside->L.Size = (ULONG)Size;
  508. if (Allocate == NULL) {
  509. Lookaside->L.Allocate = ExAllocatePoolWithTag;
  510. } else {
  511. Lookaside->L.Allocate = Allocate;
  512. }
  513. if (Free == NULL) {
  514. Lookaside->L.Free = ExFreePool;
  515. } else {
  516. Lookaside->L.Free = Free;
  517. }
  518. Lookaside->L.LastTotalAllocates = 0;
  519. Lookaside->L.LastAllocateMisses = 0;
  520. //
  521. // For IA-64 we have to correctly initialize the region field in the S-list.
  522. // This might be in a different region than the head of the S-list. We get
  523. // correct one by doing a allocation to getting the region and then saving it.
  524. //
  525. #ifdef _IA64_
  526. Entry = (Lookaside->L.Allocate)(Lookaside->L.Type,
  527. Lookaside->L.Size,
  528. Lookaside->L.Tag);
  529. if (Entry != NULL) {
  530. Lookaside->L.ListHead.Region = (ULONG_PTR)Entry & VRN_MASK;
  531. //
  532. // Free the memory.
  533. //
  534. (Lookaside->L.Free)(Entry);
  535. }
  536. #endif
  537. //
  538. // Insert the lookaside list structure in the system paged lookaside
  539. // list.
  540. //
  541. ExInterlockedInsertTailList(&ExPagedLookasideListHead,
  542. &Lookaside->L.ListEntry,
  543. &ExPagedLookasideLock);
  544. return;
  545. }
  546. VOID
  547. ExDeletePagedLookasideList (
  548. IN PPAGED_LOOKASIDE_LIST Lookaside
  549. )
  550. /*++
  551. Routine Description:
  552. This function removes a paged lookaside structure from the system paged
  553. lookaside list and frees any entries specified by the lookaside structure.
  554. Arguments:
  555. Lookaside - Supplies a pointer to a paged lookaside list structure.
  556. Return Value:
  557. None.
  558. --*/
  559. {
  560. PVOID Entry;
  561. KIRQL OldIrql;
  562. //
  563. // Acquire the paged system lookaside list lock and remove the
  564. // specified lookaside list structure from the list.
  565. //
  566. ExAcquireSpinLock(&ExPagedLookasideLock, &OldIrql);
  567. RemoveEntryList(&Lookaside->L.ListEntry);
  568. ExReleaseSpinLock(&ExPagedLookasideLock, OldIrql);
  569. //
  570. // Remove all pool entries from the specified lookaside structure
  571. // and free them.
  572. //
  573. Lookaside->L.Allocate = ExpDummyAllocate;
  574. while ((Entry = ExAllocateFromPagedLookasideList(Lookaside)) != NULL) {
  575. (Lookaside->L.Free)(Entry);
  576. }
  577. return;
  578. }
  579. PVOID
  580. ExpDummyAllocate (
  581. IN POOL_TYPE PoolType,
  582. IN SIZE_T NumberOfBytes,
  583. IN ULONG Tag
  584. )
  585. /*++
  586. Routine Description:
  587. This function is a dummy allocation routine which is used to empty
  588. a lookaside list.
  589. Arguments:
  590. PoolType - Supplies the type of pool to allocate.
  591. NumberOfBytes - supplies the number of bytes to allocate.
  592. Tag - supplies the pool tag.
  593. Return Value:
  594. NULL is returned as the function value.
  595. --*/
  596. {
  597. UNREFERENCED_PARAMETER (PoolType);
  598. UNREFERENCED_PARAMETER (NumberOfBytes);
  599. UNREFERENCED_PARAMETER (Tag);
  600. return NULL;
  601. }