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.

2840 lines
73 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. throttle.c
  5. Abstract:
  6. This module contains routines for controlling the voltaging throttling
  7. (SpeedStep) for a CPU. Note that this applies only to throttling for
  8. power savings, not throttling for thermal reasons.
  9. There are four different algorithms defined for voltage throttling.
  10. None - no voltage throttling will be used, the CPU always runs at 100% speed
  11. unless throttled for thermal reaons.
  12. Constant - CPU will be throttled to the next-lowest voltage step on DC, and
  13. always run at 100% on AC.
  14. Degrade - CPU will be throttled in proportion to the battery remaining.
  15. Adaptive - CPU throttle will vary to attempt to match the current CPU load.
  16. Author:
  17. John Vert (jvert) 2/17/2000
  18. Revision History:
  19. --*/
  20. #include "pop.h"
  21. #define POP_THROTTLE_NON_LINEAR 1
  22. //
  23. // Globals representing currently available performance levels
  24. //
  25. PSET_PROCESSOR_THROTTLE PopRealSetThrottle;
  26. UCHAR PopThunkThrottleScale;
  27. #ifdef ALLOC_PRAGMA
  28. #pragma alloc_text(PAGE, PopGetThrottle)
  29. #pragma alloc_text(PAGE, PopCalculatePerfDecreaseLevel)
  30. #pragma alloc_text(PAGE, PopCalculatePerfIncreaseDecreaseTime)
  31. #pragma alloc_text(PAGE, PopCalculatePerfIncreaseLevel)
  32. #pragma alloc_text(PAGE, PopCalculatePerfMinCapacity)
  33. #endif
  34. UCHAR
  35. PopCalculateBusyPercentage(
  36. IN PPROCESSOR_POWER_STATE PState
  37. )
  38. /*++
  39. Routine Description:
  40. This routine is called within the context of the target processor
  41. to determine how busy the processor was during the previous time
  42. period.
  43. Arguments:
  44. PState - Power State Information of the target processor
  45. Return Value:
  46. Percentage value representing how busy the Processor is
  47. --*/
  48. {
  49. PKPRCB prcb;
  50. PKTHREAD thread;
  51. UCHAR frequency;
  52. ULONGLONG idle;
  53. ULONG busy;
  54. ULONG idleTimeDelta;
  55. ULONG cpuTimeDelta;
  56. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  57. ASSERT( KeGetCurrentPrcb() == CONTAINING_RECORD( PState, KPRCB, PowerState ) );
  58. prcb = CONTAINING_RECORD( PState, KPRCB, PowerState );
  59. thread = prcb->IdleThread;
  60. //
  61. // Figure out the idle and cpu time deltas
  62. //
  63. idleTimeDelta = thread->KernelTime - PState->PerfIdleTime;
  64. cpuTimeDelta = POP_CUR_TIME(prcb) - PState->PerfSystemTime;
  65. idle = (idleTimeDelta * 100) / (cpuTimeDelta);
  66. //
  67. // We cannot be more than 100% idle, and if we are then we are
  68. // 0 busy (by definition), so apply the proper caps
  69. //
  70. if (idle > 100) {
  71. idle = 0;
  72. }
  73. busy = 100 - (UCHAR) idle;
  74. frequency = (UCHAR) (busy * PState->CurrentThrottle / POWER_PERF_SCALE);
  75. //
  76. // Remember what it was --- this will make debugging so much easier
  77. //
  78. prcb->PowerState.LastBusyPercentage = frequency;
  79. PoPrint(
  80. PO_THROTTLE_DETAIL,
  81. ("PopCalculateBusyPercentage: %d%% of %d%% (dCpu = %ld dIdle = %ld)\n",
  82. busy,
  83. PState->CurrentThrottle,
  84. cpuTimeDelta,
  85. idleTimeDelta
  86. )
  87. );
  88. return frequency;
  89. }
  90. UCHAR
  91. PopCalculateC3Percentage(
  92. IN PPROCESSOR_POWER_STATE PState
  93. )
  94. /*++
  95. Routine Description:
  96. This routine is called within the context of the target processor
  97. to determine what percentage of time was spent in C3 during the previous
  98. time period.
  99. Arguments:
  100. PState - Power State Information of the target processor
  101. Return Value:
  102. Percentage value
  103. --*/
  104. {
  105. PKPRCB prcb;
  106. ULONGLONG cpuTimeDelta;
  107. ULONGLONG c3;
  108. LARGE_INTEGER c3Delta;
  109. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  110. ASSERT( KeGetCurrentPrcb() == CONTAINING_RECORD( PState, KPRCB, PowerState ) );
  111. prcb = CONTAINING_RECORD( PState, KPRCB, PowerState );
  112. //
  113. // Calculate the C3 time delta in terms of nanosecs. The formulas for
  114. // conversion are taken from PopConvertUsToPerfCount
  115. //
  116. c3Delta.QuadPart = PState->TotalIdleStateTime[2] - PState->PreviousC3StateTime;
  117. c3Delta.QuadPart = (US2SEC * US2TIME * c3Delta.QuadPart) /
  118. PopPerfCounterFrequency.QuadPart;
  119. //
  120. // Now calculate the CpuTimeDelta in terms of nanosecs
  121. //
  122. cpuTimeDelta = (POP_CUR_TIME(prcb) - PState->PerfSystemTime) *
  123. KeTimeIncrement;
  124. //
  125. // Figure out the ratio of the two. Remember to cap it at 100%
  126. //
  127. c3 = c3Delta.QuadPart * 100 / cpuTimeDelta;
  128. if (c3 > 100) {
  129. c3 = 100;
  130. }
  131. //
  132. // Remember what it was --- this will make debugging so much easier
  133. //
  134. prcb->PowerState.LastC3Percentage = (UCHAR) c3;
  135. PoPrint(
  136. PO_THROTTLE_DETAIL,
  137. ("PopCalculateC3Percentage: C3 = %d%% (dCpu = %ld dC3 = %ld)\n",
  138. (UCHAR) c3,
  139. cpuTimeDelta,
  140. c3Delta.QuadPart
  141. )
  142. );
  143. return (UCHAR) c3;
  144. }
  145. VOID
  146. PopCalculatePerfDecreaseLevel(
  147. IN PPROCESSOR_PERF_STATE PerfStates,
  148. IN ULONG PerfStatesCount
  149. )
  150. /*++
  151. Routine Description:
  152. This routine calculate the lower bounds for each perf state
  153. Arguments:
  154. PerfStates - Array of Performance States
  155. PerfStatesCount - Number of element in array
  156. Return Value:
  157. None
  158. --*/
  159. {
  160. //
  161. // We will be required to walk the PerfStates array several times and
  162. // the only way to safely keep track of which index we are looking at
  163. // versus which one we care about is to use two variables to keep track
  164. // of the various indexes.
  165. //
  166. ULONG i;
  167. ULONG j;
  168. ULONG deltaPerf;
  169. PAGED_CODE();
  170. //
  171. // Sanity check
  172. //
  173. if (PerfStatesCount == 0) {
  174. return;
  175. }
  176. //
  177. // Set the decrease value for the last element in the array
  178. //
  179. PerfStates[PerfStatesCount-1].DecreaseLevel = 0;
  180. //
  181. // Calculate the base decrease level
  182. //
  183. for (i = 0; i < (PerfStatesCount - 1); i++) {
  184. //
  185. // it should be noted that for the decrease level, the
  186. // deltaperf level calculated maybe different than the
  187. // deltaperf level calculated for the increase level. This
  188. // is due to how we walk the array and is non-trivial to fix.
  189. //
  190. deltaPerf = PerfStates[i].PercentFrequency -
  191. PerfStates[i+1].PercentFrequency;
  192. deltaPerf *= PopPerfDecreasePercentModifier;
  193. deltaPerf /= POWER_PERF_SCALE;
  194. deltaPerf += PopPerfDecreaseAbsoluteModifier;
  195. //
  196. // We can't have a delta perf that larger than the current
  197. // CPU frequency. This would cause the decrease level to go negative
  198. //
  199. if (deltaPerf > PerfStates[i+1].PercentFrequency) {
  200. deltaPerf = 0;
  201. } else {
  202. deltaPerf = PerfStates[i+1].PercentFrequency - deltaPerf;
  203. }
  204. //
  205. // Set the decrease level to the appropiate value
  206. //
  207. PerfStates[i].DecreaseLevel = (UCHAR) deltaPerf;
  208. }
  209. #if DBG
  210. for (i = 0; i < PerfStatesCount; i++) {
  211. PoPrint(
  212. PO_THROTTLE,
  213. ("PopCalculatePerfDecreaseLevel: (%d) %d%% DecreaseLevel: %d%%\n",
  214. i,
  215. PerfStates[i].PercentFrequency,
  216. PerfStates[i].DecreaseLevel
  217. )
  218. );
  219. }
  220. #endif
  221. #if 0
  222. //
  223. // We want to eliminate demotions at the same voltage level
  224. // We want to guarantee that the DecreaseLevel gets set to a value
  225. // that will cause a voltage state transition
  226. //
  227. i = 0;
  228. while (i < PerfStatesCount) {
  229. //
  230. // Find the next non-linear state. We assume that "i" is currently
  231. // pointing at the highest-frequency state within a voltage band.
  232. // We are interested in finding the next highest-frequency state, but
  233. // at a lower voltage level
  234. //
  235. for (j = i + 1; j < PerfStatesCount; j++) {
  236. //
  237. // We known that there is a voltage change when the state is
  238. // marked as being non-linear
  239. //
  240. if (PerfStates[j].Flags & POP_THROTTLE_NON_LINEAR) {
  241. break;
  242. }
  243. }
  244. //
  245. // We want to find the previous state since that is the one
  246. // that the decrease level will be set to. Note that we aren't
  247. // worried about underflowing the array bounds since j starts at
  248. // i + 1.
  249. //
  250. j--;
  251. //
  252. // Set the decrease level of all the intervening states to this
  253. // new level
  254. //
  255. while (i < j) {
  256. PerfStates[i].DecreaseLevel = PerfStates[j].DecreaseLevel;
  257. i++;
  258. }
  259. //
  260. // Skip the Jth state since it is the bottom of the frequencies
  261. // available for the current voltage level.
  262. //
  263. i++;
  264. }
  265. #endif
  266. #if DBG
  267. for (i = 0; i < PerfStatesCount; i++) {
  268. PoPrint(
  269. PO_THROTTLE,
  270. ("PopCalculatePerfDecreaseLevel: (%d) %d%% DecreaseLevel: %d%%\n",
  271. i,
  272. PerfStates[i].PercentFrequency,
  273. PerfStates[i].DecreaseLevel
  274. )
  275. );
  276. }
  277. #endif
  278. }
  279. VOID
  280. PopCalculatePerfIncreaseDecreaseTime(
  281. IN PPROCESSOR_PERF_STATE PerfStates,
  282. IN ULONG PerfStatesCount,
  283. IN PPROCESSOR_STATE_HANDLER2 PerfHandler
  284. )
  285. /*++
  286. Routine Description:
  287. This routine calculate the lower bounds for each perf state
  288. Arguments:
  289. PerfStates - Array of Performance States
  290. PerfStatesCount - Number of element in array
  291. PerfHandler - Information about the system latencies
  292. Return Value:
  293. None
  294. --*/
  295. {
  296. ULONG i;
  297. ULONG time;
  298. ULONG tickRate;
  299. PAGED_CODE();
  300. //
  301. // Sanity Check
  302. //
  303. if (PerfStatesCount == 0) {
  304. return;
  305. }
  306. //
  307. // Get the current tick rate
  308. //
  309. tickRate = KeQueryTimeIncrement();
  310. //
  311. // We can never increase from State 0
  312. //
  313. PerfStates[0].IncreaseTime = (ULONG) - 1;
  314. //
  315. // We can never decrease from State <x>
  316. //
  317. PerfStates[PerfStatesCount-1].DecreaseTime = (ULONG) -1;
  318. //
  319. // Might as tell say what the hardware latency is...
  320. //
  321. PoPrint(
  322. PO_THROTTLE,
  323. ("PopCalculatePerfIncreaseDecreaseTime: Hardware Latency %d us\n",
  324. PerfHandler->HardwareLatency
  325. )
  326. );
  327. //
  328. // Loop over the remaining elements to calculate their
  329. // increase and decrease times
  330. //
  331. for (i = 1; i < PerfStatesCount; i++) {
  332. //
  333. // DecreaseTime is calculated for the previous state
  334. // as function of wether or not the current state
  335. // is linear
  336. //
  337. time = PerfHandler->HardwareLatency * 10;
  338. if (PerfStates[i].Flags & POP_THROTTLE_NON_LINEAR) {
  339. time *= 10;
  340. time += PopPerfDecreaseTimeValue;
  341. //
  342. // We do have some minimums that we must respect
  343. //
  344. if (time < PopPerfDecreaseMinimumTime) {
  345. time = PopPerfDecreaseMinimumTime;
  346. }
  347. } else {
  348. time += PopPerfDecreaseTimeValue;
  349. }
  350. //
  351. // Time is in microseconds (us) and we need it in
  352. // units of KeTimeIncrement
  353. //
  354. PoPrint(
  355. PO_THROTTLE,
  356. ("PopCalculatePerfIncreaseDecreaseTime: (%d) %d%% DecreaseTime %d us\n",
  357. (i-1),
  358. PerfStates[i-1].PercentFrequency,
  359. time
  360. )
  361. );
  362. PerfStates[i-1].DecreaseTime = time * US2TIME / tickRate + 1;
  363. //
  364. // IncreaseTime is calculated for the current state
  365. // as a function of wether or not the current state
  366. // is linear
  367. //
  368. time = PerfHandler->HardwareLatency;
  369. if (PerfStates[i].Flags & POP_THROTTLE_NON_LINEAR) {
  370. time *= 10;
  371. time += PopPerfIncreaseTimeValue;
  372. //
  373. // We do have some minimums that we must respect
  374. //
  375. if (time < PopPerfIncreaseMinimumTime) {
  376. time = PopPerfIncreaseMinimumTime;
  377. }
  378. } else {
  379. time += PopPerfIncreaseTimeValue;
  380. }
  381. //
  382. // Time is in microseconds (us) and we need it in
  383. // units of KeTimeIncrement
  384. //
  385. PoPrint(
  386. PO_THROTTLE,
  387. ("PopCalculatePerfIncreaseDecreaseTime: (%d) %d%% IncreaseTime %d us\n",
  388. i,
  389. PerfStates[i].PercentFrequency,
  390. time
  391. )
  392. );
  393. PerfStates[i].IncreaseTime = time * US2TIME / tickRate + 1;
  394. }
  395. #if DBG
  396. for (i = 0; i < PerfStatesCount; i++) {
  397. PoPrint(
  398. PO_THROTTLE,
  399. ("PopCalculatePerfIncreaseDecreaseTime: (%d) %d%% IncreaseTime: %d DecreaseTime: %d\n",
  400. i,
  401. PerfStates[i].PercentFrequency,
  402. PerfStates[i].IncreaseTime,
  403. PerfStates[i].DecreaseTime
  404. )
  405. );
  406. }
  407. #endif
  408. }
  409. VOID
  410. PopCalculatePerfIncreaseLevel(
  411. IN PPROCESSOR_PERF_STATE PerfStates,
  412. IN ULONG PerfStatesCount
  413. )
  414. /*++
  415. Routine Description:
  416. This routine calculate the lower bounds for each perf state
  417. Arguments:
  418. PerfStates - Array of Performance States
  419. PerfStatesCount - Number of element in array
  420. Return Value:
  421. None
  422. --*/
  423. {
  424. ULONG i;
  425. ULONG deltaPerf;
  426. PAGED_CODE();
  427. //
  428. // Sanity check
  429. //
  430. if (PerfStatesCount == 0) {
  431. return;
  432. }
  433. //
  434. // This guarantees that we cannot promote past this state
  435. //
  436. PerfStates[0].IncreaseLevel = POWER_PERF_SCALE + 1;
  437. //
  438. // Calculate the base increase level
  439. //
  440. for (i = 1; i < PerfStatesCount; i++) {
  441. //
  442. // it should be noted that for the decrease level, the
  443. // deltaperf level calculated maybe different than the
  444. // deltaperf level calculated for the increase level. This
  445. // is due to how we walk the array and is non-trivial to fix.
  446. //
  447. deltaPerf = PerfStates[i-1].PercentFrequency -
  448. PerfStates[i].PercentFrequency;
  449. deltaPerf *= PopPerfIncreasePercentModifier;
  450. deltaPerf /= POWER_PERF_SCALE;
  451. deltaPerf += PopPerfIncreaseAbsoluteModifier;
  452. //
  453. // We cannot cause the increase level to goto 0, so, if we work
  454. // out mathematically that this would happen, then the safe thing
  455. // to do is not allow for promotion out of this state...
  456. //
  457. if (deltaPerf > PerfStates[i].PercentFrequency) {
  458. deltaPerf = POWER_PERF_SCALE + 1;
  459. } else {
  460. deltaPerf = PerfStates[i].PercentFrequency - deltaPerf;
  461. }
  462. //
  463. // Set the decrease level to the appropiate value
  464. //
  465. PerfStates[i].IncreaseLevel = (UCHAR) deltaPerf;
  466. }
  467. #if DBG
  468. for (i = 0; i < PerfStatesCount; i++) {
  469. PoPrint(
  470. PO_THROTTLE,
  471. ("PopCalculatePerfIncreaseLevel: (%d) %d%% IncreaseLevel: %d%%\n",
  472. i,
  473. PerfStates[i].PercentFrequency,
  474. PerfStates[i].IncreaseLevel
  475. )
  476. );
  477. }
  478. #endif
  479. }
  480. VOID
  481. PopCalculatePerfMinCapacity(
  482. IN PPROCESSOR_PERF_STATE PerfStates,
  483. IN ULONG PerfStatesCount
  484. )
  485. /*++
  486. Routine Description:
  487. This routine is called to determine what the mininum battery capacity
  488. is for each of the states supported.
  489. Arguments:
  490. PerfStates - The states that this processor supports
  491. PerfStatesCount - The number of states that this processor supports
  492. PState - Power Information about the current processor
  493. Return Value:
  494. None
  495. --*/
  496. {
  497. UCHAR i;
  498. UCHAR kneeThrottleIndex = 0;
  499. UCHAR num;
  500. UCHAR total = (UCHAR) PopPerfDegradeThrottleMinCapacity;
  501. UCHAR width = 0;
  502. PAGED_CODE();
  503. //
  504. // Sanity check...
  505. //
  506. if (!PerfStatesCount) {
  507. return;
  508. }
  509. //
  510. // Calculate the knee of the curve ... this is quick and avoids
  511. // having to pass this information around
  512. //
  513. for (i = (UCHAR) PerfStatesCount ; i >= 1; i--) {
  514. if (PerfStates[i-1].Flags & POP_THROTTLE_NON_LINEAR) {
  515. kneeThrottleIndex = i-1;
  516. break;
  517. }
  518. }
  519. //
  520. // Look at all the states that occur before the knee in the curve
  521. //
  522. for (i = 0; i < kneeThrottleIndex; i++) {
  523. //
  524. // Any of these steps can only run when the battery is at 100%
  525. //
  526. PerfStates[i].MinCapacity = 100;
  527. }
  528. //
  529. // Calculate the range for which we will clamp down the throttle.
  530. // Note that we are currently using a linear algorithm, but this
  531. // can be changed relatively easily...
  532. //
  533. num = ( (UCHAR)PerfStatesCount - kneeThrottleIndex);
  534. if (num != 0) {
  535. //
  536. // We do this here to avoid potential divide by zero errors.
  537. // What are are trying to accomplish is figure out how much
  538. // capacity we lose during each "step"
  539. //
  540. width = total / num;
  541. }
  542. //
  543. // Look at all the states from the knee of the curve to the end.
  544. // Starting at the highest state, set the min capacity and
  545. // subtract the appropriate value to get the capacity for the next
  546. // state
  547. //
  548. for (i = kneeThrottleIndex; i < PerfStatesCount; i++) {
  549. //
  550. // We put a floor onto how low we can force the throttle
  551. // down to. If this state is operating below that floor,
  552. // then we should set the MinCapacity to 0, which
  553. // reflects the fact that we don't want to degrade beyond this
  554. // point
  555. //
  556. if (PerfStates[i].PercentFrequency < PopPerfDegradeThrottleMinCapacity) {
  557. PoPrint(
  558. PO_THROTTLE,
  559. ("PopCalculatePerMinCapacity: (%d) %d%% below MinCapacity %d%%\n",
  560. i,
  561. PerfStates[i].PercentFrequency,
  562. PopPerfDegradeThrottleMinCapacity
  563. )
  564. );
  565. //
  566. // We modify the min capacity for the previous state since we
  567. // don't want to demote from that state. Also, once we start
  568. // being less than the min frequency, the min capacity will
  569. // always be 0 except for the last state. But that's okay
  570. // since we will look at each state in order. We also have
  571. // to make sure that we don't violate the array bounds, but
  572. // that can only happen if the perf states array is badly formed
  573. // or the min frequency is badly formed
  574. //
  575. if (i != 0 && PerfStates[i-1].PercentFrequency < PopPerfDegradeThrottleMinCapacity) {
  576. PerfStates[i-1].MinCapacity = 0;
  577. }
  578. PerfStates[i].MinCapacity = 0;
  579. continue;
  580. }
  581. PerfStates[i].MinCapacity = total;
  582. total -= width;
  583. }
  584. #if DBG
  585. for (i = 0; i < PerfStatesCount; i++) {
  586. PoPrint(
  587. PO_THROTTLE,
  588. ("PopCalculatePerfMinCapacity: (%d) %d%% MinCapacity: %d%%\n",
  589. i,
  590. PerfStates[i].PercentFrequency,
  591. PerfStates[i].MinCapacity
  592. )
  593. );
  594. }
  595. #endif
  596. }
  597. UCHAR
  598. PopGetThrottle(
  599. VOID
  600. )
  601. /*++
  602. Routine Description:
  603. Based on the current throttling policy and power state, returns
  604. the CPU throttle to be used (between PO_MIN_MIN_THROTTLE and 100)
  605. Arguments:
  606. None
  607. Return Value:
  608. Throttle to be used. Range is PO_MIN_MIN_THROTTLE (slowest) to 100 (fastest)
  609. --*/
  610. {
  611. PAGED_CODE();
  612. return(PopPolicy->ForcedThrottle);
  613. }
  614. VOID
  615. PopPerfHandleInrush(
  616. IN BOOLEAN EnableHandler
  617. )
  618. /*++
  619. Routine Description:
  620. This routine is responsible for enabling/disabling support for handling
  621. the case where we are processing an inrush irp
  622. In the enable case, it sets a bit in each PRCB (using an IPI) and
  623. forces an update on the current throttle *only*
  624. Arguments:
  625. EnableHandler - TRUE if we are processing an Inrush irp, false otherwise
  626. Return Value:
  627. None
  628. --*/
  629. {
  630. KIRQL oldIrql;
  631. //
  632. // Set the proper bit on all the processors
  633. //
  634. PopSetPerfFlag( PSTATE_DISABLE_THROTTLE_INRUSH, !EnableHandler );
  635. //
  636. // Make sure we are running at DPC level (to avoid pre-emption)
  637. //
  638. KeRaiseIrql ( DISPATCH_LEVEL, &oldIrql );
  639. //
  640. // Force an update on the current processor
  641. //
  642. PopUpdateProcessorThrottle();
  643. //
  644. // Done
  645. //
  646. KeLowerIrql( oldIrql );
  647. }
  648. VOID
  649. PopPerfIdle(
  650. IN PPROCESSOR_POWER_STATE PState
  651. )
  652. /*++
  653. Routine Description:
  654. This routine is responsible for promoting or demoting the processor
  655. between various performance levels. It can *only* be called from within
  656. the context of the idle handler and the appropriate target processor
  657. Arguments:
  658. PState - power state of the processor that is idle
  659. Return Value:
  660. None
  661. --*/
  662. {
  663. BOOLEAN cancelTimer = FALSE;
  664. BOOLEAN setTimer = FALSE;
  665. BOOLEAN forced = FALSE;
  666. BOOLEAN promoted = FALSE;
  667. BOOLEAN demoted = FALSE;
  668. PKPRCB prcb;
  669. PPROCESSOR_PERF_STATE perfStates;
  670. UCHAR currentPerfState;
  671. UCHAR freq;
  672. UCHAR i;
  673. UCHAR j;
  674. ULONG idleTime;
  675. ULONG perfStatesCount;
  676. ULONG tickCount;
  677. ULONG time;
  678. ULONG timeDelta;
  679. //
  680. // Sanity checks
  681. //
  682. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  683. ASSERT( KeGetCurrentPrcb() == CONTAINING_RECORD( PState, KPRCB, PowerState ) );
  684. //
  685. // This piece of code really belongs in the functions that will eventually
  686. // call this one, PopIdle0 or PopProcessorIdle, to save a function call.
  687. //
  688. if (!(PState->Flags & PSTATE_ADAPTIVE_THROTTLE) ) {
  689. return;
  690. }
  691. //
  692. // Has enough time expired?
  693. //
  694. prcb = CONTAINING_RECORD( PState, KPRCB, PowerState );
  695. time = POP_CUR_TIME(prcb);
  696. idleTime = prcb->IdleThread->KernelTime;
  697. timeDelta = time - PState->PerfSystemTime;
  698. if (timeDelta < PopPerfTimeTicks) {
  699. return;
  700. }
  701. //
  702. // Remember what our perf states are...
  703. //
  704. perfStates = PState->PerfStates;
  705. perfStatesCount = PState->PerfStatesCount;
  706. //
  707. // Find which bucket we are currently using to get current frequency
  708. //
  709. currentPerfState = PState->CurrentThrottleIndex;
  710. i = currentPerfState;
  711. //
  712. // At this point, we need to see if the number of C3 transitions have
  713. // exceeded a threshold value, and if so, then we really need to
  714. // throttle back to the KneeThrottleIndex since we save more power if
  715. // the processor is at 100% and in C3 then if the processor at 12.5%
  716. // busy and in C3. Make sure to remember the value for user informational
  717. // purposes.
  718. //
  719. freq = PopCalculateC3Percentage( PState );
  720. PState->LastC3Percentage = freq;
  721. if (freq >= PopPerfMaxC3Frequency) {
  722. //
  723. // Set the throttle to the lowest knee in the
  724. // the voltage and frequency curve
  725. //
  726. i = PState->KneeThrottleIndex;
  727. if (currentPerfState > i) {
  728. promoted = TRUE;
  729. } else if (currentPerfState < i) {
  730. demoted = TRUE;
  731. }
  732. //
  733. // remember why we are doing this
  734. //
  735. forced = TRUE;
  736. //
  737. // Skip directly to setting the throttle
  738. //
  739. goto PopPerfIdleSetThrottle;
  740. }
  741. //
  742. // Calculate how busy the CPU is
  743. //
  744. freq = PopCalculateBusyPercentage( PState );
  745. //
  746. // Have we exceeded the thermal throttle limit?
  747. //
  748. if (freq > PState->ThermalThrottleLimit) {
  749. //
  750. // The following code will force the frequency to be only
  751. // as busy as the thermal throttle limit will actually allow.
  752. // This removes the need for complicated algorithms later on
  753. //
  754. freq = PState->ThermalThrottleLimit;
  755. i = PState->ThermalThrottleIndex;
  756. //
  757. // Additionally if we are over our thermal limit, that's important
  758. // enough that we should ignore the time checks when deciding to
  759. // demote
  760. //
  761. forced = TRUE;
  762. }
  763. //
  764. // Is there an upper limit to what the throttle can goto?
  765. // Note that because we check these after we have checked the
  766. // thermal limit, it means that it is not possible for the
  767. // frequency to exceed the thermal limit that was specified
  768. //
  769. if (PState->Flags & PSTATE_DEGRADED_THROTTLE) {
  770. //
  771. // Make sure that we don't exceed the state that is specified
  772. //
  773. j = PState->ThrottleLimitIndex;
  774. if (freq >= perfStates[j].IncreaseLevel) {
  775. //
  776. // We must make a special allowance that says that if
  777. // if we are in a higher performance state then we are
  778. // permitted, then we must switch to the 'proper' state
  779. //
  780. forced = TRUE;
  781. freq = perfStates[j].IncreaseLevel;
  782. i = j;
  783. }
  784. } else if (PState->Flags & PSTATE_CONSTANT_THROTTLE) {
  785. j = PState->KneeThrottleIndex;
  786. if (freq >= perfStates[j].IncreaseLevel) {
  787. //
  788. // We must make a special allowance that says that if
  789. // if we are in a higher performance state then we are
  790. // permitted, then we must switch to the 'proper' state
  791. //
  792. forced = TRUE;
  793. freq = perfStates[j].IncreaseLevel;
  794. i = j;
  795. }
  796. } else {
  797. //
  798. // This is the case that we are running in Adaptive throttle
  799. // mode and we need to make sure to clean up after switching
  800. // out of constant or degraded throttle mode...
  801. //
  802. //
  803. // If we are not in degraded throttle mode, then the min level
  804. // cannot be lower than the KneeThrottleIndex
  805. //
  806. if ( (i > PState->KneeThrottleIndex) ) {
  807. //
  808. // Promote to the knee of the curve
  809. //
  810. forced = TRUE;
  811. i = PState->KneeThrottleIndex;
  812. freq = perfStates[i].IncreaseLevel;
  813. }
  814. }
  815. //
  816. // Determine if there was a promotion or demotion in the previous...
  817. //
  818. if (i < currentPerfState) {
  819. promoted = TRUE;
  820. } else if (i > currentPerfState) {
  821. demoted = TRUE;
  822. }
  823. PoPrint(
  824. PO_THROTTLE_DETAIL,
  825. ("PopPerfIdle: Freq = %d%% (Adjusted)\n",
  826. freq
  827. )
  828. );
  829. //
  830. // Remember this value for user information purposes
  831. //
  832. PState->LastAdjustedBusyPercentage = freq;
  833. //
  834. // Find the processor frequency that best matches the one that we
  835. // have just calculated. Please note that the algorithm is written
  836. // in such a way that "i" can only travel in a single direction. It
  837. // is possible to collapse the following code down, but not without
  838. // allowing the possibility of "i" doing a "yo-yo" between two states
  839. // and thus never terminating the while loop.
  840. //
  841. if (perfStates[i].IncreaseLevel < freq) {
  842. //
  843. // Now, we must handle the cases where there are multiple voltage
  844. // steps above the knee in the curve and the case where there might
  845. // be frequency steps between the voltage steps. The easiest way
  846. // to do that is use to two indexes to look at the steps. We use
  847. // "j" to look at all of the steps and "i" to remember which one
  848. // we desired last.
  849. //
  850. j = i;
  851. while (perfStates[j].IncreaseLevel < freq) {
  852. //
  853. // Can we actually promote any further?
  854. //
  855. if (j == 0) {
  856. break;
  857. }
  858. //
  859. // Walk the state table. If we are in a degraded policy, then
  860. // this is automatically a promotion, otherwise, it is only a
  861. // promotion if the target state is marked as non-linear...
  862. //
  863. j--;
  864. if ((PState->Flags & PSTATE_DEGRADED_THROTTLE) ||
  865. (perfStates[j].Flags & POP_THROTTLE_NON_LINEAR)) {
  866. i = j;
  867. promoted = TRUE;
  868. }
  869. }
  870. } else if (perfStates[i].DecreaseLevel > freq) {
  871. //
  872. // We need the same logic as in the promote case. That is, we need
  873. // to walk the state table with two variables. The first one is the
  874. // current state and the second one remembers the one that the system
  875. // should transition too
  876. //
  877. j = i;
  878. do {
  879. if (j == (perfStatesCount - 1) ) {
  880. //
  881. // Can't demote further
  882. //
  883. break;
  884. }
  885. //
  886. // Walk the state table. If we are in a degraded policy, then
  887. // this is automatically a demotion, otherwise, it is only a
  888. // demotion if the target state is marked as non-linear
  889. //
  890. j++;
  891. if ((PState->Flags & PSTATE_DEGRADED_THROTTLE) ||
  892. (perfStates[j].Flags & POP_THROTTLE_NON_LINEAR) ) {
  893. i = j;
  894. demoted = TRUE;
  895. }
  896. } while ( perfStates[j].DecreaseLevel > freq );
  897. }
  898. PopPerfIdleSetThrottle:
  899. //
  900. // We have to make special allowances if we were forced to throttle
  901. // because of various considerations (C3, thermal, degrade, constant)
  902. //
  903. if (!forced) {
  904. //
  905. // See if enough time has expired to justify changing
  906. // the throttle. This code is here because certain transitions
  907. // are fairly expensive (like those across a voltage state) while
  908. // others are fairly cheap. So the amount of time required before
  909. // we will consider promotion/demotion from the expensive states
  910. // might be longer than the interval at which we will run this
  911. // function
  912. //
  913. if ((promoted && timeDelta < perfStates[currentPerfState].IncreaseTime) ||
  914. (demoted && timeDelta < perfStates[currentPerfState].DecreaseTime)) {
  915. //
  916. // We haven't had enough time in the current state to justify
  917. // the promotion or demotion. We don't update the bookkeeping
  918. // since we haven't considered the current interval as
  919. // as "success". So, we just return.
  920. //
  921. // N.B. It is very important that we don't update PState->
  922. // PerfSystemTime here. If we did, then it is possible that
  923. // TimeDelta would never exceed the required threshold
  924. //
  925. //
  926. // Base our actions for the timer based upon the current
  927. // state instead of the target state
  928. //
  929. PopSetTimer( PState, currentPerfState );
  930. return;
  931. }
  932. }
  933. PoPrint(
  934. PO_THROTTLE_DETAIL,
  935. ("PopPerfIdle: Index: %d vs %d (%s)\n",
  936. i,
  937. currentPerfState,
  938. (promoted ? "promoted" : (demoted ? "demoted" : "no change") )
  939. )
  940. );
  941. //
  942. // Note that we need to do this now because we dont want to exit this
  943. // path without having set or cancelled the timer as appropariate.
  944. //
  945. PopSetTimer( PState, i );
  946. //
  947. // Update the promote/demote count
  948. //
  949. if (promoted) {
  950. perfStates[currentPerfState].IncreaseCount++;
  951. PState->PromotionCount++;
  952. } else if (demoted) {
  953. perfStates[currentPerfState].DecreaseCount++;
  954. PState->DemotionCount++;
  955. } else {
  956. //
  957. // At this point, we realize that aren't promoting or demoting
  958. // and in fact, keeping the same performance level. So we should
  959. // just update the bookkeeping and return
  960. //
  961. PState->PerfIdleTime = idleTime;
  962. PState->PerfSystemTime = time;
  963. PState->PreviousC3StateTime = PState->TotalIdleStateTime[2];
  964. return;
  965. }
  966. PoPrint(
  967. PO_THROTTLE,
  968. ("PopPerfIdle: Index=%d (%d%%) %ld (dSystem) %ld (dIdle)\n",
  969. i,
  970. perfStates[i].PercentFrequency,
  971. (time - PState->PerfSystemTime),
  972. (idleTime - PState->PerfIdleTime)
  973. )
  974. );
  975. //
  976. // We have a new throttle. Update the bookkeeping to reflect the
  977. // amount of time that we spent in the previous state and reset the
  978. // count for the next state
  979. //
  980. PopSetThrottle(
  981. PState,
  982. perfStates,
  983. i,
  984. time,
  985. idleTime
  986. );
  987. }
  988. VOID
  989. PopPerfIdleDpc(
  990. IN PKDPC Dpc,
  991. IN PVOID DpcContext,
  992. IN PVOID SystemArgument1,
  993. IN PVOID SystemArgument2
  994. )
  995. /*++
  996. Routine Description:
  997. This routine is run when the OS is worried that the CPU is not running
  998. at the maximum possible frequency and needs to be checked because the
  999. Idle loop will not be run anytime soon
  1000. Arguments:
  1001. Dpc - the dpc object
  1002. DpcContext - pointer to the current processors PRCB
  1003. SysArg1 - not used
  1004. SysArg2 - not used
  1005. Return Value:
  1006. None
  1007. --*/
  1008. {
  1009. PKPRCB prcb;
  1010. PKTHREAD idleThread;
  1011. PPROCESSOR_PERF_STATE perfStates;
  1012. PPROCESSOR_POWER_STATE pState;
  1013. UCHAR currentPerfState;
  1014. UCHAR freq;
  1015. UCHAR i;
  1016. ULONG idleTime;
  1017. ULONG time;
  1018. ULONG timeDelta;
  1019. //
  1020. // We need to fetch the PRCB and the PState structres. We could
  1021. // easily call KeGetCurrentPrcb() here but since we had room for a
  1022. // single argument, why bother making inline call (which generates
  1023. // more code and runs more slowly than using the context field). The
  1024. // memory for the context field is already allocated anyways
  1025. //
  1026. prcb = (PKPRCB) DpcContext;
  1027. pState = &(prcb->PowerState);
  1028. //
  1029. // Remember what the perf states are...
  1030. //
  1031. perfStates = pState->PerfStates;
  1032. currentPerfState = pState->CurrentThrottleIndex;
  1033. //
  1034. // Make sure that we have some perf states to reference. Its possible
  1035. // that the watchdog fired and in the mean time, the kernel received
  1036. // notification to switch the state table
  1037. //
  1038. if (perfStates == NULL) {
  1039. //
  1040. // Note that we don't setup the timer to fire again. This is to
  1041. // deal with the case where perf states go away and never come back
  1042. //
  1043. return;
  1044. }
  1045. //
  1046. // Lets see if enough kernel time has expired since the last check
  1047. //
  1048. time = POP_CUR_TIME(prcb);
  1049. timeDelta = time - pState->PerfSystemTime;
  1050. if (timeDelta < PopPerfCriticalTimeTicks) {
  1051. PopSetTimer( pState, currentPerfState );
  1052. return;
  1053. }
  1054. //
  1055. // We will need to remember these values if we set a new state
  1056. //
  1057. idleThread = prcb->IdleThread;
  1058. idleTime = idleThread->KernelTime;
  1059. //
  1060. // Assume that if we got to this point, that we are at 100% busy.
  1061. // We do this because if this routine runs, then its clear that
  1062. // the idle loop isn't getting a chance to run, and thus, we are
  1063. // busy.
  1064. //
  1065. i = 0;
  1066. freq = perfStates[0].PercentFrequency;
  1067. //
  1068. // We might as well cancel the timer --- for sanity's sake
  1069. //
  1070. KeCancelTimer( (PKTIMER) &(pState->PerfTimer) );
  1071. //
  1072. // Have we exceeded the thermal throttle limit?
  1073. //
  1074. if (freq > pState->ThermalThrottleLimit) {
  1075. //
  1076. // The following code will force the frequency to be only
  1077. // as busy as the thermal throttle limit will actually allow.
  1078. // This removes the need for complicated algorithms later on
  1079. //
  1080. freq = pState->ThermalThrottleLimit;
  1081. i = pState->ThermalThrottleIndex;
  1082. }
  1083. //
  1084. // Is there an upper limit to what the throttle can goto?
  1085. // Note that because we check these after we have checked the
  1086. // thermal limit, it means that it is not possible for the
  1087. // frequency to exceed the thermal limit that was specified
  1088. //
  1089. if (pState->Flags & PSTATE_DEGRADED_THROTTLE) {
  1090. //
  1091. // Make sure that we don't exceed the state that is specified
  1092. //
  1093. freq = perfStates[i].PercentFrequency;
  1094. i = pState->ThrottleLimitIndex;
  1095. } else if (pState->Flags & PSTATE_CONSTANT_THROTTLE) {
  1096. freq = perfStates[i].PercentFrequency;
  1097. i = pState->KneeThrottleIndex;
  1098. }
  1099. //
  1100. // Remember these values for user information purposes
  1101. //
  1102. pState->LastBusyPercentage = perfStates[0].PercentFrequency;
  1103. pState->LastAdjustedBusyPercentage = freq;
  1104. //
  1105. // Let the world know
  1106. //
  1107. PoPrint(
  1108. PO_THROTTLE,
  1109. ("PopPerfIdleDpc: %d%% vs %d%% (Time: %ld Delta: %ld)\n",
  1110. freq,
  1111. pState->CurrentThrottle,
  1112. time,
  1113. timeDelta
  1114. )
  1115. );
  1116. PoPrint(
  1117. PO_THROTTLE,
  1118. ("PopPerfIdleDpc: Index=%d (%d%%) %ld (dSystem) %ld (dIdle)\n",
  1119. i,
  1120. perfStates[i].PercentFrequency,
  1121. (time - pState->PerfSystemTime),
  1122. (idleTime - pState->PerfIdleTime)
  1123. )
  1124. );
  1125. //
  1126. // Update the promote/demote count
  1127. //
  1128. if (i < currentPerfState) {
  1129. perfStates[currentPerfState].IncreaseCount++;
  1130. pState->PromotionCount++;
  1131. } else if (i > currentPerfState) {
  1132. perfStates[currentPerfState].DecreaseCount++;
  1133. pState->DemotionCount++;
  1134. } else {
  1135. //
  1136. // Its in theory possible for us to be running at the max
  1137. // state when this routines gets called
  1138. //
  1139. return;
  1140. }
  1141. //
  1142. // Set the new throttle
  1143. //
  1144. PopSetThrottle(
  1145. pState,
  1146. perfStates,
  1147. i,
  1148. time,
  1149. idleTime
  1150. );
  1151. }
  1152. VOID
  1153. PopRoundThrottle(
  1154. IN UCHAR Throttle,
  1155. OUT OPTIONAL PUCHAR RoundDown,
  1156. OUT OPTIONAL PUCHAR RoundUp,
  1157. OUT OPTIONAL PUCHAR RoundDownIndex,
  1158. OUT OPTIONAL PUCHAR RoundUpIndex
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. Given an arbitrary throttle percentage, computes the closest
  1163. match in the possible throttle steps. Both the lower and higher
  1164. matches are returned.
  1165. Arguments:
  1166. Throttle - supplies the percentage throttle
  1167. RoundDown - Returns the closest match, rounded down.
  1168. RoundUp - Returns the closest match, rounded up.
  1169. Return Value:
  1170. None
  1171. --*/
  1172. {
  1173. KIRQL oldIrql;
  1174. PKPRCB prcb;
  1175. PPROCESSOR_PERF_STATE perfStates;
  1176. PPROCESSOR_POWER_STATE pState;
  1177. UCHAR low;
  1178. UCHAR lowIndex;
  1179. UCHAR high;
  1180. UCHAR highIndex;
  1181. UCHAR i;
  1182. //
  1183. // We need to get the this processor's power capabilities
  1184. //
  1185. prcb = KeGetCurrentPrcb();
  1186. pState = &(prcb->PowerState);
  1187. //
  1188. // Make sure that we are synchronized with the idle thread and
  1189. // other routines that access these data structures
  1190. //
  1191. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1192. perfStates = pState->PerfStates;
  1193. //
  1194. // Does this processor support throttling?
  1195. //
  1196. if ((pState->Flags & PSTATE_SUPPORTS_THROTTLE) == 0) {
  1197. low = high = Throttle;
  1198. lowIndex = highIndex = 0;
  1199. goto PopRoundThrottleExit;
  1200. }
  1201. ASSERT( perfStates != NULL );
  1202. //
  1203. // Check if the supplied throttle is out of range
  1204. //
  1205. if (Throttle < pState->ProcessorMinThrottle) {
  1206. Throttle = pState->ProcessorMinThrottle;
  1207. } else if (Throttle > pState->ProcessorMaxThrottle) {
  1208. Throttle = pState->ProcessorMaxThrottle;
  1209. }
  1210. //
  1211. // Initialize our search space to something reasonable...
  1212. //
  1213. low = high = perfStates[0].PercentFrequency;
  1214. lowIndex = highIndex = 0;
  1215. //
  1216. // Look at all the available perf states
  1217. //
  1218. for (i = 0; i < pState->PerfStatesCount; i++) {
  1219. if (low > Throttle) {
  1220. if (perfStates[i].PercentFrequency < low) {
  1221. low = perfStates[i].PercentFrequency;
  1222. lowIndex = i;
  1223. }
  1224. } else if (low < Throttle) {
  1225. if (perfStates[i].PercentFrequency <= Throttle &&
  1226. perfStates[i].PercentFrequency > low) {
  1227. low = perfStates[i].PercentFrequency;
  1228. lowIndex = i;
  1229. }
  1230. }
  1231. if (high < Throttle) {
  1232. if (perfStates[i].PercentFrequency > high) {
  1233. high = perfStates[i].PercentFrequency;
  1234. highIndex = i;
  1235. }
  1236. } else if (high > Throttle) {
  1237. if (perfStates[i].PercentFrequency >= Throttle &&
  1238. perfStates[i].PercentFrequency < high) {
  1239. high = perfStates[i].PercentFrequency;
  1240. highIndex = i;
  1241. }
  1242. }
  1243. }
  1244. PopRoundThrottleExit:
  1245. //
  1246. // Revert back to the previous IRQL
  1247. //
  1248. KeLowerIrql( oldIrql );
  1249. //
  1250. // Fill in the pointers provided by the caller
  1251. //
  1252. if (ARGUMENT_PRESENT(RoundUp)) {
  1253. *RoundUp = high;
  1254. if (ARGUMENT_PRESENT(RoundUpIndex)) {
  1255. *RoundUpIndex = highIndex;
  1256. }
  1257. }
  1258. if (ARGUMENT_PRESENT(RoundDown)) {
  1259. *RoundDown = low;
  1260. if (ARGUMENT_PRESENT(RoundDownIndex)) {
  1261. *RoundDownIndex = lowIndex;
  1262. }
  1263. }
  1264. }
  1265. VOID
  1266. PopSetPerfFlag(
  1267. IN ULONG PerfFlag,
  1268. IN BOOLEAN Clear
  1269. )
  1270. /*++
  1271. Routine Description:
  1272. There are certain times when we want to set certain flags for each
  1273. processor. This function will safely set or clear the specified flag
  1274. Arguments:
  1275. PerfFlag - The bits to set or clear
  1276. Clear - Should we set or clear
  1277. Return Value:
  1278. None - We can't return the old flag because they are allowed to
  1279. vary in the case that its an MP system...
  1280. --*/
  1281. {
  1282. PKPRCB prcb;
  1283. ULONG processorNumber;
  1284. PULONG flags;
  1285. //
  1286. // For each processor in the system.
  1287. //
  1288. for (processorNumber = 0;
  1289. processorNumber < MAXIMUM_PROCESSORS;
  1290. processorNumber++) {
  1291. prcb = KeGetPrcb(processorNumber);
  1292. if (prcb != NULL) {
  1293. //
  1294. // Get the address of the PowerState.Flags field in
  1295. // this processor's PRCB and set/clear appropriately.
  1296. //
  1297. flags = &prcb->PowerState.Flags;
  1298. if (Clear) {
  1299. RtlInterlockedClearBits(flags, PerfFlag);
  1300. } else {
  1301. RtlInterlockedSetBits(flags, PerfFlag);
  1302. }
  1303. }
  1304. }
  1305. }
  1306. NTSTATUS
  1307. PopSetPerfLevels(
  1308. IN PPROCESSOR_STATE_HANDLER2 ProcessorHandler
  1309. )
  1310. /*++
  1311. Routine Description:
  1312. Recomputes the table of processor performance levels
  1313. Arguments:
  1314. ProcessorHandler - Supplies the processor state handler structure
  1315. Return Value:
  1316. NTSTATUS
  1317. --*/
  1318. {
  1319. BOOLEAN failedAllocation = FALSE;
  1320. KAFFINITY processors;
  1321. KAFFINITY currentAffinity;
  1322. KIRQL oldIrql;
  1323. NTSTATUS status = STATUS_SUCCESS;
  1324. PKPRCB prcb;
  1325. PPROCESSOR_PERF_STATE perfStates = NULL;
  1326. PPROCESSOR_PERF_STATE tempStates;
  1327. PPROCESSOR_POWER_STATE pState;
  1328. UCHAR freq;
  1329. UCHAR kneeThrottleIndex = 0;
  1330. UCHAR minThrottle;
  1331. UCHAR maxThrottle;
  1332. UCHAR thermalThrottleIndex = 0;
  1333. ULONG i;
  1334. ULONG perfStatesCount = 0;
  1335. //
  1336. // The first step is to convert the data that was passed to us
  1337. // in PROCESSOR_PERF_LEVEL format over to the PROCESSOR_PERF_STATE
  1338. // format
  1339. //
  1340. if (ProcessorHandler->NumPerfStates) {
  1341. //
  1342. // Because we are going to allocate the perfStates array first
  1343. // so that we can work on it, then copy it to each processor,
  1344. // we must still allocate the memory from non-paged pool.
  1345. // The reason being that we will raising IRQL when we are touching
  1346. // the individual processors.
  1347. //
  1348. perfStatesCount = ProcessorHandler->NumPerfStates;
  1349. perfStates = ExAllocatePoolWithTag(
  1350. NonPagedPool,
  1351. perfStatesCount * sizeof(PROCESSOR_PERF_STATE),
  1352. 'sPoP'
  1353. );
  1354. if (perfStates == NULL) {
  1355. //
  1356. // We can handle this case. We will set the return code to
  1357. // an appropriate failure code and we will clean up the existing
  1358. // processor states. The reason we do this is because this
  1359. // function only gets called if the current states are invalid,
  1360. // so keeping the current ones would make no sense.
  1361. //
  1362. status = STATUS_INSUFFICIENT_RESOURCES;
  1363. perfStatesCount = 0;
  1364. goto PopSetPerfLevelsSetNewStates;
  1365. }
  1366. RtlZeroMemory(
  1367. perfStates,
  1368. perfStatesCount * sizeof(PROCESSOR_PERF_STATE)
  1369. );
  1370. //
  1371. // For completeness, we should make sure that the highest performance
  1372. // state has its flag set.
  1373. //
  1374. perfStates[0].Flags |= POP_THROTTLE_NON_LINEAR;
  1375. //
  1376. // Initialize each of the PROCESSOR_PERF_STATE entries
  1377. //
  1378. for (i = 0; i < perfStatesCount; i++) {
  1379. perfStates[i].PercentFrequency =
  1380. ProcessorHandler->PerfLevel[i].PercentFrequency;
  1381. //
  1382. // If this is a Processor Performance State (Frequency and Voltage),
  1383. // then mark it as a Non-Linear state.
  1384. //
  1385. ASSERT(ProcessorHandler->PerfLevel[i].Flags);
  1386. if (ProcessorHandler->PerfLevel[i].Flags & PROCESSOR_STATE_TYPE_PERFORMANCE) {
  1387. perfStates[i].Flags |= POP_THROTTLE_NON_LINEAR;
  1388. }
  1389. }
  1390. //
  1391. // Calculate the increase level, decrease level, increase time,
  1392. // decrease time, and min capacity information
  1393. //
  1394. PopCalculatePerfIncreaseLevel( perfStates, perfStatesCount );
  1395. PopCalculatePerfDecreaseLevel( perfStates, perfStatesCount );
  1396. PopCalculatePerfMinCapacity( perfStates, perfStatesCount );
  1397. PopCalculatePerfIncreaseDecreaseTime(
  1398. perfStates,
  1399. perfStatesCount,
  1400. ProcessorHandler
  1401. );
  1402. //
  1403. // Calculate where the knee in the performance curve is...
  1404. //
  1405. for (i = (UCHAR) perfStatesCount; i >= 1; i--) {
  1406. if (perfStates[i-1].Flags & POP_THROTTLE_NON_LINEAR) {
  1407. kneeThrottleIndex = (UCHAR) i-1;
  1408. break;
  1409. }
  1410. }
  1411. //
  1412. // Find the minimum throttle value which is greater than the
  1413. // PopIdleDefaultMinThrottle and the current maximum throttle
  1414. //
  1415. minThrottle = POP_PERF_SCALE;
  1416. maxThrottle = 0;
  1417. for (i = 0; i < perfStatesCount; i ++) {
  1418. freq = perfStates[i].PercentFrequency;
  1419. if (freq < minThrottle && freq >= PopIdleDefaultMinThrottle) {
  1420. minThrottle = freq;
  1421. }
  1422. if (freq > maxThrottle && freq >= PopIdleDefaultMinThrottle) {
  1423. //
  1424. // Note that for now, the thermal throttle index should
  1425. // be the same as the max throttle index
  1426. //
  1427. maxThrottle = freq;
  1428. thermalThrottleIndex = (UCHAR) i;
  1429. }
  1430. }
  1431. //
  1432. // Make sure that we can run at *SOME* speed
  1433. //
  1434. ASSERT( maxThrottle >= PopIdleDefaultMinThrottle );
  1435. //
  1436. // Set the Time Delta and Time ticks for the idle loop based upon
  1437. // the hardware latency...
  1438. //
  1439. PopPerfTimeDelta = ProcessorHandler->HardwareLatency;
  1440. PopPerfTimeTicks = PopPerfTimeDelta * US2TIME / KeQueryTimeIncrement() + 1;
  1441. }
  1442. PopSetPerfLevelsSetNewStates:
  1443. if (!perfStates) {
  1444. //
  1445. // We don't have any perf states, so these should be remembered
  1446. // as not being setable
  1447. //
  1448. maxThrottle = minThrottle = POP_PERF_SCALE;
  1449. }
  1450. //
  1451. // At this point, we need to update the status of all the processors
  1452. //
  1453. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1454. processors = KeActiveProcessors;
  1455. currentAffinity = 1;
  1456. while (processors) {
  1457. if (!(processors & currentAffinity)) {
  1458. currentAffinity <<= 1;
  1459. continue;
  1460. }
  1461. //
  1462. // Remember that we did this processor and make sure that
  1463. // we are actually running on that processor. This ensures
  1464. // that we are synchronized with the DPC and idle loop routines
  1465. //
  1466. processors &= ~currentAffinity;
  1467. KeSetSystemAffinityThread(currentAffinity);
  1468. currentAffinity <<= 1;
  1469. //
  1470. // To make sure that we aren't pre-empted, we must raise to
  1471. // DISPATCH_LEVEL...
  1472. //
  1473. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql );
  1474. //
  1475. // Get the PRCB nad PPROCESSOR_POWER_STATE structures that
  1476. // we will need to manipulate
  1477. //
  1478. prcb = KeGetCurrentPrcb();
  1479. pState = &(prcb->PowerState);
  1480. //
  1481. // Remember what our thermal limit is. Since we precalculate this
  1482. // value, it doesn't matter if we have perf states or not...
  1483. //
  1484. pState->ThermalThrottleLimit = maxThrottle;
  1485. pState->ThermalThrottleIndex = thermalThrottleIndex;
  1486. //
  1487. // Likewise, remember what the min and max throttle values for the
  1488. // processor are. Since we precalculate these numbers, it doesn't
  1489. // matter if processor throttling is supported or not
  1490. //
  1491. pState->ProcessorMinThrottle = minThrottle;
  1492. pState->ProcessorMaxThrottle = maxThrottle;
  1493. //
  1494. // To get the bookkeeping to work out correctly, we will
  1495. // set the current throttle to 0% (which isn't possible, or
  1496. // shouldn't be...), set the current index to the last state,
  1497. // and set the tick count to the current time
  1498. //
  1499. pState->PerfTickCount = POP_CUR_TIME(prcb);
  1500. if (perfStatesCount) {
  1501. pState->CurrentThrottleIndex = (UCHAR) (perfStatesCount - 1);
  1502. pState->CurrentThrottle = perfStates[(perfStatesCount-1)].PercentFrequency;
  1503. } else {
  1504. pState->CurrentThrottle = POP_PERF_SCALE;
  1505. pState->CurrentThrottleIndex = 0;
  1506. }
  1507. //
  1508. // Reset the Knee index. This indicates where the knee
  1509. // in the performance curve is.
  1510. //
  1511. pState->KneeThrottleIndex = kneeThrottleIndex;
  1512. //
  1513. // Reset the throttle limit index. This value ranges between the
  1514. // knee and the end of the curve, starting with the knee.
  1515. //
  1516. pState->ThrottleLimitIndex = kneeThrottleIndex;
  1517. //
  1518. // Reset these values since it doesn't make much sense to keep
  1519. // track of them globally instead of on a "per-perf-state" basis
  1520. //
  1521. pState->PromotionCount = 0;
  1522. pState->DemotionCount = 0;
  1523. //
  1524. // Reset these values to something that makes sense. We can assume
  1525. // that we started at 100% busy and 0% C3 Idle
  1526. //
  1527. pState->LastBusyPercentage = 100;
  1528. pState->LastC3Percentage = 0;
  1529. //
  1530. // If there is already a perf state present for this processor
  1531. // then free it. Note that since we are pre-empting everyone else
  1532. // this should be a safe operation..
  1533. //
  1534. if (pState->PerfStates) {
  1535. ExFreePool(pState->PerfStates);
  1536. pState->PerfStates = NULL;
  1537. pState->PerfStatesCount = 0;
  1538. }
  1539. //
  1540. // At this point, we have to distinguish our behaviour based on
  1541. // whether or not we have new perfs states...
  1542. //
  1543. if (perfStates) {
  1544. //
  1545. // We do, so lets allocate some memory and make a copy of
  1546. // the template that we have already created. Note that we
  1547. // wish we could allocate these structures from an NPAGED
  1548. // lookaside list, but we can't because we don't know how many
  1549. // elements we will need to allocate
  1550. //
  1551. tempStates = ExAllocatePoolWithTag(
  1552. NonPagedPool,
  1553. perfStatesCount * sizeof(PROCESSOR_PERF_STATE),
  1554. 'sPoP'
  1555. );
  1556. if (tempStates == NULL) {
  1557. //
  1558. // Not being able to allocate this structure is surely
  1559. // fatal. We currently depend on the structures being
  1560. // symmetric. I guess one way to handle this is to set
  1561. // an error flag and then clean up all the allocations
  1562. // once we exist this iterate-the-processors loop.
  1563. //
  1564. status = STATUS_INSUFFICIENT_RESOURCES;
  1565. failedAllocation = TRUE;
  1566. //
  1567. // Make sure that we don't indicate that this thread
  1568. // supports throttling
  1569. //
  1570. RtlInterlockedClearBits( &(pState->Flags), PSTATE_SUPPORTS_THROTTLE );
  1571. pState->PerfSetThrottle = NULL;
  1572. KeLowerIrql( oldIrql );
  1573. continue;
  1574. } else {
  1575. //
  1576. // Copy the template to the one associated wit hthe
  1577. // processor
  1578. //
  1579. RtlCopyMemory(
  1580. tempStates,
  1581. perfStates,
  1582. perfStatesCount * sizeof(PROCESSOR_PERF_STATE)
  1583. );
  1584. pState->PerfStates = tempStates;
  1585. pState->PerfStatesCount = (UCHAR) perfStatesCount;
  1586. }
  1587. //
  1588. // Remember that we support processor throttling.
  1589. //
  1590. RtlInterlockedClearBits( &(pState->Flags), PSTATE_CLEAR_MASK);
  1591. RtlInterlockedSetBits(
  1592. &(pState->Flags),
  1593. (PSTATE_SUPPORTS_THROTTLE | PSTATE_NOT_INITIALIZED)
  1594. );
  1595. pState->PerfSetThrottle = ProcessorHandler->SetPerfLevel;
  1596. //
  1597. // Actually set the throttle the appropriate value (since
  1598. // we are already running on the target processor...)
  1599. //
  1600. PopUpdateProcessorThrottle();
  1601. } else {
  1602. //
  1603. // Remember that we do not support processor throttling.
  1604. // Note that we don't have to call PopUpdateProcessorThrottle
  1605. // since without a PopSetThrottle function, its a No-Op.
  1606. //
  1607. RtlInterlockedClearBits( &(pState->Flags), PSTATE_CLEAR_MASK);
  1608. RtlInterlockedSetBits( &(pState->Flags), PSTATE_NOT_INITIALIZED);
  1609. pState->PerfSetThrottle = NULL;
  1610. }
  1611. //
  1612. // At this point, we are done the work for this processors and
  1613. // we should return to our previous IRQL
  1614. //
  1615. KeLowerIrql( oldIrql );
  1616. } // while
  1617. //
  1618. // did we fail an allocation (thus requiring a cleanup)?
  1619. //
  1620. if (failedAllocation) {
  1621. processors = KeActiveProcessors;
  1622. currentAffinity = 1;
  1623. while (processors) {
  1624. if (!(processors & currentAffinity)) {
  1625. currentAffinity <<= 1;
  1626. continue;
  1627. }
  1628. //
  1629. // Do the usual setup...
  1630. //
  1631. processors &= ~currentAffinity;
  1632. KeSetSystemAffinityThread(currentAffinity);
  1633. currentAffinity <<= 1;
  1634. //
  1635. // We need to be running at DPC level to avoid synchronization
  1636. // issues.
  1637. //
  1638. KeRaiseIrql(DISPATCH_LEVEL, &oldIrql );
  1639. //
  1640. // Get the power state information from the processor
  1641. //
  1642. prcb = KeGetCurrentPrcb();
  1643. pState = &(prcb->PowerState);
  1644. //
  1645. // Set everything so that we don't support throttling
  1646. //
  1647. pState->ThermalThrottleLimit = POP_PERF_SCALE;
  1648. pState->ThermalThrottleIndex = 0;
  1649. pState->ProcessorMinThrottle = POP_PERF_SCALE;
  1650. pState->ProcessorMaxThrottle = POP_PERF_SCALE;
  1651. pState->CurrentThrottle = POP_PERF_SCALE;
  1652. pState->PerfTickCount = POP_CUR_TIME(prcb);
  1653. pState->CurrentThrottleIndex = 0;
  1654. pState->KneeThrottleIndex = 0;
  1655. pState->ThrottleLimitIndex = 0;
  1656. //
  1657. // Free the allocated structure, if any
  1658. //
  1659. if (pState->PerfStates) {
  1660. //
  1661. // For the sake of completeness, if there is a perf
  1662. // state supported, then we should grab the highest
  1663. // possible frequency and use that for the the call to
  1664. // Set Throttle...
  1665. //
  1666. maxThrottle = pState->PerfStates[0].PercentFrequency;
  1667. //
  1668. // Free the structure...
  1669. //
  1670. ExFreePool(pState->PerfStates);
  1671. } else {
  1672. //
  1673. // I guess its possible to hit this case if we are
  1674. // looking at the processor for which the allocation
  1675. // failed. But the SetThrottleFunction should be null,
  1676. // so this code might not matter.
  1677. //
  1678. maxThrottle = POP_PERF_SCALE;
  1679. }
  1680. pState->PerfStates = NULL;
  1681. pState->PerfStatesCount = 0;
  1682. //
  1683. // Sanity check says that we should issue a call to set the
  1684. // throttle back to 100% or whatever the highest freq that is
  1685. // supported...
  1686. //
  1687. if (pState->PerfSetThrottle) {
  1688. pState->PerfSetThrottle(maxThrottle);
  1689. }
  1690. //
  1691. // We should actually reset the flags to indicate that
  1692. // we support *nothing* throttle related. This should
  1693. // prevent confusion in the DPC and/or Idle loop
  1694. //
  1695. RtlInterlockedClearBits( &(pState->Flags), PSTATE_CLEAR_MASK);
  1696. pState->PerfSetThrottle = NULL;
  1697. //
  1698. // As usual, we should lower IRQL to what we started at
  1699. //
  1700. KeLowerIrql( oldIrql );
  1701. } // while
  1702. //
  1703. // Make sure that we don't think we support throttling
  1704. //
  1705. PopCapabilities.ProcessorThrottle = FALSE;
  1706. PopCapabilities.ProcessorMinThrottle = POP_PERF_SCALE;
  1707. PopCapabilities.ProcessorMaxThrottle = POP_PERF_SCALE;
  1708. } else {
  1709. //
  1710. // Otherwise, we succeeded, and thus we can use whatever we
  1711. // figured out are the falues for Min/Max Throttle
  1712. //
  1713. PopCapabilities.ProcessorThrottle = (perfStates != NULL);
  1714. PopCapabilities.ProcessorMinThrottle = minThrottle;
  1715. PopCapabilities.ProcessorMaxThrottle = maxThrottle;
  1716. }
  1717. //
  1718. // Finally, return to the appropriate affinity
  1719. //
  1720. KeRevertToUserAffinityThread();
  1721. //
  1722. // Free the memory we allocated
  1723. //
  1724. if (perfStates) {
  1725. ExFreePool(perfStates);
  1726. }
  1727. //
  1728. // And return whatever status we calculated...
  1729. //
  1730. return status;
  1731. }
  1732. NTSTATUS
  1733. PopSetTimer(
  1734. IN PPROCESSOR_POWER_STATE PState,
  1735. IN UCHAR Index
  1736. )
  1737. /*++
  1738. Routine Description:
  1739. This routine is only called within the PopPerfIdle loop. The purpose
  1740. of the routine is to set the timer based upon the conditions expressed
  1741. in the "index" case. This is the index into the processor perf states
  1742. that we will be running for the next interval
  1743. Arguments:
  1744. PState - Processor Power State Information
  1745. Index - Index into the Processor Perf States Array
  1746. Return Value:
  1747. STATUS_SUCCESS - Timer Set
  1748. STATUS_CANCELLED- Timer not Set/Cancelled
  1749. --*/
  1750. {
  1751. NTSTATUS status;
  1752. LONGLONG dueTime;
  1753. //
  1754. // Cancel the timer under the following conditions
  1755. //
  1756. if (Index == 0) {
  1757. //
  1758. // We are 100% throttle, so timer won't do much of anything...
  1759. //
  1760. KeCancelTimer( (PKTIMER) &(PState->PerfTimer) );
  1761. status = STATUS_CANCELLED;
  1762. PoPrint(
  1763. PO_THROTTLE_DETAIL,
  1764. ("PopSetTimer: Timer Cancelled (already 100%)\n")
  1765. );
  1766. } else if (PState->Flags & PSTATE_CONSTANT_THROTTLE &&
  1767. Index == PState->KneeThrottleIndex) {
  1768. //
  1769. // We are at the maximum constant throttle allowed
  1770. //
  1771. KeCancelTimer( (PKTIMER) &(PState->PerfTimer) );
  1772. status = STATUS_CANCELLED;
  1773. PoPrint(
  1774. PO_THROTTLE_DETAIL,
  1775. ("PopSetTimer: Timer Cancelled (at constant)\n")
  1776. );
  1777. } else if (PState->Flags & PSTATE_DEGRADED_THROTTLE &&
  1778. Index == PState->ThrottleLimitIndex) {
  1779. //
  1780. // We are at the maximum degraded throttle allowed
  1781. //
  1782. KeCancelTimer( (PKTIMER) &(PState->PerfTimer) );
  1783. status = STATUS_CANCELLED;
  1784. PoPrint(
  1785. PO_THROTTLE_DETAIL,
  1786. ("PopSetTimer: Timer Cancelled (at degrade)\n")
  1787. );
  1788. } else {
  1789. //
  1790. // No restrictions that we can think of, so set the timer. Note
  1791. // that the semantics of KeSetTimer are useful here --- if
  1792. // the timer has already been set, then this resets it (moves
  1793. // it back to the non-signaled state) and recomputes the period.
  1794. //
  1795. dueTime = -1 * US2TIME * (LONGLONG) PopPerfCriticalTimeDelta;
  1796. KeSetTimer(
  1797. (PKTIMER) &(PState->PerfTimer),
  1798. *(PLARGE_INTEGER) &dueTime,
  1799. &(PState->PerfDpc)
  1800. );
  1801. status = STATUS_SUCCESS;
  1802. PoPrint(
  1803. PO_THROTTLE_DETAIL,
  1804. ("PopSetTimer: Timer set for %ld hundred-nanoseconds\n",
  1805. dueTime
  1806. )
  1807. );
  1808. }
  1809. return status;
  1810. }
  1811. NTSTATUS
  1812. PopSetThrottle(
  1813. IN PPROCESSOR_POWER_STATE PState,
  1814. IN PPROCESSOR_PERF_STATE PerfStates,
  1815. IN ULONG Index,
  1816. IN ULONG SystemTime,
  1817. IN ULONG IdleTime
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. This routine is called when we want to set the throttle on the processor
  1822. associated with the PState element. Since each processor gets a unique
  1823. PState, this is guaranteed to only apply the throttle to a single
  1824. processor.
  1825. N.B. Since this routine is also responsible for updating the bookkeeping,
  1826. then if a failure occurs when trying to set the throttle, there is no
  1827. need to return a failure code --- the system state will have not been
  1828. updated and the caller will (eventually) retry
  1829. N.B. This routine can only be called at DISPATCH_LEVEL while running
  1830. on the target processor
  1831. Arguments:
  1832. PState - Power State information about the target processor
  1833. PerfStates - Array of Perf States that apply to that processor
  1834. Index - Which perf state to transition to
  1835. SystemTime - Elapsed System Time (for bookkeeping)
  1836. IdleTime - Elapsed Idle Time (for bookkeeping)
  1837. --*/
  1838. {
  1839. NTSTATUS status;
  1840. PKPRCB prcb;
  1841. PKTHREAD thread;
  1842. UCHAR current = PState->CurrentThrottleIndex;
  1843. ASSERT( KeGetCurrentIrql() == DISPATCH_LEVEL );
  1844. ASSERT( KeGetCurrentPrcb() == CONTAINING_RECORD( PState, KPRCB, PowerState ) );
  1845. ASSERT( PState != NULL && PerfStates != NULL );
  1846. ASSERT( PState->PerfSetThrottle != NULL );
  1847. PoPrint(
  1848. PO_THROTTLE,
  1849. ("PopSetThrottle: Index=%d (%d%%) at %ld (system) %ld (idle)\n",
  1850. Index,
  1851. PerfStates[Index].PercentFrequency,
  1852. SystemTime,
  1853. IdleTime
  1854. )
  1855. );
  1856. //
  1857. // If there is, then attempt to set it to the desired state
  1858. //
  1859. status = PState->PerfSetThrottle(PerfStates[Index].PercentFrequency);
  1860. if (!NT_SUCCESS(status)) {
  1861. //
  1862. // We failed. Update the Error tracking bookkeeping
  1863. //
  1864. PState->ErrorCount++;
  1865. PState->RetryCount++;
  1866. //
  1867. // No reason to update the other bookkeeping
  1868. //
  1869. PoPrint(
  1870. PO_THROTTLE,
  1871. ("PopSetThrottle: Index=%d FAILED!\n",
  1872. Index
  1873. )
  1874. );
  1875. return status;
  1876. }
  1877. //
  1878. // Get the prcb so that that we can update the kernel and idle threads
  1879. //
  1880. prcb = KeGetCurrentPrcb();
  1881. thread = prcb->IdleThread;
  1882. SystemTime = POP_CUR_TIME(prcb);
  1883. IdleTime = thread->KernelTime;
  1884. PoPrint(
  1885. PO_THROTTLE,
  1886. ("PopSetThrottle: Index=%d (%d%%) now at %ld (system) %ld (idle)\n",
  1887. Index,
  1888. PerfStates[Index].PercentFrequency,
  1889. SystemTime,
  1890. IdleTime
  1891. )
  1892. );
  1893. //
  1894. // Update the bookkeeping information for the current state
  1895. //
  1896. if (!(PState->Flags & PSTATE_NOT_INITIALIZED) ) {
  1897. ASSERT( current < PState->PerfStatesCount );
  1898. PerfStates[current].PerformanceTime +=
  1899. (SystemTime - PState->PerfTickCount);
  1900. } else {
  1901. //
  1902. // We have successfully placed the CPU into a known state
  1903. //
  1904. RtlInterlockedClearBits( &(PState->Flags), PSTATE_NOT_INITIALIZED);
  1905. }
  1906. //
  1907. // Update the current throttle information
  1908. //
  1909. PState->CurrentThrottle = PerfStates[Index].PercentFrequency;
  1910. PState->CurrentThrottleIndex = (UCHAR) Index;
  1911. //
  1912. // Update our idea of what the current tick counts are
  1913. //
  1914. PState->PerfIdleTime = IdleTime;
  1915. PState->PerfSystemTime = SystemTime;
  1916. PState->PerfTickCount = SystemTime;
  1917. //
  1918. // Reset our retry count since we have succeeded in the state transition
  1919. //
  1920. PState->RetryCount = 0;
  1921. //
  1922. // Remember how much time we spent in C3 at this point
  1923. //
  1924. PState->PreviousC3StateTime = PState->TotalIdleStateTime[2];
  1925. return status;
  1926. }
  1927. NTSTATUS
  1928. FASTCALL
  1929. PopThunkSetThrottle(
  1930. IN UCHAR Throttle
  1931. )
  1932. /*++
  1933. Routine Description:
  1934. Thunks that converts from the old flavor of throttle setting (fixed-size steps)
  1935. to the new flavor (percentage)
  1936. Arguments:
  1937. Throttle - Supplies the percentage of throttle requested
  1938. Return Value:
  1939. NTSTATUS
  1940. --*/
  1941. {
  1942. //
  1943. // Convert percentage back into level/scale. Add scale-1 so that we round up to recover
  1944. // from the truncation when we did the original divide.
  1945. //
  1946. PopRealSetThrottle((Throttle*PopThunkThrottleScale + PopThunkThrottleScale - 1)/POP_PERF_SCALE);
  1947. return STATUS_SUCCESS;
  1948. }
  1949. VOID
  1950. PopUpdateAllThrottles(
  1951. VOID
  1952. )
  1953. /*++
  1954. Routine Description:
  1955. This is the heart of the throttling policy. This routine computes
  1956. the correct speed for each CPU, based on all current information.
  1957. If this speed is different than the current speed, then throttling
  1958. is applied.
  1959. This routine may be called from any component to trigger computing
  1960. and applying a new throttle value.
  1961. Arguments:
  1962. None.
  1963. Return Value:
  1964. None.
  1965. --*/
  1966. {
  1967. KAFFINITY processors;
  1968. KAFFINITY currentAffinity;
  1969. KIRQL oldIrql;
  1970. PPROCESSOR_POWER_STATE pState;
  1971. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1972. processors = KeActiveProcessors;
  1973. currentAffinity = 1;
  1974. while (processors) {
  1975. if (processors & currentAffinity) {
  1976. processors &= ~currentAffinity;
  1977. KeSetSystemAffinityThread(currentAffinity);
  1978. //
  1979. // Ensure that all calls to PopUpdateProcessorThrottle
  1980. // are done at DISPATCH_LEVEL (to properly synchronize.
  1981. //
  1982. KeRaiseIrql( DISPATCH_LEVEL, &oldIrql );
  1983. //
  1984. // Optimization: If we haven't marked the prcb->powerstate
  1985. // as supporting throttling, then don't bother making the
  1986. // call
  1987. //
  1988. pState = &(KeGetCurrentPrcb()->PowerState);
  1989. if (pState->Flags & PSTATE_SUPPORTS_THROTTLE) {
  1990. PopUpdateProcessorThrottle();
  1991. }
  1992. //
  1993. // Return to the previous Irql
  1994. //
  1995. KeLowerIrql( oldIrql );
  1996. }
  1997. currentAffinity <<= 1;
  1998. }
  1999. KeRevertToUserAffinityThread();
  2000. }
  2001. VOID
  2002. PopUpdateProcessorThrottle(
  2003. VOID
  2004. )
  2005. /*++
  2006. Routine Description:
  2007. Computes and applies the correct throttle speed for the current CPU.
  2008. Affinity must be set to the CPU whose throttle is to be set.
  2009. N.B. This function is always called at DPC level within the context
  2010. of the target processor
  2011. Arguments:
  2012. None
  2013. Return Value:
  2014. None
  2015. --*/
  2016. {
  2017. PKPRCB prcb;
  2018. PPROCESSOR_PERF_STATE perfStates;
  2019. PPROCESSOR_POWER_STATE pState;
  2020. UCHAR i;
  2021. UCHAR index;
  2022. UCHAR newLimit;
  2023. UCHAR perfStatesCount;
  2024. ULONG idleTime;
  2025. ULONG time;
  2026. //
  2027. // Get the power state structure from the PRCB
  2028. //
  2029. prcb = KeGetCurrentPrcb();
  2030. pState = &(prcb->PowerState);
  2031. //
  2032. // Sanity check
  2033. //
  2034. if (!(pState->Flags & PSTATE_SUPPORTS_THROTTLE)) {
  2035. return;
  2036. }
  2037. //
  2038. // Get the current information such as current throttle,
  2039. // current throttle index, current system time, and current
  2040. // idle time
  2041. //
  2042. newLimit = pState->CurrentThrottle;
  2043. index = pState->CurrentThrottleIndex;
  2044. time = POP_CUR_TIME(prcb);
  2045. idleTime = prcb->IdleThread->KernelTime;
  2046. //
  2047. // We will need to refer to these frequently
  2048. //
  2049. perfStates = pState->PerfStates;
  2050. perfStatesCount = pState->PerfStatesCount;
  2051. //
  2052. // Setup all the flags. Clear any that we might not need.
  2053. //
  2054. RtlInterlockedClearBits( &(pState->Flags), PSTATE_THROTTLE_MASK);
  2055. //
  2056. // If we are on AC, then we always want to run at the highest
  2057. // possible speed. However, in case that we don't want to do that
  2058. // in the future (its fairly restrictive), we can assume that the
  2059. // AC policies set dynamic throttling to PO_THROTTLE_NONE. That way
  2060. // if someone DOES want dynamic throttling on AC, they can just edit
  2061. // the policy
  2062. //
  2063. if (PopProcessorPolicy->DynamicThrottle == PO_THROTTLE_NONE) {
  2064. //
  2065. // We precomputed what the max throttle should be
  2066. //
  2067. index = pState->ThermalThrottleIndex;
  2068. newLimit = perfStates[index].PercentFrequency;
  2069. } else {
  2070. //
  2071. // No matter what, we are taking an adaptive policy...
  2072. //
  2073. RtlInterlockedSetBits( &(pState->Flags), PSTATE_ADAPTIVE_THROTTLE );
  2074. //
  2075. // We are on DC, apply the appropriate heuristics based on
  2076. // the dynamic throttling policy
  2077. //
  2078. switch (PopProcessorPolicy->DynamicThrottle) {
  2079. case PO_THROTTLE_CONSTANT:
  2080. //
  2081. // We have pre-computed the optimal point on the graph already.
  2082. // So, we might as well use it...
  2083. //
  2084. index = pState->KneeThrottleIndex;
  2085. newLimit = perfStates[index].PercentFrequency;
  2086. //
  2087. // Set the constant flag
  2088. //
  2089. RtlInterlockedSetBits( &(pState->Flags), PSTATE_CONSTANT_THROTTLE );
  2090. break;
  2091. case PO_THROTTLE_DEGRADE:
  2092. //
  2093. // We calculate the limit of the degrade throttle on the fly
  2094. //
  2095. index = pState->ThrottleLimitIndex;
  2096. newLimit = perfStates[index].PercentFrequency;
  2097. //
  2098. // Set the degraded flag
  2099. //
  2100. RtlInterlockedSetBits( &(pState->Flags), PSTATE_DEGRADED_THROTTLE );
  2101. break;
  2102. default:
  2103. //
  2104. // In case of the default (ie: unknown, simply dump a message)
  2105. //
  2106. PoPrint(
  2107. PO_THROTTLE,
  2108. ("PopUpdateProcessorThrottle - unimplemented "
  2109. "dynamic throttle %d\n",
  2110. PopProcessorPolicy->DynamicThrottle)
  2111. );
  2112. //
  2113. // Fall through...
  2114. //
  2115. case PO_THROTTLE_ADAPTIVE:
  2116. break;
  2117. } // switch
  2118. //
  2119. // See if we are over the thermal limit...
  2120. //
  2121. ASSERT( pState->ThermalThrottleLimit >= pState->ProcessorMinThrottle );
  2122. if (newLimit > pState->ThermalThrottleLimit) {
  2123. PoPrint(
  2124. PO_THROTTLE,
  2125. ("PopUpdateProcessorThrottle - new throttle limit %d over "
  2126. " thermal throttle limit %d\n",
  2127. newLimit,
  2128. pState->ThermalThrottleLimit)
  2129. );
  2130. newLimit = pState->ThermalThrottleLimit;
  2131. index = pState->ThermalThrottleIndex;
  2132. }
  2133. } // if () { } else { }
  2134. //
  2135. // Special Cases
  2136. //
  2137. if (pState->Flags & PSTATE_DISABLE_THROTTLE_INRUSH) {
  2138. //
  2139. // InRush power irp outstanding --- force the throttle to goto
  2140. // the knee in the curve
  2141. //
  2142. index = pState->KneeThrottleIndex;
  2143. newLimit = perfStates[index].PercentFrequency;
  2144. } else if (pState->Flags & PSTATE_DISABLE_THROTTLE_NTAPI) {
  2145. //
  2146. // We are trying to do a power management API. Pick the closest
  2147. // thing to 100% and "rush-to-wait"
  2148. //
  2149. index = 0;
  2150. newLimit = perfStates[index].PercentFrequency;
  2151. }
  2152. //
  2153. // Special Case to deal with the initialization problem. If this
  2154. // flag is set, then we don't really know which processor state we
  2155. // are currently in, so we set it without updating the bookkeeping
  2156. //
  2157. if (pState->Flags & PSTATE_NOT_INITIALIZED) {
  2158. PoPrint(
  2159. PO_THROTTLE,
  2160. ("PopUpdateProcessorThrottle - setting CPU throttle to %d\n",
  2161. newLimit)
  2162. );
  2163. PopSetThrottle(
  2164. pState,
  2165. perfStates,
  2166. index,
  2167. time,
  2168. idleTime
  2169. );
  2170. return;
  2171. }
  2172. //
  2173. // Apply the new throttle if there has been a change
  2174. //
  2175. if (newLimit != pState->CurrentThrottle) {
  2176. PoPrint(
  2177. PO_THROTTLE,
  2178. ("PopUpdateProcessorThrottle - setting CPU throttle to %d\n",
  2179. newLimit)
  2180. );
  2181. if (newLimit < pState->CurrentThrottle) {
  2182. pState->DemotionCount++;
  2183. perfStates[pState->CurrentThrottleIndex].DecreaseCount++;
  2184. } else {
  2185. pState->PromotionCount++;
  2186. perfStates[pState->CurrentThrottleIndex].IncreaseCount++;
  2187. }
  2188. PopSetThrottle(
  2189. pState,
  2190. perfStates,
  2191. index,
  2192. time,
  2193. idleTime
  2194. );
  2195. }
  2196. }