edf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  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, uint64_t);
  54. break;
  55. case 't': /* int64_t 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();
  88. #ifdef EDFCYCLES
  89. edfcycles -= lcycles();
  90. #endif
  91. now = ms();
  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 = ms();
  114. DPRINT("%lu 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* ureg, Timer *t)
  122. {
  123. Proc *up = externup();
  124. /* Proc reached deadline */
  125. extern int panicking;
  126. Sched *sch;
  127. Proc *p;
  128. if(panicking || active.exiting)
  129. return;
  130. p = t->ta;
  131. now = ms();
  132. DPRINT("%lu deadlineintr %d[%s]\n", now, p->pid, statename[p->state]);
  133. /* If we're interrupting something other than the proc pointed to by t->a,
  134. * we've already achieved recheduling, so we need not do anything
  135. * Otherwise, we must cause a reschedule, but if we call sched()
  136. * here directly, the timer interrupt routine will not finish its business
  137. * Instead, we cause the resched to happen when the interrupted proc
  138. * returns to user space
  139. */
  140. if(p == up){
  141. if(up->trace)
  142. proctrace(up, SInts, 0);
  143. up->delaysched++;
  144. sch = procsched(up);
  145. sch->delayedscheds++;
  146. }
  147. }
  148. static void
  149. release(Proc *p)
  150. {
  151. /* Called with edflock held */
  152. Edf *e;
  153. int32_t n;
  154. int64_t nowns;
  155. e = p->edf;
  156. e->flags &= ~Yield;
  157. if(e->d - now < 0){
  158. e->periods++;
  159. e->r = now;
  160. if((e->flags & Sporadic) == 0){
  161. /*
  162. * Non sporadic processes stay true to their period;
  163. * calculate next release time.
  164. * Second test limits duration of while loop.
  165. */
  166. if((n = now - e->t) > 0){
  167. if(n < e->T)
  168. e->t += e->T;
  169. else
  170. e->t = now + e->T - (n % e->T);
  171. }
  172. }else{
  173. /* Sporadic processes may not be released earlier than
  174. * one period after this release
  175. */
  176. e->t = e->r + e->T;
  177. }
  178. e->d = e->r + e->D;
  179. e->S = e->C;
  180. DPRINT("%lu release %d[%s], r=%lu, d=%lu, t=%lu, S=%lu\n",
  181. now, p->pid, statename[p->state], e->r, e->d, e->t, e->S);
  182. if(p->trace){
  183. nowns = todget(nil);
  184. proctrace(p, SRelease, nowns);
  185. proctrace(p, SDeadline, nowns + 1000LL*e->D);
  186. }
  187. }else{
  188. DPRINT("%lu release %d[%s], too late t=%lu, called from %#p\n",
  189. now, p->pid, statename[p->state], e->t, getcallerpc());
  190. }
  191. }
  192. static void
  193. releaseintr(Ureg* ureg, Timer *t)
  194. {
  195. Proc *up = externup();
  196. Proc *p;
  197. extern int panicking;
  198. Sched *sch;
  199. Schedq *rq;
  200. if(panicking || active.exiting)
  201. return;
  202. p = t->ta;
  203. if((edflock(p)) == nil)
  204. return;
  205. sch = procsched(p);
  206. DPRINT("%lu releaseintr %d[%s]\n", now, p->pid, statename[p->state]);
  207. switch(p->state){
  208. default:
  209. edfunlock();
  210. return;
  211. case Ready:
  212. /* remove proc from current runq */
  213. rq = &sch->runq[p->priority];
  214. if(dequeueproc(sch, rq, p) != p){
  215. DPRINT("releaseintr: can't find proc or lock race\n");
  216. release(p); /* It'll start best effort */
  217. edfunlock();
  218. return;
  219. }
  220. p->state = Waitrelease;
  221. /* fall through */
  222. case Waitrelease:
  223. release(p);
  224. edfunlock();
  225. if(p->state == Wakeme){
  226. iprint("releaseintr: wakeme\n");
  227. }
  228. ready(p);
  229. if(up){
  230. up->delaysched++;
  231. sch->delayedscheds++;
  232. }
  233. return;
  234. case Running:
  235. release(p);
  236. edfrun(p, 1);
  237. break;
  238. case Wakeme:
  239. release(p);
  240. edfunlock();
  241. if(p->trend)
  242. wakeup(p->trend);
  243. p->trend = nil;
  244. if(up){
  245. up->delaysched++;
  246. sch->delayedscheds++;
  247. }
  248. return;
  249. }
  250. edfunlock();
  251. }
  252. void
  253. edfrecord(Proc *p)
  254. {
  255. int32_t used;
  256. Edf *e;
  257. if((e = edflock(p)) == nil)
  258. return;
  259. used = now - e->s;
  260. if(e->d - now <= 0)
  261. e->edfused += used;
  262. else
  263. e->extraused += used;
  264. if(e->S > 0){
  265. if(e->S <= used){
  266. if(p->trace)
  267. proctrace(p, SSlice, 0);
  268. DPRINT("%lu edfrecord slice used up\n", now);
  269. e->d = now;
  270. e->S = 0;
  271. }else
  272. e->S -= used;
  273. }
  274. e->s = now;
  275. edfunlock();
  276. }
  277. void
  278. edfrun(Proc *p, int edfpri)
  279. {
  280. Edf *e;
  281. int32_t tns;
  282. Sched *sch;
  283. e = p->edf;
  284. sch = procsched(p);
  285. /* Called with edflock held */
  286. if(edfpri){
  287. tns = e->d - now;
  288. if(tns <= 0 || e->S == 0){
  289. /* Deadline reached or resources exhausted,
  290. * deschedule forthwith
  291. */
  292. p->delaysched++;
  293. sch->delayedscheds++;
  294. e->s = now;
  295. return;
  296. }
  297. if(e->S < tns)
  298. tns = e->S;
  299. if(tns < 20)
  300. tns = 20;
  301. e->Timer.tns = 1000LL * tns; /* µs to ns */
  302. if(e->Timer.tt == nil || e->Timer.tf != deadlineintr){
  303. DPRINT("%lu edfrun, deadline=%lu\n", now, tns);
  304. }else{
  305. DPRINT("v");
  306. }
  307. if(p->trace)
  308. proctrace(p, SInte, todget(nil) + e->Timer.tns);
  309. e->Timer.tmode = Trelative;
  310. e->Timer.tf = deadlineintr;
  311. e->Timer.ta = p;
  312. timeradd(&e->Timer);
  313. }else{
  314. DPRINT("<");
  315. }
  316. e->s = now;
  317. }
  318. char *
  319. edfadmit(Proc *p)
  320. {
  321. Proc *up = externup();
  322. char *err;
  323. Edf *e;
  324. int i;
  325. Proc *r;
  326. int32_t tns;
  327. e = p->edf;
  328. if (e->flags & Admitted)
  329. return "task state"; /* should never happen */
  330. /* simple sanity checks */
  331. if (e->T == 0)
  332. return "T not set";
  333. if (e->C == 0)
  334. return "C not set";
  335. if (e->D > e->T)
  336. return "D > T";
  337. if (e->D == 0) /* if D is not set, set it to T */
  338. e->D = e->T;
  339. if (e->C > e->D)
  340. return "C > D";
  341. qlock(&edfschedlock);
  342. if ((err = testschedulability(p)) != nil){
  343. qunlock(&edfschedlock);
  344. return err;
  345. }
  346. e->flags |= Admitted;
  347. edflock(p);
  348. if(p->trace)
  349. proctrace(p, SAdmit, 0);
  350. /* Look for another proc with the same period to synchronize to */
  351. for(i=0; (r = psincref(i)) != nil; i++) {
  352. if(r->state == Dead || r == p){
  353. psdecref(r);
  354. continue;
  355. }
  356. if (r->edf == nil || (r->edf->flags & Admitted) == 0){
  357. psdecref(r);
  358. continue;
  359. }
  360. if (r->edf->T == e->T)
  361. break;
  362. }
  363. if (r == nil){
  364. /* Can't synchronize to another proc, release now */
  365. e->t = now;
  366. e->d = 0;
  367. release(p);
  368. if (p == up){
  369. DPRINT("%lu edfadmit self %d[%s], release now: r=%lu d=%lu t=%lu\n",
  370. now, p->pid, statename[p->state], e->r, e->d, e->t);
  371. /* We're already running */
  372. edfrun(p, 1);
  373. }else{
  374. /* We're releasing another proc */
  375. DPRINT("%lu edfadmit other %d[%s], release now: r=%lu d=%lu t=%lu\n",
  376. now, p->pid, statename[p->state], e->r, e->d, e->t);
  377. p->Timer.ta = p;
  378. edfunlock();
  379. qunlock(&edfschedlock);
  380. releaseintr(nil, &p->Timer);
  381. return nil;
  382. }
  383. }else{
  384. /* Release in synch to something else */
  385. e->t = r->edf->t;
  386. psdecref(r);
  387. if (p == up){
  388. DPRINT("%lu edfadmit self %d[%s], release at %lu\n",
  389. now, p->pid, statename[p->state], e->t);
  390. }else{
  391. DPRINT("%lu edfadmit other %d[%s], release at %lu\n",
  392. now, p->pid, statename[p->state], e->t);
  393. if(e->Timer.tt == nil){
  394. e->Timer.tf = releaseintr;
  395. e->Timer.ta = p;
  396. tns = e->t - now;
  397. if(tns < 20)
  398. tns = 20;
  399. e->Timer.tns = 1000LL * tns;
  400. e->Timer.tmode = Trelative;
  401. timeradd(&e->Timer);
  402. }
  403. }
  404. }
  405. edfunlock();
  406. qunlock(&edfschedlock);
  407. return nil;
  408. }
  409. void
  410. edfstop(Proc *p)
  411. {
  412. Edf *e;
  413. if((e = edflock(p)) != nil){
  414. DPRINT("%lu edfstop %d[%s]\n", now, p->pid, statename[p->state]);
  415. if(p->trace)
  416. proctrace(p, SExpel, 0);
  417. e->flags &= ~Admitted;
  418. if(e->Timer.tt)
  419. timerdel(&e->Timer);
  420. edfunlock();
  421. }
  422. }
  423. static int
  424. yfn(void *v)
  425. {
  426. Proc *up = externup();
  427. now = ms();
  428. return up->trend == nil || now - up->edf->r >= 0;
  429. }
  430. void
  431. edfyield(void)
  432. {
  433. Proc *up = externup();
  434. /* sleep until next release */
  435. Edf *e;
  436. int32_t n;
  437. if((e = edflock(up)) == nil)
  438. return;
  439. if(up->trace)
  440. proctrace(up, SYield, 0);
  441. if((n = now - e->t) > 0){
  442. if(n < e->T)
  443. e->t += e->T;
  444. else
  445. e->t = now + e->T - (n % e->T);
  446. }
  447. e->r = e->t;
  448. e->flags |= Yield;
  449. e->d = now;
  450. if (up->Timer.tt == nil){
  451. n = e->t - now;
  452. if(n < 20)
  453. n = 20;
  454. up->Timer.tns = 1000LL * n;
  455. up->Timer.tf = releaseintr;
  456. up->Timer.tmode = Trelative;
  457. up->Timer.ta = up;
  458. up->trend = &up->sleep;
  459. timeradd(&up->Timer);
  460. }else if(up->Timer.tf != releaseintr)
  461. print("edfyield: surprise! %#p\n", up->Timer.tf);
  462. edfunlock();
  463. sleep(&up->sleep, yfn, nil);
  464. }
  465. int
  466. edfready(Proc *p)
  467. {
  468. Edf *e;
  469. Sched *sch;
  470. Schedq *rq;
  471. Proc *l, *pp;
  472. int32_t n;
  473. if((e = edflock(p)) == nil)
  474. return 0;
  475. if(p->state == Wakeme && p->r){
  476. iprint("edfready: wakeme\n");
  477. }
  478. if(e->d - now <= 0){
  479. /* past deadline, arrange for next release */
  480. if((e->flags & Sporadic) == 0){
  481. /*
  482. * Non sporadic processes stay true to their period;
  483. * calculate next release time.
  484. */
  485. if((n = now - e->t) > 0){
  486. if(n < e->T)
  487. e->t += e->T;
  488. else
  489. e->t = now + e->T - (n % e->T);
  490. }
  491. }
  492. if(now - e->t < 0){
  493. /* Next release is in the future, schedule it */
  494. if(e->Timer.tt == nil || e->Timer.tf != releaseintr){
  495. n = e->t - now;
  496. if(n < 20)
  497. n = 20;
  498. e->Timer.tns = 1000LL * n;
  499. e->Timer.tmode = Trelative;
  500. e->Timer.tf = releaseintr;
  501. e->Timer.ta = p;
  502. timeradd(&e->Timer);
  503. DPRINT("%lu edfready %d[%s], release=%lu\n",
  504. now, p->pid, statename[p->state], e->t);
  505. }
  506. if(p->state == Running && (e->flags & (Yield|Yieldonblock)) == 0 && (e->flags & Extratime)){
  507. /* If we were running, we've overrun our CPU allocation
  508. * or missed the deadline, continue running best-effort at low priority
  509. * Otherwise we were blocked. If we don't yield on block, we continue
  510. * best effort
  511. */
  512. DPRINT(">");
  513. p->basepri = PriExtra;
  514. p->fixedpri = 1;
  515. edfunlock();
  516. return 0; /* Stick on runq[PriExtra] */
  517. }
  518. DPRINT("%lu edfready %d[%s] wait release at %lu\n",
  519. now, p->pid, statename[p->state], e->t);
  520. p->state = Waitrelease;
  521. edfunlock();
  522. return 1; /* Make runnable later */
  523. }
  524. DPRINT("%lu edfready %d %s release now\n", now, p->pid, statename[p->state]);
  525. /* release now */
  526. release(p);
  527. }
  528. edfunlock();
  529. DPRINT("^");
  530. sch = procsched(p);
  531. rq = &sch->runq[PriEdf];
  532. /* insert in queue in earliest deadline order */
  533. lock(&sch->l);
  534. l = nil;
  535. for(pp = rq->head; pp; pp = pp->rnext){
  536. if(pp->edf->d > e->d)
  537. break;
  538. l = pp;
  539. }
  540. p->rnext = pp;
  541. if (l == nil)
  542. rq->head = p;
  543. else
  544. l->rnext = p;
  545. if(pp == nil)
  546. rq->tail = p;
  547. rq->n++;
  548. sch->nrdy++;
  549. sch->runvec |= 1 << PriEdf;
  550. p->priority = PriEdf;
  551. p->readytime = machp()->ticks;
  552. p->state = Ready;
  553. unlock(&sch->l);
  554. if(p->trace)
  555. proctrace(p, SReady, 0);
  556. return 1;
  557. }
  558. static void
  559. testenq(Proc *p)
  560. {
  561. Proc *xp, **xpp;
  562. Edf *e;
  563. e = p->edf;
  564. e->testnext = nil;
  565. if (qschedulability == nil) {
  566. qschedulability = p;
  567. return;
  568. }
  569. SET(xp);
  570. for (xpp = &qschedulability; *xpp; xpp = &xp->edf->testnext) {
  571. xp = *xpp;
  572. if (e->testtime - xp->edf->testtime < 0
  573. || (e->testtime == xp->edf->testtime && e->testtype < xp->edf->testtype)){
  574. e->testnext = xp;
  575. *xpp = p;
  576. return;
  577. }
  578. }
  579. assert(xp->edf->testnext == nil);
  580. xp->edf->testnext = p;
  581. }
  582. static char *
  583. testschedulability(Proc *theproc)
  584. {
  585. Proc *p;
  586. int32_t H, G, Cb, ticks;
  587. int steps, i;
  588. /* initialize */
  589. DPRINT("schedulability test %d\n", theproc->pid);
  590. qschedulability = nil;
  591. for(i=0; (p = psincref(i)) != nil; i++) {
  592. if(p->state == Dead){
  593. psdecref(p);
  594. continue;
  595. }
  596. if ((p->edf == nil || (p->edf->flags & Admitted) == 0) && p != theproc){
  597. psdecref(p);
  598. continue;
  599. }
  600. p->edf->testtype = Rl;
  601. p->edf->testtime = 0;
  602. DPRINT("\tInit: edfenqueue %d\n", p->pid);
  603. testenq(p);
  604. psdecref(p);
  605. }
  606. H=0;
  607. G=0;
  608. for(steps = 0; steps < Maxsteps; steps++){
  609. p = qschedulability;
  610. qschedulability = p->edf->testnext;
  611. ticks = p->edf->testtime;
  612. switch (p->edf->testtype){
  613. case Dl:
  614. H += p->edf->C;
  615. Cb = 0;
  616. DPRINT("\tStep %3d, Ticks %lu, pid %d, deadline, H += %lu → %lu, Cb = %lu\n",
  617. steps, ticks, p->pid, p->edf->C, H, Cb);
  618. if (H+Cb>ticks){
  619. DPRINT("not schedulable\n");
  620. return "not schedulable";
  621. }
  622. p->edf->testtime += p->edf->T - p->edf->D;
  623. p->edf->testtype = Rl;
  624. testenq(p);
  625. break;
  626. case Rl:
  627. DPRINT("\tStep %3d, Ticks %lu, pid %d, release, G %lu, C%lu\n",
  628. steps, ticks, p->pid, p->edf->C, G);
  629. if(ticks && G <= ticks){
  630. DPRINT("schedulable\n");
  631. return nil;
  632. }
  633. G += p->edf->C;
  634. p->edf->testtime += p->edf->D;
  635. p->edf->testtype = Dl;
  636. testenq(p);
  637. break;
  638. default:
  639. assert(0);
  640. }
  641. }
  642. DPRINT("probably not schedulable\n");
  643. return "probably not schedulable";
  644. }