Leaked source code of windows server 2003
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.

868 lines
21 KiB

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