edf.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. /* EDF scheduling */
  10. #include "u.h"
  11. #include "../port/lib.h"
  12. #include "mem.h"
  13. #include "dat.h"
  14. #include "fns.h"
  15. #include "../port/error.h"
  16. #include "../port/edf.h"
  17. #include <trace.h>
  18. /* debugging */
  19. enum {
  20. Dontprint = 1,
  21. };
  22. #define DPRINT if(Dontprint){}else print
  23. static int32_t now; /* Low order 32 bits of time in µs */
  24. /* Statistics stuff */
  25. uint32_t nilcount;
  26. uint32_t scheds;
  27. uint32_t edfnrun;
  28. int misseddeadlines;
  29. /* Edfschedlock protects modification of admission params */
  30. int edfinited;
  31. QLock edfschedlock;
  32. static Lock thelock;
  33. enum{
  34. Dl, /* Invariant for schedulability test: Dl < Rl */
  35. Rl,
  36. };
  37. static char *testschedulability(Proc*);
  38. static Proc *qschedulability;
  39. enum {
  40. Onemicrosecond = 1,
  41. Onemillisecond = 1000,
  42. Onesecond = 1000000,
  43. OneRound = Onemillisecond/2,
  44. };
  45. static int
  46. timeconv(Fmt *f)
  47. {
  48. char buf[128], *sign;
  49. int64_t t;
  50. buf[0] = 0;
  51. switch(f->r) {
  52. case 'U':
  53. t = va_arg(f->args, uvlong);
  54. break;
  55. case 't': /* vlong in nanoseconds */
  56. t = va_arg(f->args, int32_t);
  57. break;
  58. default:
  59. return fmtstrcpy(f, "(timeconv)");
  60. }
  61. if (t < 0) {
  62. sign = "-";
  63. t = -t;
  64. }
  65. else
  66. sign = "";
  67. if (t > Onesecond){
  68. t += OneRound;
  69. sprint(buf, "%s%d.%.3ds", sign, (int)(t / Onesecond),
  70. (int)(t % Onesecond)/Onemillisecond);
  71. }else if (t > Onemillisecond)
  72. sprint(buf, "%s%d.%.3dms", sign, (int)(t / Onemillisecond),
  73. (int)(t % Onemillisecond));
  74. else
  75. sprint(buf, "%s%dµs", sign, (int)t);
  76. return fmtstrcpy(f, buf);
  77. }
  78. int32_t edfcycles;
  79. Edf*
  80. edflock(Proc *p)
  81. {
  82. Edf *e;
  83. if (p->edf == nil)
  84. return nil;
  85. ilock(&thelock);
  86. if((e = p->edf) && (e->flags & Admitted)){
  87. thelock.pc = getcallerpc(&p);
  88. #ifdef EDFCYCLES
  89. edfcycles -= lcycles();
  90. #endif
  91. now = µs();
  92. return e;
  93. }
  94. iunlock(&thelock);
  95. return nil;
  96. }
  97. void
  98. edfunlock(void)
  99. {
  100. #ifdef EDFCYCLES
  101. edfcycles += lcycles();
  102. #endif
  103. edfnrun++;
  104. iunlock(&thelock);
  105. }
  106. void
  107. edfinit(Proc*p)
  108. {
  109. if(!edfinited){
  110. fmtinstall('t', timeconv);
  111. edfinited++;
  112. }
  113. now = µs();
  114. DPRINT("%lud edfinit %d[%s]\n", now, p->pid, statename[p->state]);
  115. p->edf = malloc(sizeof(Edf));
  116. if(p->edf == nil)
  117. error(Enomem);
  118. return;
  119. }
  120. static void
  121. deadlineintr(Ureg*, Timer *t)
  122. {
  123. /* Proc reached deadline */
  124. extern int panicking;
  125. Sched *sch;
  126. Proc *p;
  127. if(panicking || active.exiting)
  128. return;
  129. p = t->ta;
  130. now = µs();
  131. DPRINT("%lud deadlineintr %d[%s]\n", now, p->pid, statename[p->state]);
  132. /* If we're interrupting something other than the proc pointed to by t->a,
  133. * we've already achieved recheduling, so we need not do anything
  134. * Otherwise, we must cause a reschedule, but if we call sched()
  135. * here directly, the timer interrupt routine will not finish its business
  136. * Instead, we cause the resched to happen when the interrupted proc
  137. * returns to user space
  138. */
  139. if(p == up){
  140. if(up->trace)
  141. proctrace(up, SInts, 0);
  142. up->delaysched++;
  143. sch = procsched(up);
  144. sch->delayedscheds++;
  145. }
  146. }
  147. static void
  148. release(Proc *p)
  149. {
  150. /* Called with edflock held */
  151. Edf *e;
  152. int32_t n;
  153. int64_t nowns;
  154. e = p->edf;
  155. e->flags &= ~Yield;
  156. if(e->d - now < 0){
  157. e->periods++;
  158. e->r = now;
  159. if((e->flags & Sporadic) == 0){
  160. /*
  161. * Non sporadic processes stay true to their period;
  162. * calculate next release time.
  163. * Second test limits duration of while loop.
  164. */
  165. if((n = now - e->t) > 0){
  166. if(n < e->T)
  167. e->t += e->T;
  168. else
  169. e->t = now + e->T - (n % e->T);
  170. }
  171. }else{
  172. /* Sporadic processes may not be released earlier than
  173. * one period after this release
  174. */
  175. e->t = e->r + e->T;
  176. }
  177. e->d = e->r + e->D;
  178. e->S = e->C;
  179. DPRINT("%lud release %d[%s], r=%lud, d=%lud, t=%lud, S=%lud\n",
  180. now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
  181. if(p->trace){
  182. nowns = todget(nil);
  183. proctrace(p, SRelease, nowns);
  184. proctrace(p, SDeadline, nowns + 1000LL*e->D);
  185. }
  186. }else{
  187. DPRINT("%lud release %d[%s], too late t=%lud, called from %#p\n",
  188. now, p->pid, statename[p->state], e->t, getcallerpc(&p));
  189. }
  190. }
  191. static void
  192. releaseintr(Ureg*, Timer *t)
  193. {
  194. Proc *p;
  195. extern int panicking;
  196. Sched *sch;
  197. Schedq *rq;
  198. if(panicking || active.exiting)
  199. return;
  200. p = t->ta;
  201. if((edflock(p)) == nil)
  202. return;
  203. sch = procsched(p);
  204. DPRINT("%lud releaseintr %d[%s]\n", now, p->pid, statename[p->state]);
  205. switch(p->state){
  206. default:
  207. edfunlock();
  208. return;
  209. case Ready:
  210. /* remove proc from current runq */
  211. rq = &sch->runq[p->priority];
  212. if(dequeueproc(sch, rq, p) != p){
  213. DPRINT("releaseintr: can't find proc or lock race\n");
  214. release(p); /* It'll start best effort */
  215. edfunlock();
  216. return;
  217. }
  218. p->state = Waitrelease;
  219. /* fall through */
  220. case Waitrelease:
  221. release(p);
  222. edfunlock();
  223. if(p->state == Wakeme){
  224. iprint("releaseintr: wakeme\n");
  225. }
  226. ready(p);
  227. if(up){
  228. up->delaysched++;
  229. sch->delayedscheds++;
  230. }
  231. return;
  232. case Running:
  233. release(p);
  234. edfrun(p, 1);
  235. break;
  236. case Wakeme:
  237. release(p);
  238. edfunlock();
  239. if(p->trend)
  240. wakeup(p->trend);
  241. p->trend = nil;
  242. if(up){
  243. up->delaysched++;
  244. sch->delayedscheds++;
  245. }
  246. return;
  247. }
  248. edfunlock();
  249. }
  250. void
  251. edfrecord(Proc *p)
  252. {
  253. int32_t used;
  254. Edf *e;
  255. if((e = edflock(p)) == nil)
  256. return;
  257. used = now - e->s;
  258. if(e->d - now <= 0)
  259. e->edfused += used;
  260. else
  261. e->extraused += used;
  262. if(e->S > 0){
  263. if(e->S <= used){
  264. if(p->trace)
  265. proctrace(p, SSlice, 0);
  266. DPRINT("%lud edfrecord slice used up\n", now);
  267. e->d = now;
  268. e->S = 0;
  269. }else
  270. e->S -= used;
  271. }
  272. e->s = now;
  273. edfunlock();
  274. }
  275. void
  276. edfrun(Proc *p, int edfpri)
  277. {
  278. Edf *e;
  279. int32_t tns;
  280. Sched *sch;
  281. e = p->edf;
  282. sch = procsched(p);
  283. /* Called with edflock held */
  284. if(edfpri){
  285. tns = e->d - now;
  286. if(tns <= 0 || e->S == 0){
  287. /* Deadline reached or resources exhausted,
  288. * deschedule forthwith
  289. */
  290. p->delaysched++;
  291. sch->delayedscheds++;
  292. e->s = now;
  293. return;
  294. }
  295. if(e->S < tns)
  296. tns = e->S;
  297. if(tns < 20)
  298. tns = 20;
  299. e->tns = 1000LL * tns; /* µs to ns */
  300. if(e->tt == nil || e->tf != deadlineintr){
  301. DPRINT("%lud edfrun, deadline=%lud\n", now, tns);
  302. }else{
  303. DPRINT("v");
  304. }
  305. if(p->trace)
  306. proctrace(p, SInte, todget(nil) + e->tns);
  307. e->tmode = Trelative;
  308. e->tf = deadlineintr;
  309. e->ta = p;
  310. timeradd(e);
  311. }else{
  312. DPRINT("<");
  313. }
  314. e->s = now;
  315. }
  316. char *
  317. edfadmit(Proc *p)
  318. {
  319. char *err;
  320. Edf *e;
  321. int i;
  322. Proc *r;
  323. int32_t tns;
  324. e = p->edf;
  325. if (e->flags & Admitted)
  326. return "task state"; /* should never happen */
  327. /* simple sanity checks */
  328. if (e->T == 0)
  329. return "T not set";
  330. if (e->C == 0)
  331. return "C not set";
  332. if (e->D > e->T)
  333. return "D > T";
  334. if (e->D == 0) /* if D is not set, set it to T */
  335. e->D = e->T;
  336. if (e->C > e->D)
  337. return "C > D";
  338. qlock(&edfschedlock);
  339. if (err = testschedulability(p)){
  340. qunlock(&edfschedlock);
  341. return err;
  342. }
  343. e->flags |= Admitted;
  344. edflock(p);
  345. if(p->trace)
  346. proctrace(p, SAdmit, 0);
  347. /* Look for another proc with the same period to synchronize to */
  348. for(i=0; (r = psincref(i)) != nil; i++) {
  349. if(r->state == Dead || r == p){
  350. psdecref(r);
  351. continue;
  352. }
  353. if (r->edf == nil || (r->edf->flags & Admitted) == 0){
  354. psdecref(r);
  355. continue;
  356. }
  357. if (r->edf->T == e->T)
  358. break;
  359. }
  360. if (r == nil){
  361. /* Can't synchronize to another proc, release now */
  362. e->t = now;
  363. e->d = 0;
  364. release(p);
  365. if (p == up){
  366. DPRINT("%lud edfadmit self %d[%s], release now: r=%lud d=%lud t=%lud\n",
  367. now, p->pid, statename[p->state], e->r, e->d, e->t);
  368. /* We're already running */
  369. edfrun(p, 1);
  370. }else{
  371. /* We're releasing another proc */
  372. DPRINT("%lud edfadmit other %d[%s], release now: r=%lud d=%lud t=%lud\n",
  373. now, p->pid, statename[p->state], e->r, e->d, e->t);
  374. p->ta = p;
  375. edfunlock();
  376. qunlock(&edfschedlock);
  377. releaseintr(nil, p);
  378. return nil;
  379. }
  380. }else{
  381. /* Release in synch to something else */
  382. e->t = r->edf->t;
  383. psdecref(r);
  384. if (p == up){
  385. DPRINT("%lud edfadmit self %d[%s], release at %lud\n",
  386. now, p->pid, statename[p->state], e->t);
  387. }else{
  388. DPRINT("%lud edfadmit other %d[%s], release at %lud\n",
  389. now, p->pid, statename[p->state], e->t);
  390. if(e->tt == nil){
  391. e->tf = releaseintr;
  392. e->ta = p;
  393. tns = e->t - now;
  394. if(tns < 20)
  395. tns = 20;
  396. e->tns = 1000LL * tns;
  397. e->tmode = Trelative;
  398. timeradd(e);
  399. }
  400. }
  401. }
  402. edfunlock();
  403. qunlock(&edfschedlock);
  404. return nil;
  405. }
  406. void
  407. edfstop(Proc *p)
  408. {
  409. Edf *e;
  410. if(e = edflock(p)){
  411. DPRINT("%lud edfstop %d[%s]\n", now, p->pid, statename[p->state]);
  412. if(p->trace)
  413. proctrace(p, SExpel, 0);
  414. e->flags &= ~Admitted;
  415. if(e->tt)
  416. timerdel(e);
  417. edfunlock();
  418. }
  419. }
  420. static int
  421. yfn(void *)
  422. {
  423. now = µs();
  424. return up->trend == nil || now - up->edf->r >= 0;
  425. }
  426. void
  427. edfyield(void)
  428. {
  429. /* sleep until next release */
  430. Edf *e;
  431. int32_t n;
  432. if((e = edflock(up)) == nil)
  433. return;
  434. if(up->trace)
  435. proctrace(up, SYield, 0);
  436. if((n = now - e->t) > 0){
  437. if(n < e->T)
  438. e->t += e->T;
  439. else
  440. e->t = now + e->T - (n % e->T);
  441. }
  442. e->r = e->t;
  443. e->flags |= Yield;
  444. e->d = now;
  445. if (up->tt == nil){
  446. n = e->t - now;
  447. if(n < 20)
  448. n = 20;
  449. up->tns = 1000LL * n;
  450. up->tf = releaseintr;
  451. up->tmode = Trelative;
  452. up->ta = up;
  453. up->trend = &up->sleep;
  454. timeradd(up);
  455. }else if(up->tf != releaseintr)
  456. print("edfyield: surprise! %#p\n", up->tf);
  457. edfunlock();
  458. sleep(&up->sleep, yfn, nil);
  459. }
  460. int
  461. edfready(Proc *p)
  462. {
  463. Edf *e;
  464. Sched *sch;
  465. Schedq *rq;
  466. Proc *l, *pp;
  467. int32_t n;
  468. if((e = edflock(p)) == nil)
  469. return 0;
  470. if(p->state == Wakeme && p->r){
  471. iprint("edfready: wakeme\n");
  472. }
  473. if(e->d - now <= 0){
  474. /* past deadline, arrange for next release */
  475. if((e->flags & Sporadic) == 0){
  476. /*
  477. * Non sporadic processes stay true to their period;
  478. * calculate next release time.
  479. */
  480. if((n = now - e->t) > 0){
  481. if(n < e->T)
  482. e->t += e->T;
  483. else
  484. e->t = now + e->T - (n % e->T);
  485. }
  486. }
  487. if(now - e->t < 0){
  488. /* Next release is in the future, schedule it */
  489. if(e->tt == nil || e->tf != releaseintr){
  490. n = e->t - now;
  491. if(n < 20)
  492. n = 20;
  493. e->tns = 1000LL * n;
  494. e->tmode = Trelative;
  495. e->tf = releaseintr;
  496. e->ta = p;
  497. timeradd(e);
  498. DPRINT("%lud edfready %d[%s], release=%lud\n",
  499. now, p->pid, statename[p->state], e->t);
  500. }
  501. if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){
  502. /* If we were running, we've overrun our CPU allocation
  503. * or missed the deadline, continue running best-effort at low priority
  504. * Otherwise we were blocked. If we don't yield on block, we continue
  505. * best effort
  506. */
  507. DPRINT(">");
  508. p->basepri = PriExtra;
  509. p->fixedpri = 1;
  510. edfunlock();
  511. return 0; /* Stick on runq[PriExtra] */
  512. }
  513. DPRINT("%lud edfready %d[%s] wait release at %lud\n",
  514. now, p->pid, statename[p->state], e->t);
  515. p->state = Waitrelease;
  516. edfunlock();
  517. return 1; /* Make runnable later */
  518. }
  519. DPRINT("%lud edfready %d %s release now\n", now, p->pid, statename[p->state]);
  520. /* release now */
  521. release(p);
  522. }
  523. edfunlock();
  524. DPRINT("^");
  525. sch = procsched(p);
  526. rq = &sch->runq[PriEdf];
  527. /* insert in queue in earliest deadline order */
  528. lock(sch);
  529. l = nil;
  530. for(pp = rq->head; pp; pp = pp->rnext){
  531. if(pp->edf->d > e->d)
  532. break;
  533. l = pp;
  534. }
  535. p->rnext = pp;
  536. if (l == nil)
  537. rq->head = p;
  538. else
  539. l->rnext = p;
  540. if(pp == nil)
  541. rq->tail = p;
  542. rq->n++;
  543. sch->nrdy++;
  544. sch->runvec |= 1 << PriEdf;
  545. p->priority = PriEdf;
  546. p->readytime = m->ticks;
  547. p->state = Ready;
  548. unlock(sch);
  549. if(p->trace)
  550. proctrace(p, SReady, 0);
  551. return 1;
  552. }
  553. static void
  554. testenq(Proc *p)
  555. {
  556. Proc *xp, **xpp;
  557. Edf *e;
  558. e = p->edf;
  559. e->testnext = nil;
  560. if (qschedulability == nil) {
  561. qschedulability = p;
  562. return;
  563. }
  564. SET(xp);
  565. for (xpp = &qschedulability; *xpp; xpp = &xp->edf->testnext) {
  566. xp = *xpp;
  567. if (e->testtime - xp->edf->testtime < 0
  568. || (e->testtime == xp->edf->testtime && e->testtype < xp->edf->testtype)){
  569. e->testnext = xp;
  570. *xpp = p;
  571. return;
  572. }
  573. }
  574. assert(xp->edf->testnext == nil);
  575. xp->edf->testnext = p;
  576. }
  577. static char *
  578. testschedulability(Proc *theproc)
  579. {
  580. Proc *p;
  581. int32_t H, G, Cb, ticks;
  582. int steps, i;
  583. /* initialize */
  584. DPRINT("schedulability test %d\n", theproc->pid);
  585. qschedulability = nil;
  586. for(i=0; (p = psincref(i)) != nil; i++) {
  587. if(p->state == Dead){
  588. psdecref(p);
  589. continue;
  590. }
  591. if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc){
  592. psdecref(p);
  593. continue;
  594. }
  595. p->edf->testtype = Rl;
  596. p->edf->testtime = 0;
  597. DPRINT("\tInit: edfenqueue %d\n", p->pid);
  598. testenq(p);
  599. psdecref(p);
  600. }
  601. H=0;
  602. G=0;
  603. for(steps = 0; steps < Maxsteps; steps++){
  604. p = qschedulability;
  605. qschedulability = p->edf->testnext;
  606. ticks = p->edf->testtime;
  607. switch (p->edf->testtype){
  608. case Dl:
  609. H += p->edf->C;
  610. Cb = 0;
  611. DPRINT("\tStep %3d, Ticks %lud, pid %d, deadline, H += %lud → %lud, Cb = %lud\n",
  612. steps, ticks, p->pid, p->edf->C, H, Cb);
  613. if (H+Cb>ticks){
  614. DPRINT("not schedulable\n");
  615. return "not schedulable";
  616. }
  617. p->edf->testtime += p->edf->T - p->edf->D;
  618. p->edf->testtype = Rl;
  619. testenq(p);
  620. break;
  621. case Rl:
  622. DPRINT("\tStep %3d, Ticks %lud, pid %d, release, G %lud, C%lud\n",
  623. steps, ticks, p->pid, p->edf->C, G);
  624. if(ticks && G <= ticks){
  625. DPRINT("schedulable\n");
  626. return nil;
  627. }
  628. G += p->edf->C;
  629. p->edf->testtime += p->edf->D;
  630. p->edf->testtype = Dl;
  631. testenq(p);
  632. break;
  633. default:
  634. assert(0);
  635. }
  636. }
  637. DPRINT("probably not schedulable\n");
  638. return "probably not schedulable";
  639. }