sched_bsd.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719
  1. /* $OpenBSD: sched_bsd.c,v 1.41 2015/03/14 03:38:50 jsg Exp $ */
  2. /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */
  3. /*-
  4. * Copyright (c) 1982, 1986, 1990, 1991, 1993
  5. * The Regents of the University of California. All rights reserved.
  6. * (c) UNIX System Laboratories, Inc.
  7. * All or some portions of this file are derived from material licensed
  8. * to the University of California by American Telephone and Telegraph
  9. * Co. or Unix System Laboratories, Inc. and are reproduced herein with
  10. * the permission of UNIX System Laboratories, Inc.
  11. *
  12. * Redistribution and use in source and binary forms, with or without
  13. * modification, are permitted provided that the following conditions
  14. * are met:
  15. * 1. Redistributions of source code must retain the above copyright
  16. * notice, this list of conditions and the following disclaimer.
  17. * 2. Redistributions in binary form must reproduce the above copyright
  18. * notice, this list of conditions and the following disclaimer in the
  19. * documentation and/or other materials provided with the distribution.
  20. * 3. Neither the name of the University nor the names of its contributors
  21. * may be used to endorse or promote products derived from this software
  22. * without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  25. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  26. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  27. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  28. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  29. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  30. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  31. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  32. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  33. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  34. * SUCH DAMAGE.
  35. *
  36. * @(#)kern_synch.c 8.6 (Berkeley) 1/21/94
  37. */
  38. #include <sys/param.h>
  39. #include <sys/systm.h>
  40. #include <sys/proc.h>
  41. #include <sys/kernel.h>
  42. #include <sys/malloc.h>
  43. #include <sys/signalvar.h>
  44. #include <sys/resourcevar.h>
  45. #include <uvm/uvm_extern.h>
  46. #include <sys/sched.h>
  47. #include <sys/timeout.h>
  48. #ifdef KTRACE
  49. #include <sys/ktrace.h>
  50. #endif
  51. int lbolt; /* once a second sleep address */
  52. int rrticks_init; /* # of hardclock ticks per roundrobin() */
  53. #ifdef MULTIPROCESSOR
  54. struct __mp_lock sched_lock;
  55. #endif
  56. void schedcpu(void *);
  57. void
  58. scheduler_start(void)
  59. {
  60. static struct timeout schedcpu_to;
  61. /*
  62. * We avoid polluting the global namespace by keeping the scheduler
  63. * timeouts static in this function.
  64. * We setup the timeouts here and kick schedcpu and roundrobin once to
  65. * make them do their job.
  66. */
  67. timeout_set(&schedcpu_to, schedcpu, &schedcpu_to);
  68. rrticks_init = hz / 10;
  69. schedcpu(&schedcpu_to);
  70. }
  71. /*
  72. * Force switch among equal priority processes every 100ms.
  73. */
  74. void
  75. roundrobin(struct cpu_info *ci)
  76. {
  77. struct schedstate_percpu *spc = &ci->ci_schedstate;
  78. spc->spc_rrticks = rrticks_init;
  79. if (ci->ci_curproc != NULL) {
  80. if (spc->spc_schedflags & SPCF_SEENRR) {
  81. /*
  82. * The process has already been through a roundrobin
  83. * without switching and may be hogging the CPU.
  84. * Indicate that the process should yield.
  85. */
  86. atomic_setbits_int(&spc->spc_schedflags,
  87. SPCF_SHOULDYIELD);
  88. } else {
  89. atomic_setbits_int(&spc->spc_schedflags,
  90. SPCF_SEENRR);
  91. }
  92. }
  93. if (spc->spc_nrun)
  94. need_resched(ci);
  95. }
  96. /*
  97. * Constants for digital decay and forget:
  98. * 90% of (p_estcpu) usage in 5 * loadav time
  99. * 95% of (p_pctcpu) usage in 60 seconds (load insensitive)
  100. * Note that, as ps(1) mentions, this can let percentages
  101. * total over 100% (I've seen 137.9% for 3 processes).
  102. *
  103. * Note that hardclock updates p_estcpu and p_cpticks independently.
  104. *
  105. * We wish to decay away 90% of p_estcpu in (5 * loadavg) seconds.
  106. * That is, the system wants to compute a value of decay such
  107. * that the following for loop:
  108. * for (i = 0; i < (5 * loadavg); i++)
  109. * p_estcpu *= decay;
  110. * will compute
  111. * p_estcpu *= 0.1;
  112. * for all values of loadavg:
  113. *
  114. * Mathematically this loop can be expressed by saying:
  115. * decay ** (5 * loadavg) ~= .1
  116. *
  117. * The system computes decay as:
  118. * decay = (2 * loadavg) / (2 * loadavg + 1)
  119. *
  120. * We wish to prove that the system's computation of decay
  121. * will always fulfill the equation:
  122. * decay ** (5 * loadavg) ~= .1
  123. *
  124. * If we compute b as:
  125. * b = 2 * loadavg
  126. * then
  127. * decay = b / (b + 1)
  128. *
  129. * We now need to prove two things:
  130. * 1) Given factor ** (5 * loadavg) ~= .1, prove factor == b/(b+1)
  131. * 2) Given b/(b+1) ** power ~= .1, prove power == (5 * loadavg)
  132. *
  133. * Facts:
  134. * For x close to zero, exp(x) =~ 1 + x, since
  135. * exp(x) = 0! + x**1/1! + x**2/2! + ... .
  136. * therefore exp(-1/b) =~ 1 - (1/b) = (b-1)/b.
  137. * For x close to zero, ln(1+x) =~ x, since
  138. * ln(1+x) = x - x**2/2 + x**3/3 - ... -1 < x < 1
  139. * therefore ln(b/(b+1)) = ln(1 - 1/(b+1)) =~ -1/(b+1).
  140. * ln(.1) =~ -2.30
  141. *
  142. * Proof of (1):
  143. * Solve (factor)**(power) =~ .1 given power (5*loadav):
  144. * solving for factor,
  145. * ln(factor) =~ (-2.30/5*loadav), or
  146. * factor =~ exp(-1/((5/2.30)*loadav)) =~ exp(-1/(2*loadav)) =
  147. * exp(-1/b) =~ (b-1)/b =~ b/(b+1). QED
  148. *
  149. * Proof of (2):
  150. * Solve (factor)**(power) =~ .1 given factor == (b/(b+1)):
  151. * solving for power,
  152. * power*ln(b/(b+1)) =~ -2.30, or
  153. * power =~ 2.3 * (b + 1) = 4.6*loadav + 2.3 =~ 5*loadav. QED
  154. *
  155. * Actual power values for the implemented algorithm are as follows:
  156. * loadav: 1 2 3 4
  157. * power: 5.68 10.32 14.94 19.55
  158. */
  159. /* calculations for digital decay to forget 90% of usage in 5*loadav sec */
  160. #define loadfactor(loadav) (2 * (loadav))
  161. #define decay_cpu(loadfac, cpu) (((loadfac) * (cpu)) / ((loadfac) + FSCALE))
  162. /* decay 95% of `p_pctcpu' in 60 seconds; see CCPU_SHIFT before changing */
  163. fixpt_t ccpu = 0.95122942450071400909 * FSCALE; /* exp(-1/20) */
  164. /*
  165. * If `ccpu' is not equal to `exp(-1/20)' and you still want to use the
  166. * faster/more-accurate formula, you'll have to estimate CCPU_SHIFT below
  167. * and possibly adjust FSHIFT in "param.h" so that (FSHIFT >= CCPU_SHIFT).
  168. *
  169. * To estimate CCPU_SHIFT for exp(-1/20), the following formula was used:
  170. * 1 - exp(-1/20) ~= 0.0487 ~= 0.0488 == 1 (fixed pt, *11* bits).
  171. *
  172. * If you don't want to bother with the faster/more-accurate formula, you
  173. * can set CCPU_SHIFT to (FSHIFT + 1) which will use a slower/less-accurate
  174. * (more general) method of calculating the %age of CPU used by a process.
  175. */
  176. #define CCPU_SHIFT 11
  177. /*
  178. * Recompute process priorities, every second.
  179. */
  180. void
  181. schedcpu(void *arg)
  182. {
  183. struct timeout *to = (struct timeout *)arg;
  184. fixpt_t loadfac = loadfactor(averunnable.ldavg[0]);
  185. struct proc *p;
  186. int s;
  187. unsigned int newcpu;
  188. int phz;
  189. /*
  190. * If we have a statistics clock, use that to calculate CPU
  191. * time, otherwise revert to using the profiling clock (which,
  192. * in turn, defaults to hz if there is no separate profiling
  193. * clock available)
  194. */
  195. phz = stathz ? stathz : profhz;
  196. KASSERT(phz);
  197. LIST_FOREACH(p, &allproc, p_list) {
  198. /*
  199. * Increment time in/out of memory and sleep time
  200. * (if sleeping). We ignore overflow; with 16-bit int's
  201. * (remember them?) overflow takes 45 days.
  202. */
  203. if (p->p_stat == SSLEEP || p->p_stat == SSTOP)
  204. p->p_slptime++;
  205. p->p_pctcpu = (p->p_pctcpu * ccpu) >> FSHIFT;
  206. /*
  207. * If the process has slept the entire second,
  208. * stop recalculating its priority until it wakes up.
  209. */
  210. if (p->p_slptime > 1)
  211. continue;
  212. SCHED_LOCK(s);
  213. /*
  214. * p_pctcpu is only for ps.
  215. */
  216. #if (FSHIFT >= CCPU_SHIFT)
  217. p->p_pctcpu += (phz == 100)?
  218. ((fixpt_t) p->p_cpticks) << (FSHIFT - CCPU_SHIFT):
  219. 100 * (((fixpt_t) p->p_cpticks)
  220. << (FSHIFT - CCPU_SHIFT)) / phz;
  221. #else
  222. p->p_pctcpu += ((FSCALE - ccpu) *
  223. (p->p_cpticks * FSCALE / phz)) >> FSHIFT;
  224. #endif
  225. p->p_cpticks = 0;
  226. newcpu = (u_int) decay_cpu(loadfac, p->p_estcpu);
  227. p->p_estcpu = newcpu;
  228. resetpriority(p);
  229. if (p->p_priority >= PUSER) {
  230. if (p->p_stat == SRUN &&
  231. (p->p_priority / SCHED_PPQ) !=
  232. (p->p_usrpri / SCHED_PPQ)) {
  233. remrunqueue(p);
  234. p->p_priority = p->p_usrpri;
  235. setrunqueue(p);
  236. } else
  237. p->p_priority = p->p_usrpri;
  238. }
  239. SCHED_UNLOCK(s);
  240. }
  241. uvm_meter();
  242. wakeup(&lbolt);
  243. timeout_add_sec(to, 1);
  244. }
  245. /*
  246. * Recalculate the priority of a process after it has slept for a while.
  247. * For all load averages >= 1 and max p_estcpu of 255, sleeping for at
  248. * least six times the loadfactor will decay p_estcpu to zero.
  249. */
  250. void
  251. updatepri(struct proc *p)
  252. {
  253. unsigned int newcpu = p->p_estcpu;
  254. fixpt_t loadfac = loadfactor(averunnable.ldavg[0]);
  255. SCHED_ASSERT_LOCKED();
  256. if (p->p_slptime > 5 * loadfac)
  257. p->p_estcpu = 0;
  258. else {
  259. p->p_slptime--; /* the first time was done in schedcpu */
  260. while (newcpu && --p->p_slptime)
  261. newcpu = (int) decay_cpu(loadfac, newcpu);
  262. p->p_estcpu = newcpu;
  263. }
  264. resetpriority(p);
  265. }
  266. /*
  267. * General yield call. Puts the current process back on its run queue and
  268. * performs a voluntary context switch.
  269. */
  270. void
  271. yield(void)
  272. {
  273. struct proc *p = curproc;
  274. int s;
  275. SCHED_LOCK(s);
  276. p->p_priority = p->p_usrpri;
  277. p->p_stat = SRUN;
  278. setrunqueue(p);
  279. p->p_ru.ru_nvcsw++;
  280. mi_switch();
  281. SCHED_UNLOCK(s);
  282. }
  283. /*
  284. * General preemption call. Puts the current process back on its run queue
  285. * and performs an involuntary context switch. If a process is supplied,
  286. * we switch to that process. Otherwise, we use the normal process selection
  287. * criteria.
  288. */
  289. void
  290. preempt(struct proc *newp)
  291. {
  292. struct proc *p = curproc;
  293. int s;
  294. /*
  295. * XXX Switching to a specific process is not supported yet.
  296. */
  297. if (newp != NULL)
  298. panic("preempt: cpu_preempt not yet implemented");
  299. SCHED_LOCK(s);
  300. p->p_priority = p->p_usrpri;
  301. p->p_stat = SRUN;
  302. p->p_cpu = sched_choosecpu(p);
  303. setrunqueue(p);
  304. p->p_ru.ru_nivcsw++;
  305. mi_switch();
  306. SCHED_UNLOCK(s);
  307. }
  308. void
  309. mi_switch(void)
  310. {
  311. struct schedstate_percpu *spc = &curcpu()->ci_schedstate;
  312. struct proc *p = curproc;
  313. struct proc *nextproc;
  314. struct process *pr = p->p_p;
  315. struct rlimit *rlim;
  316. rlim_t secs;
  317. struct timespec ts;
  318. #ifdef MULTIPROCESSOR
  319. int hold_count;
  320. int sched_count;
  321. #endif
  322. assertwaitok();
  323. KASSERT(p->p_stat != SONPROC);
  324. SCHED_ASSERT_LOCKED();
  325. #ifdef MULTIPROCESSOR
  326. /*
  327. * Release the kernel_lock, as we are about to yield the CPU.
  328. */
  329. sched_count = __mp_release_all_but_one(&sched_lock);
  330. if (__mp_lock_held(&kernel_lock))
  331. hold_count = __mp_release_all(&kernel_lock);
  332. else
  333. hold_count = 0;
  334. #endif
  335. /*
  336. * Compute the amount of time during which the current
  337. * process was running, and add that to its total so far.
  338. */
  339. nanouptime(&ts);
  340. if (timespeccmp(&ts, &spc->spc_runtime, <)) {
  341. #if 0
  342. printf("uptime is not monotonic! "
  343. "ts=%lld.%09lu, runtime=%lld.%09lu\n",
  344. (long long)tv.tv_sec, tv.tv_nsec,
  345. (long long)spc->spc_runtime.tv_sec,
  346. spc->spc_runtime.tv_nsec);
  347. #endif
  348. } else {
  349. timespecsub(&ts, &spc->spc_runtime, &ts);
  350. timespecadd(&p->p_rtime, &ts, &p->p_rtime);
  351. }
  352. /* add the time counts for this thread to the process's total */
  353. tuagg_unlocked(pr, p);
  354. /*
  355. * Check if the process exceeds its cpu resource allocation.
  356. * If over max, kill it.
  357. */
  358. rlim = &pr->ps_limit->pl_rlimit[RLIMIT_CPU];
  359. secs = pr->ps_tu.tu_runtime.tv_sec;
  360. if (secs >= rlim->rlim_cur) {
  361. if (secs >= rlim->rlim_max) {
  362. psignal(p, SIGKILL);
  363. } else {
  364. psignal(p, SIGXCPU);
  365. if (rlim->rlim_cur < rlim->rlim_max)
  366. rlim->rlim_cur += 5;
  367. }
  368. }
  369. /*
  370. * Process is about to yield the CPU; clear the appropriate
  371. * scheduling flags.
  372. */
  373. atomic_clearbits_int(&spc->spc_schedflags, SPCF_SWITCHCLEAR);
  374. nextproc = sched_chooseproc();
  375. if (p != nextproc) {
  376. uvmexp.swtch++;
  377. cpu_switchto(p, nextproc);
  378. } else {
  379. p->p_stat = SONPROC;
  380. }
  381. clear_resched(curcpu());
  382. SCHED_ASSERT_LOCKED();
  383. /*
  384. * To preserve lock ordering, we need to release the sched lock
  385. * and grab it after we grab the big lock.
  386. * In the future, when the sched lock isn't recursive, we'll
  387. * just release it here.
  388. */
  389. #ifdef MULTIPROCESSOR
  390. __mp_unlock(&sched_lock);
  391. #endif
  392. SCHED_ASSERT_UNLOCKED();
  393. /*
  394. * We're running again; record our new start time. We might
  395. * be running on a new CPU now, so don't use the cache'd
  396. * schedstate_percpu pointer.
  397. */
  398. KASSERT(p->p_cpu == curcpu());
  399. nanouptime(&p->p_cpu->ci_schedstate.spc_runtime);
  400. #ifdef MULTIPROCESSOR
  401. /*
  402. * Reacquire the kernel_lock now. We do this after we've
  403. * released the scheduler lock to avoid deadlock, and before
  404. * we reacquire the interlock and the scheduler lock.
  405. */
  406. if (hold_count)
  407. __mp_acquire_count(&kernel_lock, hold_count);
  408. __mp_acquire_count(&sched_lock, sched_count + 1);
  409. #endif
  410. }
  411. static __inline void
  412. resched_proc(struct proc *p, u_char pri)
  413. {
  414. struct cpu_info *ci;
  415. /*
  416. * XXXSMP
  417. * This does not handle the case where its last
  418. * CPU is running a higher-priority process, but every
  419. * other CPU is running a lower-priority process. There
  420. * are ways to handle this situation, but they're not
  421. * currently very pretty, and we also need to weigh the
  422. * cost of moving a process from one CPU to another.
  423. *
  424. * XXXSMP
  425. * There is also the issue of locking the other CPU's
  426. * sched state, which we currently do not do.
  427. */
  428. ci = (p->p_cpu != NULL) ? p->p_cpu : curcpu();
  429. if (pri < ci->ci_schedstate.spc_curpriority)
  430. need_resched(ci);
  431. }
  432. /*
  433. * Change process state to be runnable,
  434. * placing it on the run queue if it is in memory,
  435. * and awakening the swapper if it isn't in memory.
  436. */
  437. void
  438. setrunnable(struct proc *p)
  439. {
  440. SCHED_ASSERT_LOCKED();
  441. switch (p->p_stat) {
  442. case 0:
  443. case SRUN:
  444. case SONPROC:
  445. case SDEAD:
  446. case SIDL:
  447. default:
  448. panic("setrunnable");
  449. case SSTOP:
  450. /*
  451. * If we're being traced (possibly because someone attached us
  452. * while we were stopped), check for a signal from the debugger.
  453. */
  454. if ((p->p_p->ps_flags & PS_TRACED) != 0 && p->p_xstat != 0)
  455. atomic_setbits_int(&p->p_siglist, sigmask(p->p_xstat));
  456. case SSLEEP:
  457. unsleep(p); /* e.g. when sending signals */
  458. break;
  459. }
  460. p->p_stat = SRUN;
  461. p->p_cpu = sched_choosecpu(p);
  462. setrunqueue(p);
  463. if (p->p_slptime > 1)
  464. updatepri(p);
  465. p->p_slptime = 0;
  466. resched_proc(p, p->p_priority);
  467. }
  468. /*
  469. * Compute the priority of a process when running in user mode.
  470. * Arrange to reschedule if the resulting priority is better
  471. * than that of the current process.
  472. */
  473. void
  474. resetpriority(struct proc *p)
  475. {
  476. unsigned int newpriority;
  477. SCHED_ASSERT_LOCKED();
  478. newpriority = PUSER + p->p_estcpu +
  479. NICE_WEIGHT * (p->p_p->ps_nice - NZERO);
  480. newpriority = min(newpriority, MAXPRI);
  481. p->p_usrpri = newpriority;
  482. resched_proc(p, p->p_usrpri);
  483. }
  484. /*
  485. * We adjust the priority of the current process. The priority of a process
  486. * gets worse as it accumulates CPU time. The cpu usage estimator (p_estcpu)
  487. * is increased here. The formula for computing priorities (in kern_synch.c)
  488. * will compute a different value each time p_estcpu increases. This can
  489. * cause a switch, but unless the priority crosses a PPQ boundary the actual
  490. * queue will not change. The cpu usage estimator ramps up quite quickly
  491. * when the process is running (linearly), and decays away exponentially, at
  492. * a rate which is proportionally slower when the system is busy. The basic
  493. * principle is that the system will 90% forget that the process used a lot
  494. * of CPU time in 5 * loadav seconds. This causes the system to favor
  495. * processes which haven't run much recently, and to round-robin among other
  496. * processes.
  497. */
  498. void
  499. schedclock(struct proc *p)
  500. {
  501. int s;
  502. SCHED_LOCK(s);
  503. p->p_estcpu = ESTCPULIM(p->p_estcpu + 1);
  504. resetpriority(p);
  505. if (p->p_priority >= PUSER)
  506. p->p_priority = p->p_usrpri;
  507. SCHED_UNLOCK(s);
  508. }
  509. void (*cpu_setperf)(int);
  510. #define PERFPOL_MANUAL 0
  511. #define PERFPOL_AUTO 1
  512. #define PERFPOL_HIGH 2
  513. int perflevel = 100;
  514. int perfpolicy = PERFPOL_MANUAL;
  515. #ifndef SMALL_KERNEL
  516. /*
  517. * The code below handles CPU throttling.
  518. */
  519. #include <sys/sysctl.h>
  520. struct timeout setperf_to;
  521. void setperf_auto(void *);
  522. void
  523. setperf_auto(void *v)
  524. {
  525. static uint64_t *idleticks, *totalticks;
  526. static int downbeats;
  527. int i, j;
  528. int speedup;
  529. CPU_INFO_ITERATOR cii;
  530. struct cpu_info *ci;
  531. uint64_t idle, total, allidle, alltotal;
  532. if (perfpolicy != PERFPOL_AUTO)
  533. return;
  534. if (!idleticks)
  535. if (!(idleticks = mallocarray(ncpusfound, sizeof(*idleticks),
  536. M_DEVBUF, M_NOWAIT | M_ZERO)))
  537. return;
  538. if (!totalticks)
  539. if (!(totalticks = mallocarray(ncpusfound, sizeof(*totalticks),
  540. M_DEVBUF, M_NOWAIT | M_ZERO))) {
  541. free(idleticks, M_DEVBUF,
  542. sizeof(*idleticks) * ncpusfound);
  543. return;
  544. }
  545. alltotal = allidle = 0;
  546. j = 0;
  547. speedup = 0;
  548. CPU_INFO_FOREACH(cii, ci) {
  549. total = 0;
  550. for (i = 0; i < CPUSTATES; i++) {
  551. total += ci->ci_schedstate.spc_cp_time[i];
  552. }
  553. total -= totalticks[j];
  554. idle = ci->ci_schedstate.spc_cp_time[CP_IDLE] - idleticks[j];
  555. if (idle < total / 3)
  556. speedup = 1;
  557. alltotal += total;
  558. allidle += idle;
  559. idleticks[j] += idle;
  560. totalticks[j] += total;
  561. j++;
  562. }
  563. if (allidle < alltotal / 2)
  564. speedup = 1;
  565. if (speedup)
  566. downbeats = 5;
  567. if (speedup && perflevel != 100) {
  568. perflevel = 100;
  569. cpu_setperf(perflevel);
  570. } else if (!speedup && perflevel != 0 && --downbeats <= 0) {
  571. perflevel = 0;
  572. cpu_setperf(perflevel);
  573. }
  574. timeout_add_msec(&setperf_to, 100);
  575. }
  576. int
  577. sysctl_hwsetperf(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
  578. {
  579. int err, newperf;
  580. if (!cpu_setperf)
  581. return EOPNOTSUPP;
  582. if (perfpolicy != PERFPOL_MANUAL)
  583. return sysctl_rdint(oldp, oldlenp, newp, perflevel);
  584. newperf = perflevel;
  585. err = sysctl_int(oldp, oldlenp, newp, newlen, &newperf);
  586. if (err)
  587. return err;
  588. if (newperf > 100)
  589. newperf = 100;
  590. if (newperf < 0)
  591. newperf = 0;
  592. perflevel = newperf;
  593. cpu_setperf(perflevel);
  594. return 0;
  595. }
  596. int
  597. sysctl_hwperfpolicy(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
  598. {
  599. char policy[32];
  600. int err;
  601. if (!cpu_setperf)
  602. return EOPNOTSUPP;
  603. switch (perfpolicy) {
  604. case PERFPOL_MANUAL:
  605. strlcpy(policy, "manual", sizeof(policy));
  606. break;
  607. case PERFPOL_AUTO:
  608. strlcpy(policy, "auto", sizeof(policy));
  609. break;
  610. case PERFPOL_HIGH:
  611. strlcpy(policy, "high", sizeof(policy));
  612. break;
  613. default:
  614. strlcpy(policy, "unknown", sizeof(policy));
  615. break;
  616. }
  617. if (newp == NULL)
  618. return sysctl_rdstring(oldp, oldlenp, newp, policy);
  619. err = sysctl_string(oldp, oldlenp, newp, newlen, policy, sizeof(policy));
  620. if (err)
  621. return err;
  622. if (strcmp(policy, "manual") == 0)
  623. perfpolicy = PERFPOL_MANUAL;
  624. else if (strcmp(policy, "auto") == 0)
  625. perfpolicy = PERFPOL_AUTO;
  626. else if (strcmp(policy, "high") == 0)
  627. perfpolicy = PERFPOL_HIGH;
  628. else
  629. return EINVAL;
  630. if (perfpolicy == PERFPOL_AUTO) {
  631. timeout_add_msec(&setperf_to, 200);
  632. } else if (perfpolicy == PERFPOL_HIGH) {
  633. perflevel = 100;
  634. cpu_setperf(perflevel);
  635. }
  636. return 0;
  637. }
  638. #endif