|
|
1.1 root 1: //
2: // nono
1.1.1.4 root 3: // Copyright (C) 2020 nono project
4: // Licensed under nono-license.txt
1.1 root 5: //
6:
1.1.1.14 root 7: //
8: // スケジューラ
9: //
1.1 root 10:
11: // VM スケジューラは、仮想時間とイベントを管理する。
1.1.1.14 root 12: // 仮想時間はすべて nsec で表し、StartTime() から単調増加する。
13: // VM 界からは仮想時間は gScheduler->GetVirtTime() で取得する。
1.1 root 14: //
1.1.1.16! root 15: // 実時間は Syncer が管理し、こちらも nsec で表す。
1.1.1.14 root 16: // このストップウォッチも StartTime() から単調増加する。
17: // 実時間、仮想時間とも電源オフ中でも単調増加することに注意。
1.1.1.9 root 18: //
1.1.1.14 root 19: // 「実経過時間」は gRealtime.Elapsed() で取得でき
20: // o (たぶん) Scheduler スレッド開始時から、常に増加。
1.1.1.9 root 21: // o (たぶん)ホストの時刻変更やサスペンドの影響を受けず、常に増加。
22: // o デバッガプロンプトで停止中は進行が停止する。
23: // という性質を持つ。
24: //
25: // 同期走行モードにおいては rtime_epoch, vtime_epoch をそれぞれの基準点とし
26: // これらと現在の実経過時間、仮想経過時間の差が同期するよう調整する。
27: // 高速走行モードにおいてはこれらは必要ないので特に参照しない。
28: //
29: // 一定間隔で行うパフォーマンス測定は、前回計測時の実および仮想経過時間を
30: // last_perf_rtime, last_perf_vtime として持っているので、これと現在の
31: // 経過時間との比で求める。同期走行/高速走行の影響は受けない。
1.1 root 32:
1.1.1.14 root 33: #include "scheduler.h"
34: #include "mpu.h"
35: #include "rtc.h"
1.1.1.16! root 36: #include "syncer.h"
1.1 root 37:
1.1.1.14 root 38: //#define CT_ON
1.1.1.9 root 39:
1.1.1.14 root 40: #ifdef CT_ON
41: static uint64 ct_get1;
42: static uint64 ct_get2;
43: static uint64 ct_start;
44: static uint64 ct_start1;
45: static uint64 ct_start2;
46: static uint64 ct_start3;
47: static uint64 ct_start4;
48: static uint64 ct_stop1;
49: static uint64 ct_stop2;
50: static uint64 ct_eslow;
51: static uint64 ct_sslow;
52: static uint64 ct_pslow;
53: #define CT(name) ct_##name += 1
54: #else
55: #define CT(name)
56: #endif
1.1.1.9 root 57:
58: #define FORMAT_FULL 0
59: #define FORMAT_SEC 1
60:
61: // 経過時間 t を文字列にして返す。
1.1.1.10 root 62: // 文字列長は、t の大きさ(とフォーマット指定)によって以下の通り。
63: //
64: // 0 1 2
65: // 01234567890123456789012345
66: // "0.mmm'uuu'nnn" 10秒未満、または FORMAT_SEC なら13桁
67: // "59.mmm'uuu'nnn" 1分未満なら14桁
68: // " 9:59.mmm'uuu'nnn" 1時間未満なら17桁
69: // " 9:59:59.mmm'uuu'nnn" 24時間未満なら20桁
70: // "999d 23:59:59.mmm'uuu'nnn" 1日以上なら25桁。これが最大幅。
71: //
72: // FORMAT_SEC は1桁秒以下の場合 (実際には1秒未満の場合) に用いる。
73: // FORMAT_FULL は 1000日経過すると桁がずれるけど、それはもういいだろう。
74: //
75: // 10秒未満の場合だけ %2d ではなく %d で1桁切り詰めているが、これは
76: // FORMAT_SEC との互換性のため。その必要のない10分未満と10時間未満は
77: // どちらも %2d で表記し桁数を維持することに努める。
1.1.1.9 root 78: static const std::string
79: TimeToStrF(uint64 t, int format)
80: {
81: char buf[32];
82: char *p;
83: size_t len;
84: int n;
85:
86: uint ns = t % 1000;
87: t /= 1000;
88: uint us = t % 1000;
89: t /= 1000;
90: uint ms = t % 1000;
91: t /= 1000;
92:
93: uint s, m, h, d;
94: if (format == FORMAT_FULL) {
95: s = t % 60;
96: t /= 60;
97: m = t % 60;
98: t /= 60;
99: h = t % 24;
100: t /= 24;
101: d = t;
102: } else {
103: s = t;
104: m = 0;
105: h = 0;
106: d = 0;
107: }
108:
109: p = buf;
110: len = sizeof(buf);
111: if (d) {
112: n = snprintf(p, len, "%3dd %02u:%02u:%02u", d, h, m, s);
113: p += n;
114: len -= n;
115: } else if (h) {
116: n = snprintf(p, len, "%2u:%02u:%02u", h, m, s);
117: p += n;
118: len -= n;
119: } else if (m) {
120: n = snprintf(p, len, "%2u:%02u", m, s);
121: p += n;
122: len -= n;
123: } else {
124: n = snprintf(p, len, "%u", s);
125: p += n;
126: len -= n;
127: }
128: n = snprintf(p, len, ".%03u'%03u'%03u", ms, us, ns);
129: p += n;
130: len -= n;
131:
132: return std::string(buf, p - buf);
133: }
134:
1.1.1.10 root 135: const std::string
1.1.1.9 root 136: TimeToStr(uint64 t)
137: {
138: return TimeToStrF(t, FORMAT_FULL);
139: }
140:
1.1.1.14 root 141: const std::string
1.1.1.9 root 142: SecToStr(uint64 t)
143: {
144: return TimeToStrF(t, FORMAT_SEC);
145: }
146:
147: //
148: // スケジューラ
149: //
150:
1.1 root 151: // コンストラクタ
152: Scheduler::Scheduler()
1.1.1.16! root 153: : inherited(OBJ_SCHEDULER)
1.1 root 154: {
1.1.1.14 root 155: // オブジェクト名は Scheduler だがここのスレッド名は VM くらいのほうが
156: // 通りがよさそうだ。
157: SetThreadName("VM");
1.1.1.9 root 158:
1.1.1.14 root 159: slow_top = -1;
160: slow_top_vtime = UINT64_MAX;
1.1.1.10 root 161:
1.1.1.14 root 162: monitor.func = ToMonitorCallback(&Scheduler::MonitorUpdate);
1.1.1.10 root 163: // サイズは Init で決まる
164: monitor.Regist(ID_MONITOR_SCHEDULER);
1.1 root 165: }
166:
167: // デストラクタ
168: Scheduler::~Scheduler()
169: {
1.1.1.14 root 170: TerminateThread();
1.1 root 171: }
172:
173: // 初期化
174: bool
175: Scheduler::Init()
176: {
1.1.1.16! root 177: if (inherited::Init() == false) {
! 178: return false;
! 179: }
! 180:
! 181: syncer = GetSyncer();
! 182:
1.1.1.10 root 183: // この時点でイベントの個数は確定しているはず(してなければならない)
1.1.1.14 root 184: monitor.SetSize(80, 9 + all_events.size());
1.1 root 185:
186: return true;
187: }
188:
189: // スレッドエントリ関数
190: void
191: Scheduler::ThreadRun()
192: {
1.1.1.14 root 193: // 電源オンオフに関わらず、ここが rtime, vtime の基準点
194: StartTime();
1.1 root 195:
1.1.1.3 root 196: for (;;) {
1.1.1.14 root 197: // 条件変数の正しい使い方としては request の参照にも mtx ロックが必要
198: // だが、ここでロック取らずに参照したことによって request が立った
199: // ことを見落としても、ループ一回回ってもう一度ここに来るだけなので
200: // たぶん致命的なことはないはず。
201: if (__predict_false(request)) {
202: uint32 req;
203: {
204: std::lock_guard<std::mutex> lock(mtx);
205: req = request;
206: request = 0;
1.1.1.9 root 207: }
1.1.1.14 root 208: if ((req & REQUEST_EXIT)) {
209: break;
1.1.1.9 root 210: }
1.1.1.16! root 211:
! 212: for (; req; req &= req - 1) {
! 213: int id = __builtin_ctz(req);
! 214: if (id < MessageID::MAX_REQUEST) {
! 215: InvokeMessage(id, 0);
! 216: } else {
! 217: DispatchMessage();
! 218: }
1.1.1.9 root 219: }
1.1.1.14 root 220: }
1.1.1.9 root 221:
1.1.1.14 root 222: // 先頭のイベントを取得して停止
223: Event *ev;
224: if (__predict_true(fast != NULL)) {
225: CT(get1);
226: ev = fast;
227: fast = NULL;
228: } else {
229: CT(get2);
230: ev = slow[slow_top--];
231: slow_top_vtime = slow[slow_top]->vtime;
1.1.1.9 root 232: }
1.1.1.14 root 233: ev->active = false;
1.1.1.9 root 234:
1.1.1.14 root 235: // 時刻更新
236: vtime = ev->vtime;
237:
238: // コールバック
239: ev->count++;
240: ((ev->dev)->*(ev->func))(*ev);
1.1 root 241: }
1.1.1.9 root 242: }
1.1 root 243:
1.1.1.14 root 244: // 時間の始まり
245: void
246: Scheduler::StartTime()
1.1.1.9 root 247: {
1.1.1.14 root 248: // イベントキューを空にする
249: for (auto ev : all_events) {
250: if (ev->active) {
251: StopEvent(*ev);
1.1.1.9 root 252: }
1.1.1.14 root 253: ev->count = 0;
1.1.1.9 root 254: }
1.1.1.14 root 255:
256: // 時間をリセットする。
257: // 呼び出しの依存関係に注意。
258: vtime = 0; // required by Sync
1.1.1.16! root 259: syncer->StartTime(); // required by RTC
! 260: GetRTCDevice()->StartTime();
1.1.1.9 root 261: }
1.1 root 262:
1.1.1.14 root 263: // スレッド終了指示
264: // (当然他スレッドから呼ぶことになる)
1.1.1.9 root 265: void
1.1.1.14 root 266: Scheduler::Terminate()
1.1.1.9 root 267: {
1.1.1.14 root 268: std::unique_lock<std::mutex> lock(mtx);
269: request |= REQUEST_EXIT;
270: cv.notify_one();
1.1.1.9 root 271: }
1.1 root 272:
1.1.1.14 root 273: // イベントを登録する。
274: // 登録時点では実は type だけ確定していればよい。
275: //
276: // ここで管理してるのはポインタだけで、実体は呼び出し元クラスのメンバ
277: // インスタンスのはずなので、登録しっぱなしにする。
278: void
279: Scheduler::RegistEvent(Event& ev)
1.1.1.9 root 280: {
1.1.1.14 root 281: // イベントリストに追加
282: all_events.push_back(&ev);
1.1.1.9 root 283: }
284:
1.1.1.14 root 285: // 指定のイベントを開始する。
286: // すでに同イベントが登録されている場合は古いイベントを削除してから
287: // 新しいイベントを再登録となる。
288: // イベントはワンショットのみ。
1.1.1.9 root 289: void
1.1.1.14 root 290: Scheduler::RestartEvent(Event& ev)
1.1.1.9 root 291: {
1.1.1.14 root 292: if (ev.IsRunning()) {
293: StopEvent(ev);
1.1.1.9 root 294: }
1.1.1.14 root 295:
296: StartEvent(ev);
1.1 root 297: }
298:
1.1.1.14 root 299: // 指定のイベントを開始する。
300: // このイベントが登録されてないことが確定できる場合のみこちらが使える。
301: // イベントはワンショットのみ。
1.1 root 302: void
1.1.1.14 root 303: Scheduler::StartEvent(Event& ev)
1.1 root 304: {
1.1.1.14 root 305: CT(start);
306: #ifdef CT_ON
307: if (ct_start % 100'000'000 == 0) {
308: printf("get*=%lu [%lu, %lu]\n",
309: (ct_get1 + ct_get2), ct_get1, ct_get2);
310: printf("start*=%lu [%lu, %lu, %lu, %lu]\n",
311: ct_start, ct_start1, ct_start2, ct_start3, ct_start4);
312: printf("stop*=%lu [%lu, %lu]\n",
313: (ct_stop1 + ct_stop2), ct_stop1, ct_stop2);
314: printf("eslow=%lu sslow=%lu pslow=%lu\n",
315: ct_eslow, ct_sslow, ct_pslow);
316: printf("slow_top=%d vtime=%lu\n", slow_top, slow_top_vtime);
317: }
318: #endif
319:
320: // この assert を有効にすると 10 ポイント性能が低下する(502%->492%)
321: //assertmsg(ev.IsRunning() == false, "%s", ev.GetName().c_str());
322:
323: // vtime は仮想絶対時刻 [nsec]、time は仮想相対時間 [nsec]
324: ev.vtime = vtime + ev.time;
325:
326: ev.active = true;
327:
328: if (__predict_true(ev.vtime <= slow_top_vtime)) {
329: if (__predict_true(fast == NULL)) {
330: CT(start1);
331: fast = &ev;
332: } else {
333: if (__predict_false(ev.vtime <= fast->vtime)) {
334: CT(start2);
335: PushSlow(*fast);
336: fast = &ev;
337: } else {
338: CT(start3);
339: PushSlow(ev);
340: }
341: }
342: } else {
343: CT(start4);
344: EnqueueSlow(ev);
1.1.1.10 root 345: }
346: }
347:
1.1.1.14 root 348: // 実時間間隔を指定してイベントを開始する。
349: // rt_now はイベント発行者の実時間での現在時刻で、
350: // rt_period は次回のイベントまでの実時間間隔。
351: void
352: Scheduler::StartRealtimeEvent(Event& ev, uint64 rt_now, uint64 rt_period)
353: {
354: // 実時間をもとに仮想時間軸上の推定を行う。
355:
1.1.1.16! root 356: uint64 rtime = syncer->GetRealTime();
1.1.1.14 root 357:
358: if (rtime > rt_now + rt_period) {
359: // 実時間がさらに 1 period 以上進んでいる。
360: // 実時間に追いつかないといけないので、イベントの
361: // 周期を短くして回復運転させる。
362: // 周期を短くしすぎるとゲストが処理できなくなるので、
363: // 10% カットに留める。
364: ev.time = rt_period - rt_period / 10;
365: } else if (rtime < rt_now - rt_period) {
366: // イベントがさらに 1 period 以上進んでいる。
367: // 実時間を追い越してしまっているので、イベントの
368: // 周期を長くして待つ。長くする方はいくらでも長くしていいので、
369: // 連続した場合はどんどん長くしていく。
370: ev.time += rt_period;
371: } else {
372: // おおむね同期している
373: ev.time = rt_period;
374: }
375:
376: RestartEvent(ev);
377: }
378:
379: // ev は slow_top には来ない前提
1.1.1.10 root 380: void
1.1.1.14 root 381: Scheduler::EnqueueSlow(Event& ev)
1.1.1.10 root 382: {
1.1.1.14 root 383: CT(eslow);
384:
385: int s = slow_top;
386: slow[++slow_top] = slow[s];
387:
388: for (; --s >= 0; ) {
389: if (ev.vtime <= slow[s]->vtime) {
390: slow[s + 1] = &ev;
391: return;
392: } else {
393: slow[s + 1] = slow[s];
394: }
1.1.1.3 root 395: }
1.1.1.14 root 396: slow[0] = &ev;
1.1 root 397: }
398:
1.1.1.8 root 399: void
1.1.1.14 root 400: Scheduler::PushSlow(Event& ev)
1.1.1.8 root 401: {
1.1.1.14 root 402: CT(pslow);
403:
404: slow[++slow_top] = &ev;
405: slow_top_vtime = ev.vtime;
1.1.1.8 root 406: }
407:
1.1.1.14 root 408: // 指定のイベントを停止する。
409: // 指定されたイベントが登録されていなければ何もしない。
1.1 root 410: void
1.1.1.14 root 411: Scheduler::StopEvent(Event& ev)
1.1 root 412: {
1.1.1.14 root 413: ev.active = false;
414:
415: if (__predict_false(&ev == fast)) {
416: CT(stop1);
417: fast = NULL;
1.1 root 418: } else {
1.1.1.14 root 419: CT(stop2);
420: StopSlowEvent(ev);
1.1 root 421: }
422: }
423:
1.1.1.9 root 424: void
1.1.1.14 root 425: Scheduler::StopSlowEvent(Event& ev)
1.1.1.9 root 426: {
1.1.1.14 root 427: CT(sslow);
428:
429: int s = slow_top;
430:
431: for (; s >= 0; s--) {
432: if (&ev == slow[s]) {
433: for (; s < slow_top; s++) {
434: slow[s] = slow[s + 1];
435: }
436: slow_top--;
437: if (slow_top < 0) {
438: slow_top_vtime = UINT64_MAX;
439: } else {
440: slow_top_vtime = slow[slow_top]->vtime;
441: }
442: break;
443: }
1.1.1.9 root 444: }
445: }
446:
1.1.1.14 root 447: // メッセージハンドラを登録する。
1.1.1.9 root 448: void
1.1.1.14 root 449: Scheduler::ConnectMessage(MessageID msgid, Device *dev, MessageCallback_t func)
1.1.1.9 root 450: {
1.1.1.16! root 451: assert(msgid < MessageID::MAX);
! 452:
1.1.1.14 root 453: auto& mh = message_handlers[msgid];
1.1.1.16! root 454: assertmsg(mh.dev == NULL,
! 455: "%s: msgid=%d connected again", __func__, (int)msgid);
1.1.1.14 root 456: mh.dev = dev;
457: mh.func = func;
1.1.1.9 root 458: }
459:
1.1.1.14 root 460: // メッセージをディスパッチして、登録されていればハンドラを呼び出す。
1.1.1.9 root 461: void
1.1.1.14 root 462: Scheduler::DispatchMessage()
1.1.1.9 root 463: {
1.1.1.14 root 464: uint64 msg;
1.1.1.9 root 465:
1.1.1.14 root 466: while (msgq.Dequeue(&msg)) {
467: MessageID msgid = (MessageID)(msg & 0xff);
468: uint32 arg = (msg >> 32);
1.1.1.9 root 469:
1.1.1.16! root 470: // MessageID::MPU_TRACE_ALL だけ特別対応。
! 471: // MPU_TRACE メッセージの宛先は(最大)2つあるが、
! 472: // スレッドを越える時は1メッセージにしておきたいので、
! 473: // MPU_TRACE_ALL が来たらここで分岐。
! 474: if (msgid == MessageID::MPU_TRACE_ALL) {
! 475: InvokeMessage(MessageID::MPU_TRACE_MAIN, arg);
! 476: InvokeMessage(MessageID::MPU_TRACE_XP, arg);
! 477: } else {
! 478: assert(msgid < MessageID::MAX);
! 479: InvokeMessage(msgid, arg);
1.1.1.14 root 480: }
1.1.1.9 root 481: }
482: }
483:
1.1.1.16! root 484: // メッセージハンドラを呼び出す。登録されてなければ何もしない。
! 485: void
! 486: Scheduler::InvokeMessage(MessageID msgid, uint32 arg)
! 487: {
! 488: auto h = message_handlers[msgid];
! 489: if (h.dev != NULL) {
! 490: (h.dev->*(h.func))(msgid, arg);
! 491: }
! 492: }
! 493:
1.1.1.14 root 494: // メッセージを送る。
495: // VM スレッド以外から呼び出しても良い。
1.1 root 496: void
1.1.1.14 root 497: Scheduler::SendMessage(MessageID msgid, uint32 arg)
1.1 root 498: {
1.1.1.14 root 499: std::unique_lock<std::mutex> lock(mtx);
1.1 root 500:
1.1.1.16! root 501: if (msgid < MessageID::MAX_REQUEST) {
! 502: request |= 1U << (uint)msgid;
! 503: } else {
! 504: uint64 msg = (uint64)msgid | (((uint64)arg) << 32);
! 505: if (msgq.Enqueue(msg) == false) {
! 506: putlog(0, "Message queue exhausted !! msgid=%d", (int)msgid);
! 507: }
! 508: request |= REQUEST_MESSAGE;
1.1 root 509: }
1.1.1.14 root 510: cv.notify_one();
1.1 root 511: }
512:
1.1.1.14 root 513: // 指定時間が経過するか、リクエストが起きるまでスリープ
1.1 root 514: void
1.1.1.14 root 515: Scheduler::Sleep(uint64 time)
1.1 root 516: {
1.1.1.14 root 517: std::unique_lock<std::mutex> lock(mtx);
518: cv.wait_for(lock, std::chrono::nanoseconds(time), [&] {
519: return (request != 0);
520: });
521: // リクエストフラグが立ってもここでは何もしない
1.1 root 522: }
523:
1.1.1.5 root 524: void
1.1.1.10 root 525: Scheduler::MonitorUpdate(Monitor *, TextScreen& screen)
1.1 root 526: {
1.1.1.14 root 527: int y;
1.1 root 528:
1.1.1.10 root 529: screen.Clear();
1.1 root 530:
1.1.1.16! root 531: y = syncer->MonitorUpdateSub(screen, vtime);
1.1.1.7 root 532:
1.1.1.16! root 533: int clock_khz = mpu->GetClockSpeed();
1.1.1.10 root 534: screen.Print(0, y++, "MPU Speed: %d.%03dMHz",
1.1.1.7 root 535: (clock_khz / 1000), (clock_khz % 1000));
1.1.1.9 root 536:
1.1.1.14 root 537: // 0 1 2 3
538: // 012345678901234567890123456789
1.1.1.15 root 539: // Event Time Remain Time
540: // 3.123'456'789 3.123'456'789
1.1.1.14 root 541: //
542: // 3 4 5 6 7
543: // 01234567890123456789012345678901234567890123456789
544: // Description Count
545: // 012345678901234567890123456789 999,999,999,999,999
546: // 18,446,744,073,709,551,615
547: y++;
548: screen.Puts(0, y, "Event Time");
549: screen.Puts(15, y, "Remain Time");
550: screen.Puts(30, y, "Description");
551: screen.Puts(75, y, "Count");
1.1 root 552: y++;
1.1.1.6 root 553:
1.1.1.14 root 554: for (const auto ev : all_events) {
1.1 root 555: uint64 rem;
1.1.1.4 root 556: TA attr;
1.1.1.15 root 557:
1.1.1.14 root 558: if (ev->IsRunning()) {
1.1.1.15 root 559: attr = TA::Normal;
1.1.1.14 root 560: if (ev->vtime > vtime) {
561: rem = ev->vtime - vtime;
1.1.1.6 root 562: } else {
563: // XXX 実際には起きないけど、この表示をするにあたって
564: // スケジューラスレッドと一切調停していないので、仮想時刻が
1.1.1.14 root 565: // ev->vtime (イベント発生時刻) をすぎていることがある。
1.1.1.6 root 566: // すぎてるので残り時間 0 と表示しておく。
567: rem = 0;
568: }
1.1 root 569: } else {
1.1.1.15 root 570: attr = TA::Disable;
1.1 root 571: rem = 0;
572: }
1.1.1.14 root 573:
574: if (ev->count != ev->last_count) {
575: attr = TA::Normal;
576: ev->last_count = ev->count;
577: }
578:
579: // 先にイベント回数を表示。
580: // 21文字以上になったら上位桁が長い Description で消されても
581: // 大勢に影響はないだろう。
582: std::string countstr = format_number(ev->count);
583: screen.Print(54, y, attr, "%26s", countstr.c_str());
1.1.1.15 root 584: screen.Print(0, y, attr, "%14s %14s %s ",
1.1.1.14 root 585: SecToStr(ev->time).c_str(),
1.1.1.9 root 586: SecToStr(rem).c_str(),
1.1.1.14 root 587: ev->GetName().c_str());
588: y++;
1.1 root 589: }
590: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.