Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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