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.

1684 lines
39 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. pidle.c
  5. Abstract:
  6. This module implements processor idle functionality
  7. Author:
  8. Ken Reneris (kenr) 17-Jan-1997
  9. Revision History:
  10. --*/
  11. #include "pop.h"
  12. #if DBG
  13. #define IDLE_DEBUG_TABLE_SIZE 400
  14. ULONGLONG ST[IDLE_DEBUG_TABLE_SIZE];
  15. ULONGLONG ET[IDLE_DEBUG_TABLE_SIZE];
  16. ULONGLONG TD[IDLE_DEBUG_TABLE_SIZE];
  17. #endif
  18. VOID
  19. PopPromoteFromIdle0 (
  20. IN PPROCESSOR_POWER_STATE PState,
  21. IN PKTHREAD Thread
  22. );
  23. VOID
  24. FASTCALL
  25. PopDemoteIdleness (
  26. IN PPROCESSOR_POWER_STATE PState,
  27. IN PPOP_IDLE_HANDLER IdleState
  28. );
  29. VOID
  30. FASTCALL
  31. PopPromoteIdleness (
  32. IN PPROCESSOR_POWER_STATE PState,
  33. IN PPOP_IDLE_HANDLER IdleState
  34. );
  35. VOID
  36. FASTCALL
  37. PopIdle0 (
  38. IN PPROCESSOR_POWER_STATE PState
  39. );
  40. VOID
  41. PopConvertUsToPerfCount (
  42. IN OUT PULONG UsTime
  43. );
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text(INIT, PoInitializePrcb)
  46. #pragma alloc_text(PAGE, PopInitProcessorStateHandlers)
  47. #pragma alloc_text(PAGE, PopInitProcessorStateHandlers2)
  48. #endif
  49. #if defined(i386) && !defined(NT_UP)
  50. PPROCESSOR_IDLE_FUNCTION PopIdle0Function = PopIdle0;
  51. VOID
  52. FASTCALL
  53. PopIdle0SMT (
  54. IN PPROCESSOR_POWER_STATE PState
  55. );
  56. //
  57. // PopIdle0Function is a pointer to Idle0 function.
  58. //
  59. #if 0
  60. VOID
  61. (FASTCALL *PopIdle0Function) (
  62. IN PPROCESSOR_POWER_STATE PState
  63. ) = PopIdle0;
  64. #endif
  65. #else
  66. #define PopIdle0Function PopIdle0
  67. #endif
  68. VOID
  69. FASTCALL
  70. PoInitializePrcb (
  71. PKPRCB Prcb
  72. )
  73. /*++
  74. Routine Description:
  75. Initialize PowerState structure within processor's Prcb
  76. before it enters the idle loop
  77. Arguments:
  78. Prcb Prcb for current processor which is initializing
  79. Return Value:
  80. None.
  81. --*/
  82. {
  83. //
  84. // Zero power state structure
  85. //
  86. RtlZeroMemory(&Prcb->PowerState, sizeof(Prcb->PowerState));
  87. //
  88. // Initialize to legacy function with promotion from it disabled
  89. //
  90. Prcb->PowerState.Idle0KernelTimeLimit = (ULONG) -1;
  91. Prcb->PowerState.IdleFunction = PopIdle0;
  92. Prcb->PowerState.CurrentThrottle = POP_PERF_SCALE;
  93. //
  94. // Initialize the adaptive throttling subcomponents
  95. //
  96. KeInitializeDpc(
  97. &(Prcb->PowerState.PerfDpc),
  98. PopPerfIdleDpc,
  99. Prcb
  100. );
  101. KeSetTargetProcessorDpc(
  102. &(Prcb->PowerState.PerfDpc),
  103. Prcb->Number
  104. );
  105. KeInitializeTimer(
  106. (PKTIMER) &(Prcb->PowerState.PerfTimer)
  107. );
  108. }
  109. VOID
  110. PopInitProcessorStateHandlers (
  111. IN PPROCESSOR_STATE_HANDLER InputBuffer
  112. )
  113. /*++
  114. Routine Description:
  115. Install processor state handlers. This routine simply translates the old-style
  116. PROCESSOR_STATE_HANDLER structure into a new-style PROCESSOR_STATE_HANDLER2
  117. structure and calls PopInitProcessorStateHandlers2
  118. Arguments:
  119. InputBuffer - Handlers
  120. Return Value:
  121. None.
  122. --*/
  123. {
  124. PPROCESSOR_STATE_HANDLER StateHandler1 = (PPROCESSOR_STATE_HANDLER)InputBuffer;
  125. PPROCESSOR_STATE_HANDLER2 StateHandler2;
  126. UCHAR PerfStates;
  127. ULONG i;
  128. UCHAR Frequency;
  129. //
  130. // Allocate a buffer large enough to hold the larger structure
  131. //
  132. if (StateHandler1->ThrottleScale > 1) {
  133. PerfStates = StateHandler1->ThrottleScale;
  134. } else {
  135. PerfStates = 0;
  136. }
  137. StateHandler2 = ExAllocatePoolWithTag(PagedPool,
  138. sizeof(PROCESSOR_STATE_HANDLER2) +
  139. sizeof(PROCESSOR_PERF_LEVEL) * (PerfStates-1),
  140. 'dHoP');
  141. if (!StateHandler2) {
  142. ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
  143. }
  144. StateHandler2->NumPerfStates = PerfStates;
  145. //
  146. // Fill in common information
  147. //
  148. StateHandler2->NumIdleHandlers = StateHandler1->NumIdleHandlers;
  149. for (i=0;i<MAX_IDLE_HANDLERS;i++) {
  150. StateHandler2->IdleHandler[i] = StateHandler1->IdleHandler[i];
  151. }
  152. //
  153. // Install our thunk that converts between the old and the new throttling
  154. // interfaces
  155. //
  156. PopRealSetThrottle = StateHandler1->SetThrottle;
  157. PopThunkThrottleScale = StateHandler1->ThrottleScale;
  158. StateHandler2->SetPerfLevel = PopThunkSetThrottle;
  159. StateHandler2->HardwareLatency = 0;
  160. //
  161. // Generate a perf level handler for each throttle step.
  162. //
  163. for (i=0; i<StateHandler2->NumPerfStates;i++) {
  164. Frequency = (UCHAR)((PerfStates-i)*POP_PERF_SCALE/PerfStates);
  165. StateHandler2->PerfLevel[i].PercentFrequency = Frequency;
  166. }
  167. //
  168. // We have built up our table, call off to PopInitProcessorStateHandlers2 for the rest
  169. // of the work. Note that this can raise an exception if there is an error.
  170. //
  171. try {
  172. PopInitProcessorStateHandlers2(StateHandler2);
  173. } finally {
  174. ExFreePool(StateHandler2);
  175. }
  176. }
  177. VOID
  178. PopInitProcessorStateHandlers2 (
  179. IN PPROCESSOR_STATE_HANDLER2 InputBuffer
  180. )
  181. /*++
  182. Routine Description:
  183. Install processor state handlers
  184. Arguments:
  185. InputBuffer - Handlers
  186. Return Value:
  187. None.
  188. --*/
  189. {
  190. PPROCESSOR_STATE_HANDLER2 processorHandler;
  191. ULONG last;
  192. ULONG i;
  193. ULONG j;
  194. ULONG max;
  195. POP_IDLE_HANDLER newIdle[MAX_IDLE_HANDLERS];
  196. POP_IDLE_HANDLER tempIdle[MAX_IDLE_HANDLERS];
  197. NTSTATUS status;
  198. processorHandler = (PPROCESSOR_STATE_HANDLER2) InputBuffer;
  199. //
  200. // Install processor throttle support if present
  201. //
  202. status = PopSetPerfLevels(processorHandler);
  203. if (!NT_SUCCESS(status)) {
  204. ExRaiseStatus(status);
  205. }
  206. //
  207. // If there aren't any idle handlers, then we must deregister the old
  208. // handlers (if any)
  209. //
  210. if ((KeNumberProcessors > 1 && processorHandler->NumIdleHandlers < 1) ||
  211. (KeNumberProcessors == 1 && processorHandler->NumIdleHandlers <= 1)) {
  212. //
  213. // Use NULL and 0 to indicate the number of elements...
  214. //
  215. PopIdleSwitchIdleHandlers( NULL, 0 );
  216. return;
  217. }
  218. //
  219. // Get ready to build a set of idle state handlers
  220. //
  221. RtlZeroMemory(newIdle, sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLERS );
  222. RtlZeroMemory(tempIdle, sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLERS );
  223. //
  224. // We don't support more than 3 handlers ...
  225. //
  226. max = processorHandler->NumIdleHandlers;
  227. if (max > MAX_IDLE_HANDLERS) {
  228. max = MAX_IDLE_HANDLERS;
  229. }
  230. //
  231. // Look at all the handlers provided to us...
  232. //
  233. for (last = i = 0; i < max; i++) {
  234. //
  235. // Ensure they were passed in ascending order
  236. //
  237. j = processorHandler->IdleHandler[i].HardwareLatency;
  238. ASSERT (j >= last && j <= 1000);
  239. last = j;
  240. //
  241. // Fill in some defaults
  242. //
  243. tempIdle[i].State = (UCHAR) i;
  244. tempIdle[i].IdleFunction= processorHandler->IdleHandler[i].Handler;
  245. tempIdle[i].Latency = j;
  246. //
  247. // Convert latency to perf rate scale
  248. //
  249. PopConvertUsToPerfCount(&tempIdle[i].Latency);
  250. }
  251. //
  252. // Apply policy to this set of states
  253. //
  254. status = PopIdleUpdateIdleHandler( newIdle, tempIdle, max );
  255. ASSERT( NT_SUCCESS( status ) );
  256. if (!NT_SUCCESS( status ) ) {
  257. return;
  258. }
  259. //
  260. // Initialize each processors idle info to start idle savings
  261. //
  262. PopIdleSwitchIdleHandlers( newIdle, max );
  263. }
  264. NTSTATUS
  265. PopIdleSwitchIdleHandler(
  266. IN PPOP_IDLE_HANDLER NewHandler,
  267. IN ULONG NumElements
  268. )
  269. /*++
  270. Routine Description:
  271. This routine is responsible for switching the idle handler on the
  272. current processor for the specified new one.
  273. N.B. This function is only callable at DISPATCH_LEVEL
  274. Arguments:
  275. NewHandler - Pointer to new handlers
  276. NumElements - Number of elements in the array
  277. Return Value:
  278. NTSTATUS
  279. --*/
  280. {
  281. PKPRCB prcb;
  282. PKTHREAD thread;
  283. PPROCESSOR_POWER_STATE pState;
  284. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  285. //
  286. // We need to know where the following data structures are
  287. //
  288. prcb = KeGetCurrentPrcb();
  289. pState = &(prcb->PowerState);
  290. thread = prcb->IdleThread;
  291. //
  292. // Update the current IdleHandler and IdleState to reflect what was
  293. // given to us
  294. //
  295. pState->IdleState = NewHandler;
  296. pState->IdleHandlers = NewHandler;
  297. pState->IdleHandlersCount = NumElements;
  298. if ( NewHandler) {
  299. //
  300. // Reset the timers to indicate that there is an idle handler
  301. // available
  302. //
  303. pState->Idle0KernelTimeLimit = thread->KernelTime + PopIdle0PromoteTicks;
  304. pState->Idle0LastTime = thread->KernelTime + thread->UserTime;
  305. pState->PromotionCheck = NewHandler[0].PromoteCount;
  306. } else {
  307. //
  308. // Setting these to Zero should indicate that there are no idle
  309. // handlers available
  310. //
  311. pState->Idle0KernelTimeLimit = (ULONG) -1;
  312. pState->Idle0LastTime = 0;
  313. pState->PromotionCheck = 0;
  314. pState->IdleFunction = PopIdle0Function;
  315. }
  316. #if defined(i386) && !defined(NT_UP)
  317. if (prcb->MultiThreadProcessorSet != prcb->SetMember) {
  318. //
  319. // This processor is a member of a simultaneous
  320. // multi threading processor set. Use the SMT
  321. // version of PopIdle0.
  322. //
  323. PopIdle0Function = PopIdle0SMT;
  324. pState->IdleFunction = PopIdle0SMT;
  325. }
  326. #endif
  327. //
  328. // Success
  329. //
  330. return STATUS_SUCCESS;
  331. }
  332. NTSTATUS
  333. PopIdleSwitchIdleHandlers(
  334. IN PPOP_IDLE_HANDLER NewHandler,
  335. IN ULONG NumElements
  336. )
  337. /*++
  338. Routine Description:
  339. This routine is responsible for swapping each processor's idle handler
  340. routine for a new one....
  341. Arguments:
  342. NewHandler - Pointer to the array of new handlers
  343. NumElements - Number of elements in the array
  344. Return Value:
  345. STATUS_SUCCESS
  346. STATUS_INSUFICCIENT_RESOURCES
  347. --*/
  348. {
  349. KAFFINITY currentAffinity;
  350. KAFFINITY processors;
  351. KIRQL oldIrql;
  352. NTSTATUS status = STATUS_SUCCESS;
  353. PPOP_IDLE_HANDLER tempHandler = NULL;
  354. ASSERT( NumElements <= MAX_IDLE_HANDLER );
  355. if (NewHandler) {
  356. //
  357. // Step 1. Allocate a new set of handlers to hold the copy that we
  358. // will need to keep around
  359. //
  360. tempHandler = ExAllocateFromNPagedLookasideList(
  361. &PopIdleHandlerLookAsideList
  362. );
  363. if (tempHandler == NULL) {
  364. status = STATUS_INSUFFICIENT_RESOURCES;
  365. return status;
  366. }
  367. //
  368. // Step 2. Make sure that this new handler is in a consistent state,
  369. // and copy the buffer that was passed to us
  370. //
  371. RtlZeroMemory(
  372. tempHandler,
  373. sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLER
  374. );
  375. RtlCopyMemory(
  376. tempHandler,
  377. NewHandler,
  378. sizeof(POP_IDLE_HANDLER) * NumElements
  379. );
  380. } else {
  381. tempHandler = NULL;
  382. }
  383. //
  384. // Step 3. Iterate over the processors
  385. //
  386. currentAffinity = 1;
  387. processors = KeActiveProcessors;
  388. while (processors) {
  389. if (!(currentAffinity & processors)) {
  390. currentAffinity <<= 1;
  391. continue;
  392. }
  393. KeSetSystemAffinityThread( currentAffinity );
  394. processors &= ~currentAffinity;
  395. currentAffinity <<= 1;
  396. //
  397. // Step 4. Swap out old handler. Indicate that we want to free it
  398. //
  399. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  400. PopIdleSwitchIdleHandler( tempHandler, NumElements );
  401. KeLowerIrql(oldIrql);
  402. }
  403. //
  404. // Step 5. At this point, all of the processors should have been updated
  405. // and we are still running on the "last" processor in the machine. This
  406. // is a good point to update PopIdle to point to the new value. Note that
  407. // PopIdle isn't actually used for any else than storing a pointer to
  408. // the handler, but if there was something there already, then it should
  409. // be freed
  410. //
  411. if (PopIdle != NULL) {
  412. ExFreeToNPagedLookasideList(
  413. &PopIdleHandlerLookAsideList,
  414. PopIdle
  415. );
  416. }
  417. PopIdle = tempHandler;
  418. //
  419. // Step 6. At this point, its safe to return to the original processor
  420. // and to back to the previous IRQL...
  421. //
  422. KeRevertToUserAffinityThread();
  423. //
  424. // Done
  425. //
  426. return status;
  427. }
  428. NTSTATUS
  429. PopIdleUpdateIdleHandler(
  430. IN PPOP_IDLE_HANDLER NewHandler,
  431. IN PPOP_IDLE_HANDLER OldHandler,
  432. IN ULONG NumElements
  433. )
  434. /*++
  435. Routine Description:
  436. This routine takes the information stored in OldHandler (such as latency,
  437. and IdleFunction) and uses that to build the new idle handlers...
  438. Arguements:
  439. NewHandler - pointer to the new idle handlers
  440. OldHandler - pointer to the old idle handlers
  441. NumElements - number of elements in the old idle handlers
  442. Return Value:
  443. NTSTATUS
  444. --*/
  445. {
  446. NTSTATUS status;
  447. ULONG i;
  448. ULONG max;
  449. ULONG realMax;
  450. //
  451. // We don't support more than 3 handlers ...
  452. //
  453. realMax = max = NumElements;
  454. if (max > MAX_IDLE_HANDLERS) {
  455. realMax = max = MAX_IDLE_HANDLERS;
  456. }
  457. //
  458. // Cap the max based upon what the policy supports
  459. //
  460. if (max > PopProcessorPolicy->PolicyCount) {
  461. max = PopProcessorPolicy->PolicyCount;
  462. }
  463. //
  464. // Update the temp handler with the new policy
  465. //
  466. for (i = 0; i < max; i++) {
  467. NewHandler[i].State = (UCHAR) i;
  468. NewHandler[i].Latency = OldHandler[i].Latency;
  469. NewHandler[i].IdleFunction = OldHandler[i].IdleFunction;
  470. NewHandler[i].TimeCheck = PopProcessorPolicy->Policy[i].TimeCheck;
  471. NewHandler[i].PromoteLimit = PopProcessorPolicy->Policy[i].PromoteLimit;
  472. NewHandler[i].PromotePercent= PopProcessorPolicy->Policy[i].PromotePercent;
  473. NewHandler[i].DemoteLimit = PopProcessorPolicy->Policy[i].DemoteLimit;
  474. NewHandler[i].DemotePercent = PopProcessorPolicy->Policy[i].DemotePercent;
  475. //
  476. // Convert all the time units to the correct units
  477. //
  478. PopConvertUsToPerfCount(&NewHandler[i].TimeCheck);
  479. PopConvertUsToPerfCount(&NewHandler[i].DemoteLimit);
  480. PopConvertUsToPerfCount(&NewHandler[i].PromoteLimit);
  481. //
  482. // Fill in the table that allows for promotion / demotion
  483. //
  484. if (PopProcessorPolicy->Policy[i].AllowDemotion) {
  485. NewHandler[i].Demote = (UCHAR) i-1;
  486. } else {
  487. NewHandler[i].Demote = (UCHAR) i;
  488. }
  489. if (PopProcessorPolicy->Policy[i].AllowPromotion) {
  490. NewHandler[i].Promote = (UCHAR) i+1;
  491. } else {
  492. NewHandler[i].Promote = (UCHAR) i;
  493. }
  494. }
  495. //
  496. // Make sure that the boundary cases are well respected...
  497. //
  498. NewHandler[0].Demote = 0;
  499. NewHandler[(max-1)].Promote = (UCHAR) (max-1);
  500. //
  501. // We let PopVerifyHandler fill in all the details associated with
  502. // the fact that we don't want to allow demotion/promotion from these
  503. // states
  504. //
  505. NewHandler[0].DemotePercent = 0;
  506. NewHandler[(max-1)].PromotePercent = 0;
  507. //
  508. // Handle the states that we don't have a policy handler in place for
  509. //
  510. for (; i < realMax; i++) {
  511. //
  512. // The only pieces of data that we really need are the latency and the
  513. // idle handler function
  514. //
  515. NewHandler[i].State = (UCHAR) i;
  516. NewHandler[i].Latency = OldHandler[i].Latency;
  517. NewHandler[i].IdleFunction = OldHandler[i].IdleFunction;
  518. }
  519. //
  520. // Sanity check the new handler
  521. //
  522. status = PopIdleVerifyIdleHandlers( NewHandler, max );
  523. ASSERT( NT_SUCCESS( status ) );
  524. return status;
  525. }
  526. NTSTATUS
  527. PopIdleUpdateIdleHandlers(
  528. VOID
  529. )
  530. /*++
  531. Routine Description:
  532. This routine is called to update the idle handlers when the state of the
  533. machine warrants a possible change in policy
  534. Arguments:
  535. None
  536. Return Value:
  537. NTSTATUS
  538. --*/
  539. {
  540. BOOLEAN foundProcessor = FALSE;
  541. KAFFINITY currentAffinity;
  542. KAFFINITY processors;
  543. KIRQL oldIrql;
  544. NTSTATUS status = STATUS_SUCCESS;
  545. PKPRCB prcb;
  546. PPOP_IDLE_HANDLER tempHandler = NULL;
  547. PPROCESSOR_POWER_STATE pState;
  548. ULONG numElements;
  549. //
  550. // Step 1. Allocate a new set of handlers to hold the copy that we
  551. // will need to keep around
  552. //
  553. tempHandler = ExAllocateFromNPagedLookasideList(
  554. &PopIdleHandlerLookAsideList
  555. );
  556. if (tempHandler == NULL) {
  557. return STATUS_INSUFFICIENT_RESOURCES;
  558. }
  559. RtlZeroMemory(
  560. tempHandler,
  561. sizeof(POP_IDLE_HANDLER) * MAX_IDLE_HANDLER
  562. );
  563. //
  564. // Step 2. Iterate over the processors
  565. //
  566. currentAffinity = 1;
  567. processors = KeActiveProcessors;
  568. while (processors) {
  569. if (!(currentAffinity & processors)) {
  570. currentAffinity <<= 1;
  571. continue;
  572. }
  573. KeSetSystemAffinityThread( currentAffinity );
  574. processors &= ~currentAffinity;
  575. currentAffinity <<= 1;
  576. //
  577. // Can't look at the processors without being at DPC level
  578. //
  579. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  580. //
  581. // We need to find a template to get the processor info from
  582. //
  583. if (!foundProcessor) {
  584. //
  585. // Step 3. If we haven't already found a processor so that we
  586. // create a new idle handler, then do so now. Note that it is
  587. // possible that this processor has no mask, in which case we
  588. // should clean up and return.
  589. //
  590. // N.B. That it is still safe to return at this point since
  591. // we haven't touch a single processor's data structures, so
  592. // we are in no danger of corrupting something...
  593. //
  594. prcb = KeGetCurrentPrcb();
  595. pState = &(prcb->PowerState);
  596. if (pState->IdleHandlers == NULL) {
  597. //
  598. // No idle handlers to update
  599. //
  600. ExFreeToNPagedLookasideList(
  601. &PopIdleHandlerLookAsideList,
  602. tempHandler
  603. );
  604. KeLowerIrql( oldIrql );
  605. KeRevertToUserAffinityThread();
  606. return STATUS_SUCCESS;
  607. }
  608. numElements = pState->IdleHandlersCount;
  609. //
  610. // Update the temp handler with the new policy
  611. //
  612. status = PopIdleUpdateIdleHandler(
  613. tempHandler,
  614. pState->IdleHandlers,
  615. numElements
  616. );
  617. ASSERT( NT_SUCCESS( status ) );
  618. if (!NT_SUCCESS( status ) ) {
  619. //
  620. // No idle handlers to update
  621. //
  622. ExFreeToNPagedLookasideList(
  623. &PopIdleHandlerLookAsideList,
  624. tempHandler
  625. );
  626. KeLowerIrql( oldIrql );
  627. KeRevertToUserAffinityThread();
  628. return status;
  629. }
  630. //
  631. // Remember that we have found the processor information
  632. //
  633. foundProcessor = TRUE;
  634. }
  635. //
  636. // Step 4. Swap out old handler. Indicate that we want to free it
  637. //
  638. PopIdleSwitchIdleHandler( tempHandler, numElements );
  639. //
  640. // Revert back to original irql
  641. //
  642. KeLowerIrql(oldIrql);
  643. }
  644. //
  645. // Step 5. At this point, all of the processors should have been updated
  646. // and we are still running on the "last" processor in the machine. This
  647. // is a good point to update PopIdle to point to the new value. Note that
  648. // PopIdle isn't actually used for any else than storing a pointer to
  649. // the handler, but if there was something there already, then it should
  650. // be freed
  651. //
  652. if (PopIdle != NULL) {
  653. ExFreeToNPagedLookasideList(
  654. &PopIdleHandlerLookAsideList,
  655. PopIdle
  656. );
  657. }
  658. PopIdle = tempHandler;
  659. //
  660. // Step 6. At this point, its safe to return to the original processor.
  661. //
  662. KeRevertToUserAffinityThread();
  663. //
  664. // Done
  665. //
  666. return status;
  667. }
  668. NTSTATUS
  669. PopIdleVerifyIdleHandlers(
  670. IN PPOP_IDLE_HANDLER NewHandler,
  671. IN ULONG NumElements
  672. )
  673. /*++
  674. Routine Description:
  675. This routine is called to sanity check a set of idle handlers. It will
  676. correct the errors (if it can) or return a failure code (if it cannot)
  677. Arguments:
  678. NewHandler - Array of Handlers
  679. NumElements - Number of Elements in the Array to actually verify. This
  680. may be smaller than the actual number of elements in the
  681. array
  682. Return Value:
  683. NTSTATUS
  684. --*/
  685. {
  686. ULONG i;
  687. //
  688. // Sanity Check
  689. //
  690. ASSERT( NewHandler != NULL );
  691. ASSERT( NumElements );
  692. //
  693. // Sanity check rules of multi-processors. We don't allow demotion from
  694. // Idle0 unless the machine is MP
  695. //
  696. if (KeNumberProcessors == 1 && NewHandler[0].DemotePercent != 0) {
  697. NewHandler[0].DemotePercent = 0;
  698. }
  699. //
  700. // Sanity check the other rules for the first state...
  701. //
  702. if (NewHandler[0].Demote != 0) {
  703. NewHandler[0].Demote = 0;
  704. }
  705. //
  706. // Sanity check idle values. These numbers are stored in the policy
  707. // as MicroSeconds, we need to take the opportunity to convert them to
  708. // PerfCount units...
  709. //
  710. for (i = 0; i < NumElements; i++) {
  711. //
  712. // TimeCheck must be in units of Demotion time check
  713. //
  714. if (NewHandler[i].TimeCheck < NewHandler[i].DemoteLimit) {
  715. NewHandler[i].TimeCheck = NewHandler[i].DemoteLimit;
  716. }
  717. //
  718. // If there's no demotion then use promotion time check
  719. //
  720. if (NewHandler[i].DemotePercent == 0 &&
  721. NewHandler[i].TimeCheck < NewHandler[i].PromoteLimit) {
  722. NewHandler[i].TimeCheck = NewHandler[i].PromoteLimit;
  723. }
  724. //
  725. // TimeCheck must be in units of Promotion time check
  726. //
  727. if (NewHandler[i].DemotePercent) {
  728. NewHandler[i].DemoteLimit =
  729. NewHandler[i].TimeCheck * NewHandler[i].DemotePercent / 100;
  730. } else {
  731. NewHandler[i].DemoteLimit = 0;
  732. }
  733. //
  734. // Compute promote count as # of time checks
  735. //
  736. NewHandler[i].PromoteCount =
  737. NewHandler[i].PromoteLimit / NewHandler[i].TimeCheck;
  738. //
  739. // Compute promote limit
  740. //
  741. if (NewHandler[i].PromotePercent) {
  742. NewHandler[i].PromoteLimit =
  743. NewHandler[i].PromoteLimit * NewHandler[i].PromotePercent / 100;
  744. } else {
  745. NewHandler[i].PromoteCount = (ULONG) -1;
  746. NewHandler[i].PromoteLimit = (ULONG) -1;
  747. }
  748. }
  749. //
  750. // Sanity check the last state
  751. //
  752. i = NumElements - 1;
  753. NewHandler[i].Promote = (UCHAR) i;
  754. NewHandler[i].PromoteLimit = (ULONG) -1;
  755. NewHandler[i].PromotePercent = 0;
  756. //
  757. // We are happy with this policy...
  758. //
  759. return STATUS_SUCCESS;
  760. }
  761. VOID
  762. PopConvertUsToPerfCount (
  763. IN OUT PULONG UsTime
  764. )
  765. {
  766. LARGE_INTEGER li;
  767. LONGLONG temp;
  768. if (*UsTime) {
  769. //
  770. // Try to avoid Divide by Zero Errors...
  771. //
  772. temp = (US2SEC * MAXSECCHECK * 100L) / *UsTime;
  773. if (!temp) {
  774. *UsTime = (ULONG) -1;
  775. return;
  776. }
  777. //
  778. // Get scale of idle times
  779. //
  780. KeQueryPerformanceCounter (&li);
  781. li.QuadPart = (li.QuadPart*MAXSECCHECK*100L) / temp;
  782. ASSERT (li.HighPart == 0);
  783. *UsTime = li.LowPart;
  784. }
  785. }
  786. //
  787. // ----------------
  788. //
  789. VOID
  790. FASTCALL
  791. PopIdle0 (
  792. IN PPROCESSOR_POWER_STATE PState
  793. )
  794. /*++
  795. Routine Description:
  796. No idle optmiziations.
  797. N.B. This function is called with interrupts disabled from the idle loop
  798. Arguments:
  799. PState - Current processors power state structure
  800. Return Value:
  801. None.
  802. --*/
  803. {
  804. PKTHREAD Thread = KeGetCurrentThread();
  805. //
  806. // Performance Throttling Check
  807. //
  808. //
  809. // This piece of code really belongs in the functions that will eventually
  810. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  811. //
  812. if ( (PState->Flags & PSTATE_ADAPTIVE_THROTTLE) &&
  813. !(PState->Flags & PSTATE_DISABLE_THROTTLE) ) {
  814. PopPerfIdle( PState );
  815. }
  816. //
  817. // If the idle thread's kernel time has exceeded the target idle time, then
  818. // check for possible promotion from Idle0
  819. //
  820. if (Thread->KernelTime > PState->Idle0KernelTimeLimit) {
  821. //
  822. // Must enable interrupts prior to calling PopPromoteFromIdle
  823. // to avoid spinning on system locks with interrupts disabled.
  824. //
  825. _enable();
  826. PopPromoteFromIdle0 (PState, Thread);
  827. return ;
  828. }
  829. #if defined(NT_UP)
  830. // use legacy function
  831. HalProcessorIdle ();
  832. #endif
  833. }
  834. #if defined(i386) && !defined(NT_UP)
  835. VOID
  836. FASTCALL
  837. PopIdle0SMT (
  838. IN PPROCESSOR_POWER_STATE PState
  839. )
  840. /*++
  841. Routine Description:
  842. No idle optmiziations.
  843. N.B. This function is called with interrupts disabled from the idle loop
  844. Arguments:
  845. PState - Current processors power state structure
  846. Return Value:
  847. None.
  848. --*/
  849. {
  850. PKTHREAD Thread = KeGetCurrentThread();
  851. PKPRCB Prcb = KeGetCurrentPrcb();
  852. //
  853. // Performance Throttling Check
  854. //
  855. //
  856. // This piece of code really belongs in the functions that will eventually
  857. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  858. //
  859. if ( (PState->Flags & PSTATE_ADAPTIVE_THROTTLE) &&
  860. !(PState->Flags & PSTATE_DISABLE_THROTTLE) ) {
  861. PopPerfIdle( PState );
  862. }
  863. //
  864. // If this is a Simultaneous Multi Threading processor and other
  865. // processors in this set are NOT idle, promote this processor
  866. // immediately OR if the idle thread's kernel time has exceeded
  867. // the target idle time, then check for possible promotion from Idle0.
  868. //
  869. if ((Prcb->MultiThreadSetMaster->MultiThreadSetBusy != FALSE) ||
  870. (Thread->KernelTime > PState->Idle0KernelTimeLimit)) {
  871. //
  872. // Must enable interrupts prior to calling PopPromoteFromIdle
  873. // to avoid spinning on system locks with interrupts disabled.
  874. //
  875. _enable();
  876. PopPromoteFromIdle0 (PState, Thread);
  877. return ;
  878. }
  879. }
  880. #endif
  881. VOID
  882. FASTCALL
  883. PopProcessorIdle (
  884. IN PPROCESSOR_POWER_STATE PState
  885. )
  886. /*++
  887. Routine Description:
  888. For now this function is coded in C
  889. N.B. This function is called with interrupts disabled from the idle loop
  890. Arguments:
  891. PState - Current processors power state structure
  892. Return Value:
  893. None.
  894. --*/
  895. {
  896. PPOP_IDLE_HANDLER IdleState;
  897. LARGE_INTEGER Delta;
  898. ULONG IdleTime;
  899. BOOLEAN DemoteNow;
  900. IdleState = (PPOP_IDLE_HANDLER) PState->IdleState;
  901. //
  902. // Performance Throttling Check
  903. //
  904. //
  905. // This piece of code really belongs in the functions that will eventually
  906. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  907. //
  908. if ( (PState->Flags & PSTATE_ADAPTIVE_THROTTLE) &&
  909. !(PState->Flags & PSTATE_DISABLE_THROTTLE) ) {
  910. PopPerfIdle( PState );
  911. }
  912. #if DBG
  913. if (!PState->LastCheck) {
  914. IdleState->IdleFunction (&PState->IdleTimes);
  915. PState->TotalIdleStateTime[IdleState->State] += (ULONG)(PState->IdleTimes.EndTime - PState->IdleTimes.StartTime);
  916. PState->TotalIdleTransitions[IdleState->State] += 1;
  917. PState->LastCheck = PState->IdleTimes.EndTime;
  918. PState->IdleTime1 = 0;
  919. PState->IdleTime2 = 0;
  920. PState->PromotionCheck = IdleState->PromoteCount;
  921. PState->DebugCount = 0;
  922. return ;
  923. }
  924. #endif
  925. //
  926. // Determine how long since last check
  927. //
  928. Delta.QuadPart = PState->IdleTimes.EndTime - PState->LastCheck;
  929. //
  930. // Accumulate last idle time
  931. //
  932. IdleTime = (ULONG) (PState->IdleTimes.EndTime - PState->IdleTimes.StartTime);
  933. if (IdleTime > IdleState->Latency) {
  934. PState->IdleTime1 += IdleTime - IdleState->Latency;
  935. }
  936. #if DBG
  937. PState->DebugDelta = Delta.QuadPart;
  938. PState->DebugCount += 1;
  939. if (PState->DebugCount < IDLE_DEBUG_TABLE_SIZE) {
  940. ST[PState->DebugCount] = PState->IdleTimes.StartTime;
  941. ET[PState->DebugCount] = PState->IdleTimes.EndTime;
  942. TD[PState->DebugCount] = PState->IdleTimes.EndTime - PState->IdleTimes.StartTime;
  943. }
  944. #endif
  945. //
  946. // If over check interval, check fine grain idleness
  947. //
  948. if (Delta.HighPart || Delta.LowPart > IdleState->TimeCheck) {
  949. PState->LastCheck = PState->IdleTimes.EndTime;
  950. //
  951. // Demote idleness?
  952. //
  953. if (PState->IdleTime1 < IdleState->DemoteLimit) {
  954. #if defined(i386) && !defined(NT_UP)
  955. //
  956. // Don't demote if this is an SMT processor and any other
  957. // member of the SMT set is not idle.
  958. //
  959. PKPRCB Prcb = KeGetCurrentPrcb();
  960. if ((Prcb->MultiThreadSetMaster->MultiThreadSetBusy) &&
  961. (Prcb->SetMember != Prcb->MultiThreadProcessorSet)) {
  962. PState->IdleTime1 = 0;
  963. return;
  964. }
  965. #endif
  966. PopDemoteIdleness (PState, IdleState);
  967. #if DBG
  968. PState->DebugCount = 0;
  969. #endif
  970. return ;
  971. }
  972. #if DBG
  973. PState->DebugCount = 0;
  974. #endif
  975. //
  976. // Clear demotion idle time check, and accumulate stat for promotion check
  977. //
  978. PState->IdleTime2 += PState->IdleTime1;
  979. PState->IdleTime1 = 0;
  980. //
  981. // Time to check for promotion?
  982. //
  983. PState->PromotionCheck -= 1;
  984. if (!PState->PromotionCheck) {
  985. //
  986. // Promote idleness?
  987. //
  988. if (PState->IdleTime2 > IdleState->PromoteLimit) {
  989. PopPromoteIdleness (PState, IdleState);
  990. return;
  991. }
  992. PState->PromotionCheck = IdleState->PromoteCount;
  993. PState->IdleTime2 = 0;
  994. }
  995. }
  996. //
  997. // Call system specific power handler handler
  998. //
  999. DemoteNow = IdleState->IdleFunction (&PState->IdleTimes);
  1000. //
  1001. // If the handler returns TRUE, then the demote to less power savings state
  1002. //
  1003. if (DemoteNow) {
  1004. PopDemoteIdleness (PState, IdleState);
  1005. #if DBG
  1006. PState->DebugCount = 0;
  1007. #endif
  1008. } else {
  1009. PState->TotalIdleStateTime[IdleState->State] += PState->IdleTimes.EndTime - PState->IdleTimes.StartTime;
  1010. PState->TotalIdleTransitions[IdleState->State] += 1;
  1011. }
  1012. }
  1013. VOID
  1014. FASTCALL
  1015. PopDemoteIdleness (
  1016. IN PPROCESSOR_POWER_STATE PState,
  1017. IN PPOP_IDLE_HANDLER IdleState
  1018. )
  1019. /*++
  1020. Routine Description:
  1021. Processor is not idle enough. Use a less agressive idle handler (or
  1022. increase processors throttle control).
  1023. Arguments:
  1024. PState - Current processors power state structure
  1025. IdleState - Current idle state for the current processor
  1026. Return Value:
  1027. None.
  1028. --*/
  1029. {
  1030. PKPRCB Prcb;
  1031. PKTHREAD Thread;
  1032. PPOP_IDLE_HANDLER Idle;
  1033. //
  1034. // Clear idleness for next check
  1035. //
  1036. PState->IdleTime1 = 0;
  1037. PState->IdleTime2 = 0;
  1038. PERFINFO_POWER_IDLE_STATE_CHANGE( PState, -1 );
  1039. #if !defined(NT_UP)
  1040. //
  1041. // If this is a demotion to the non-blocking idle handler then
  1042. // clear this processors bit in the PoSleepingSummary
  1043. //
  1044. if (IdleState->Demote == PO_IDLE_COMPLETE_DEMOTION) {
  1045. Prcb = CONTAINING_RECORD (PState, KPRCB, PowerState);
  1046. InterlockedAndAffinity (&PoSleepingSummary, ~Prcb->SetMember);
  1047. Thread = Prcb->IdleThread;
  1048. PState->Idle0KernelTimeLimit = Thread->KernelTime + PopIdle0PromoteTicks;
  1049. PState->Idle0LastTime = Prcb->KernelTime + Prcb->UserTime;
  1050. PState->IdleFunction = PopIdle0Function;
  1051. return ;
  1052. }
  1053. #endif
  1054. //
  1055. // Demote to next idle state
  1056. //
  1057. Idle = PState->IdleHandlers;
  1058. PState->PromotionCheck = Idle[IdleState->Demote].PromoteCount;
  1059. PState->IdleState = (PVOID) &Idle[IdleState->Demote];
  1060. }
  1061. VOID
  1062. PopPromoteFromIdle0 (
  1063. IN PPROCESSOR_POWER_STATE PState,
  1064. IN PKTHREAD Thread
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Processor is using Idle0 and the required idle time has elasped.
  1069. Check idle precentage to see if a promotion out of Idle0 should occur.
  1070. Arguments:
  1071. PState - Current processors power state structure
  1072. Thread - Idle thread for the current processor
  1073. Return Value:
  1074. None.
  1075. --*/
  1076. {
  1077. ULONG etime;
  1078. PKPRCB Prcb;
  1079. PPOP_IDLE_HANDLER Idle;
  1080. //
  1081. // Compute elapsed system time
  1082. //
  1083. Prcb = CONTAINING_RECORD (PState, KPRCB, PowerState);
  1084. etime = Prcb->UserTime + Prcb->KernelTime - PState->Idle0LastTime;
  1085. Idle = PState->IdleHandlers;
  1086. //
  1087. // Has the processor been idle enough to promote?
  1088. //
  1089. if (etime < PopIdle0PromoteLimit) {
  1090. KEVENT DummyEvent;
  1091. //
  1092. // Promote to the first real idle handler
  1093. //
  1094. PERFINFO_POWER_IDLE_STATE_CHANGE( PState, 0 );
  1095. PState->IdleTime1 = 0;
  1096. PState->IdleTime2 = 0;
  1097. PState->PromotionCheck = Idle[0].PromoteCount;
  1098. PState->IdleState = Idle;
  1099. PState->IdleFunction = PopProcessorIdle;
  1100. PState->LastCheck = KeQueryPerformanceCounter(NULL).QuadPart;
  1101. PState->IdleTimes.StartTime = PState->LastCheck;
  1102. PState->IdleTimes.EndTime = PState->LastCheck;
  1103. InterlockedOrAffinity (&PoSleepingSummary, Prcb->SetMember);
  1104. //
  1105. // Once SleepingSummary is set, make sure no one is in the
  1106. // middle of a context switch by aquiring & releasing the
  1107. // dispatcher database lock
  1108. //
  1109. KeInitializeEvent(&DummyEvent, SynchronizationEvent, TRUE);
  1110. KeResetEvent (&DummyEvent);
  1111. return ;
  1112. }
  1113. //
  1114. // Set for next compare
  1115. //
  1116. PState->Idle0KernelTimeLimit = Thread->KernelTime + PopIdle0PromoteTicks;
  1117. PState->Idle0LastTime = Prcb->UserTime + Prcb->KernelTime;
  1118. }
  1119. VOID
  1120. FASTCALL
  1121. PopPromoteIdleness (
  1122. IN PPROCESSOR_POWER_STATE PState,
  1123. IN PPOP_IDLE_HANDLER IdleState
  1124. )
  1125. /*++
  1126. Routine Description:
  1127. Processor is idle enough to be promoted to the next idle handler.
  1128. If the processor is already at its max idle handler, check to
  1129. see if the processors throttle control can be reduced. If any
  1130. processor is not running at it's best speed, a timer is used to
  1131. watch for some changes from idle to busy.
  1132. Arguments:
  1133. PState - Current processors power state structure
  1134. IdleState - Current idle state for the current processor
  1135. Return Value:
  1136. None.
  1137. --*/
  1138. {
  1139. LARGE_INTEGER DueTime;
  1140. PPOP_IDLE_HANDLER Idle;
  1141. //
  1142. // Clear idleness for next check
  1143. //
  1144. PState->IdleTime2 = 0;
  1145. PERFINFO_POWER_IDLE_STATE_CHANGE( PState, 1 );
  1146. //
  1147. // If already fully promoted, then nothing more to do.
  1148. //
  1149. if (IdleState->Promote == PO_IDLE_THROTTLE_PROMOTION) {
  1150. PState->PromotionCheck = IdleState->PromoteCount;
  1151. return;
  1152. }
  1153. //
  1154. // Promote to next idle state
  1155. //
  1156. Idle = PState->IdleHandlers;
  1157. PState->PromotionCheck = Idle[IdleState->Promote].PromoteCount;
  1158. PState->IdleState = (PVOID) &Idle[IdleState->Promote];
  1159. }
  1160. VOID
  1161. PopProcessorInformation (
  1162. OUT PPROCESSOR_POWER_INFORMATION ProcInfo,
  1163. IN ULONG ProcInfoLength,
  1164. OUT PULONG ReturnBufferLength
  1165. )
  1166. {
  1167. KAFFINITY Summary;
  1168. KAFFINITY Mask;
  1169. KIRQL OldIrql;
  1170. PPOP_IDLE_HANDLER IdleState;
  1171. PKPRCB Prcb;
  1172. PPROCESSOR_POWER_STATE PState;
  1173. PROCESSOR_POWER_INFORMATION TempInfo;
  1174. ULONG Processor;
  1175. ULONG MaxMhz;
  1176. ULONG BufferSize = 0;
  1177. ULONG MaxIdleState = 0;
  1178. ULONG i;
  1179. ULONG j;
  1180. //
  1181. // The best way to grab the state of the idle handlers is to raise to
  1182. // DISPATCH_LEVEL, grab the current PRCB and look at the handler there.
  1183. // The alternative is to find the last processor, switch to it, and then
  1184. // look at the PopIdle global. As an FYI, we cannot just arbitrarily
  1185. // look at it since the code that updates it might have already run past
  1186. // *this* processor...
  1187. //
  1188. KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
  1189. Prcb = KeGetCurrentPrcb();
  1190. PState = &(Prcb->PowerState);
  1191. IdleState = PState->IdleHandlers;
  1192. if (IdleState) {
  1193. for (i = 0, MaxIdleState = 1; ;) {
  1194. j = IdleState[i].Promote;
  1195. if (j == 0 || j == i || j == PO_IDLE_THROTTLE_PROMOTION) {
  1196. break;
  1197. }
  1198. i = j;
  1199. MaxIdleState += 1;
  1200. }
  1201. }
  1202. KeLowerIrql( OldIrql );
  1203. Summary = KeActiveProcessors;
  1204. Processor = 0;
  1205. Mask = 1;
  1206. while (Summary) {
  1207. if (!(Mask & Summary)) {
  1208. Mask <<= 1;
  1209. continue;
  1210. }
  1211. if (ProcInfoLength < BufferSize + sizeof(PROCESSOR_POWER_INFORMATION)) {
  1212. break;
  1213. }
  1214. //
  1215. // Run in the context of the target processor
  1216. //
  1217. KeSetSystemAffinityThread( Mask );
  1218. Summary &= ~Mask;
  1219. Mask <<= 1;
  1220. //
  1221. // Lets play safe
  1222. //
  1223. KeRaiseIrql( DISPATCH_LEVEL, &OldIrql );
  1224. //
  1225. // Get the current PState block...
  1226. //
  1227. Prcb = KeGetCurrentPrcb();
  1228. PState = &Prcb->PowerState;
  1229. MaxMhz = Prcb->MHz;
  1230. TempInfo.Number = Processor;
  1231. TempInfo.MaxMhz = MaxMhz;
  1232. TempInfo.CurrentMhz = (MaxMhz * PState->CurrentThrottle) / POP_PERF_SCALE;
  1233. TempInfo.MhzLimit = (MaxMhz * PState->ThermalThrottleLimit) / POP_PERF_SCALE;
  1234. //
  1235. // In theory, we could recalculate this number here, but I'm not sure
  1236. // that there is a benefit to doing that
  1237. //
  1238. TempInfo.MaxIdleState = MaxIdleState;
  1239. //
  1240. // Determine what the current Idle state is...
  1241. //
  1242. TempInfo.CurrentIdleState = 0;
  1243. if (PState->IdleFunction != PopIdle0Function) {
  1244. IdleState = PState->IdleState;
  1245. if (IdleState != NULL) {
  1246. TempInfo.CurrentIdleState = IdleState->State;
  1247. }
  1248. }
  1249. //
  1250. // At this point, we have captured the info that we need and can safely
  1251. // drop back to a lower irql
  1252. //
  1253. KeLowerIrql( OldIrql );
  1254. //
  1255. // Copy the temp structure we just created over...
  1256. //
  1257. RtlCopyMemory(ProcInfo, &TempInfo, sizeof(PROCESSOR_POWER_INFORMATION) );
  1258. ProcInfo += 1;
  1259. BufferSize += sizeof (PROCESSOR_POWER_INFORMATION);
  1260. //
  1261. // Next
  1262. //
  1263. Processor = Processor + 1;
  1264. }
  1265. KeRevertToUserAffinityThread();
  1266. *ReturnBufferLength = BufferSize;
  1267. }