Annotation of nono/vm/scheduler.cpp, revision 1.1.1.21

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"
1.1.1.21! root       34: #include "event.h"
1.1.1.18  root       35: #include "monitor.h"
1.1.1.14  root       36: #include "rtc.h"
1.1.1.16  root       37: #include "syncer.h"
1.1       root       38: 
1.1.1.14  root       39: //#define CT_ON
1.1.1.9   root       40: 
1.1.1.14  root       41: #ifdef CT_ON
                     42: static uint64 ct_get1;
                     43: static uint64 ct_get2;
                     44: static uint64 ct_start;
                     45: static uint64 ct_start1;
                     46: static uint64 ct_start2;
                     47: static uint64 ct_start3;
                     48: static uint64 ct_start4;
                     49: static uint64 ct_stop1;
                     50: static uint64 ct_stop2;
                     51: static uint64 ct_eslow;
                     52: static uint64 ct_sslow;
                     53: static uint64 ct_pslow;
                     54: #define CT(name) ct_##name += 1
                     55: #else
                     56: #define CT(name)
                     57: #endif
1.1.1.9   root       58: 
                     59: //
                     60: // スケジューラ
                     61: //
                     62: 
1.1       root       63: // コンストラクタ
                     64: Scheduler::Scheduler()
1.1.1.16  root       65:        : inherited(OBJ_SCHEDULER)
1.1       root       66: {
1.1.1.14  root       67:        // オブジェクト名は Scheduler だがここのスレッド名は VM くらいのほうが
                     68:        // 通りがよさそうだ。
                     69:        SetThreadName("VM");
1.1.1.9   root       70: 
1.1.1.14  root       71:        slow_top = -1;
                     72:        slow_top_vtime = UINT64_MAX;
1.1.1.10  root       73: 
1.1.1.18  root       74:        monitor = gMonitorManager->Regist(ID_MONITOR_SCHEDULER, this);
                     75:        monitor->func = ToMonitorCallback(&Scheduler::MonitorUpdate);
1.1.1.20  root       76:        // サイズは最終的に Init2() で決まる。
                     77:        monitor->SetSize(80, 9);
1.1       root       78: }
                     79: 
                     80: // デストラクタ
                     81: Scheduler::~Scheduler()
                     82: {
1.1.1.14  root       83:        TerminateThread();
1.1       root       84: }
                     85: 
                     86: // 初期化
                     87: bool
                     88: Scheduler::Init()
                     89: {
1.1.1.21! root       90:        evman = GetEventManager();
1.1.1.16  root       91:        syncer = GetSyncer();
                     92: 
1.1.1.17  root       93:        return true;
                     94: }
                     95: 
                     96: // 初期化(VM から呼ばれる)
                     97: bool
                     98: Scheduler::Init2()
                     99: {
                    100:        // イベントの個数が確定した(してなければならない)
1.1.1.21! root      101:        monitor->AddHeight(evman->all.size());
1.1       root      102: 
                    103:        return true;
                    104: }
                    105: 
                    106: // スレッドエントリ関数
                    107: void
                    108: Scheduler::ThreadRun()
                    109: {
1.1.1.17  root      110:        SetThreadAffinityHint(AffinityClass::Heavy);
                    111: 
1.1.1.14  root      112:        // 電源オンオフに関わらず、ここが rtime, vtime の基準点
                    113:        StartTime();
1.1       root      114: 
1.1.1.3   root      115:        for (;;) {
1.1.1.14  root      116:                // 条件変数の正しい使い方としては request の参照にも mtx ロックが必要
                    117:                // だが、ここでロック取らずに参照したことによって request が立った
                    118:                // ことを見落としても、ループ一回回ってもう一度ここに来るだけなので
                    119:                // たぶん致命的なことはないはず。
                    120:                if (__predict_false(request)) {
                    121:                        uint32 req;
                    122:                        {
                    123:                                std::lock_guard<std::mutex> lock(mtx);
                    124:                                req = request;
                    125:                                request = 0;
1.1.1.9   root      126:                        }
1.1.1.14  root      127:                        if ((req & REQUEST_EXIT)) {
                    128:                                break;
1.1.1.9   root      129:                        }
1.1.1.16  root      130: 
                    131:                        for (; req; req &= req - 1) {
1.1.1.17  root      132:                                uint id = __builtin_ctz(req);
1.1.1.16  root      133:                                if (id < MessageID::MAX_REQUEST) {
                    134:                                        InvokeMessage(id, 0);
                    135:                                } else {
                    136:                                        DispatchMessage();
                    137:                                }
1.1.1.9   root      138:                        }
1.1.1.14  root      139:                }
1.1.1.9   root      140: 
1.1.1.14  root      141:                // 先頭のイベントを取得して停止
                    142:                Event *ev;
                    143:                if (__predict_true(fast != NULL)) {
                    144:                        CT(get1);
                    145:                        ev = fast;
                    146:                        fast = NULL;
                    147:                } else {
                    148:                        CT(get2);
                    149:                        ev = slow[slow_top--];
                    150:                        slow_top_vtime = slow[slow_top]->vtime;
1.1.1.9   root      151:                }
1.1.1.14  root      152:                ev->active = false;
1.1.1.9   root      153: 
1.1.1.14  root      154:                // 時刻更新
                    155:                vtime = ev->vtime;
                    156: 
                    157:                // コールバック
                    158:                ev->count++;
1.1.1.21! root      159:                ((ev->dev)->*(ev->func))(ev);
1.1       root      160:        }
1.1.1.9   root      161: }
1.1       root      162: 
1.1.1.14  root      163: // 時間の始まり
                    164: void
                    165: Scheduler::StartTime()
1.1.1.9   root      166: {
1.1.1.14  root      167:        // イベントキューを空にする
1.1.1.21! root      168:        for (auto *ev : evman->all) {
1.1.1.14  root      169:                if (ev->active) {
1.1.1.21! root      170:                        StopEvent(ev);
1.1.1.9   root      171:                }
1.1.1.14  root      172:                ev->count = 0;
1.1.1.9   root      173:        }
1.1.1.14  root      174: 
                    175:        // 時間をリセットする。
                    176:        // 呼び出しの依存関係に注意。
                    177:        vtime = 0;                                      // required by Sync
1.1.1.16  root      178:        syncer->StartTime();            // required by RTC
                    179:        GetRTCDevice()->StartTime();
1.1.1.9   root      180: }
1.1       root      181: 
1.1.1.14  root      182: // スレッド終了指示
                    183: // (当然他スレッドから呼ぶことになる)
1.1.1.9   root      184: void
1.1.1.14  root      185: Scheduler::Terminate()
1.1.1.9   root      186: {
1.1.1.21! root      187:        std::lock_guard<std::mutex> lock(mtx);
1.1.1.14  root      188:        request |= REQUEST_EXIT;
                    189:        cv.notify_one();
1.1.1.9   root      190: }
1.1       root      191: 
1.1.1.14  root      192: // 指定のイベントを開始する。
                    193: // すでに同イベントが登録されている場合は古いイベントを削除してから
                    194: // 新しいイベントを再登録となる。
                    195: // イベントはワンショットのみ。
1.1.1.9   root      196: void
1.1.1.21! root      197: Scheduler::RestartEvent(Event *ev)
1.1.1.9   root      198: {
1.1.1.21! root      199:        if (ev->IsRunning()) {
1.1.1.14  root      200:                StopEvent(ev);
1.1.1.9   root      201:        }
1.1.1.14  root      202: 
                    203:        StartEvent(ev);
1.1       root      204: }
                    205: 
1.1.1.14  root      206: // 指定のイベントを開始する。
                    207: // このイベントが登録されてないことが確定できる場合のみこちらが使える。
                    208: // イベントはワンショットのみ。
1.1       root      209: void
1.1.1.21! root      210: Scheduler::StartEvent(Event *ev)
1.1       root      211: {
1.1.1.14  root      212:        CT(start);
                    213: #ifdef CT_ON
                    214:        if (ct_start % 100'000'000 == 0) {
1.1.1.17  root      215:                printf("get*=%" PRIu64 " [%" PRIu64 ", %" PRIu64 "]\n",
1.1.1.14  root      216:                        (ct_get1 + ct_get2), ct_get1, ct_get2);
1.1.1.17  root      217:                printf("start*=%" PRIu64
                    218:                        " [%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "]\n",
1.1.1.14  root      219:                        ct_start, ct_start1, ct_start2, ct_start3, ct_start4);
1.1.1.17  root      220:                printf("stop*=%" PRIu64 " [%" PRIu64 ", %" PRIu64 "]\n",
1.1.1.14  root      221:                        (ct_stop1 + ct_stop2), ct_stop1, ct_stop2);
1.1.1.17  root      222:                printf("eslow=%" PRIu64 " sslow=%" PRIu64 " pslow=%" PRIu64 "\n",
1.1.1.14  root      223:                        ct_eslow, ct_sslow, ct_pslow);
1.1.1.17  root      224:                printf("slow_top=%d vtime=%" PRIu64 "\n", slow_top, slow_top_vtime);
1.1.1.14  root      225:        }
                    226: #endif
                    227: 
                    228:        // この assert を有効にすると 10 ポイント性能が低下する(502%->492%)
1.1.1.21! root      229:        //assertmsg(ev->IsRunning() == false, "%s", ev->GetName().c_str());
1.1.1.14  root      230: 
                    231:        // vtime は仮想絶対時刻 [nsec]、time は仮想相対時間 [nsec]
1.1.1.21! root      232:        ev->vtime = vtime + ev->time;
1.1.1.14  root      233: 
1.1.1.21! root      234:        ev->active = true;
1.1.1.14  root      235: 
1.1.1.21! root      236:        if (__predict_true(ev->vtime <= slow_top_vtime)) {
1.1.1.14  root      237:                if (__predict_true(fast == NULL)) {
                    238:                        CT(start1);
1.1.1.21! root      239:                        fast = ev;
1.1.1.14  root      240:                } else {
1.1.1.21! root      241:                        if (__predict_false(ev->vtime <= fast->vtime)) {
1.1.1.14  root      242:                                CT(start2);
1.1.1.21! root      243:                                PushSlow(fast);
        !           244:                                fast = ev;
1.1.1.14  root      245:                        } else {
                    246:                                CT(start3);
                    247:                                PushSlow(ev);
                    248:                        }
                    249:                }
                    250:        } else {
                    251:                CT(start4);
                    252:                EnqueueSlow(ev);
1.1.1.10  root      253:        }
                    254: }
                    255: 
1.1.1.14  root      256: // 実時間間隔を指定してイベントを開始する。
                    257: // rt_now はイベント発行者の実時間での現在時刻で、
                    258: // rt_period は次回のイベントまでの実時間間隔。
                    259: void
1.1.1.21! root      260: Scheduler::StartRealtimeEvent(Event *ev, uint64 rt_now, uint64 rt_period)
1.1.1.14  root      261: {
                    262:        // 実時間をもとに仮想時間軸上の推定を行う。
                    263: 
1.1.1.16  root      264:        uint64 rtime = syncer->GetRealTime();
1.1.1.14  root      265: 
                    266:        if (rtime > rt_now + rt_period) {
                    267:                // 実時間がさらに 1 period 以上進んでいる。
                    268:                // 実時間に追いつかないといけないので、イベントの
                    269:                // 周期を短くして回復運転させる。
                    270:                // 周期を短くしすぎるとゲストが処理できなくなるので、
                    271:                // 10% カットに留める。
1.1.1.21! root      272:                ev->time = rt_period - rt_period / 10;
1.1.1.14  root      273:        } else if (rtime < rt_now - rt_period) {
                    274:                // イベントがさらに 1 period 以上進んでいる。
                    275:                // 実時間を追い越してしまっているので、イベントの
                    276:                // 周期を長くして待つ。長くする方はいくらでも長くしていいので、
                    277:                // 連続した場合はどんどん長くしていく。
1.1.1.21! root      278:                ev->time += rt_period;
1.1.1.14  root      279:        } else {
                    280:                // おおむね同期している
1.1.1.21! root      281:                ev->time = rt_period;
1.1.1.14  root      282:        }
                    283: 
                    284:        RestartEvent(ev);
                    285: }
                    286: 
                    287: // ev は slow_top には来ない前提
1.1.1.10  root      288: void
1.1.1.21! root      289: Scheduler::EnqueueSlow(Event *ev)
1.1.1.10  root      290: {
1.1.1.14  root      291:        CT(eslow);
                    292: 
                    293:        int s = slow_top;
                    294:        slow[++slow_top] = slow[s];
                    295: 
                    296:        for (; --s >= 0; ) {
1.1.1.21! root      297:                if (ev->vtime <= slow[s]->vtime) {
        !           298:                        slow[s + 1] = ev;
1.1.1.14  root      299:                        return;
                    300:                } else {
                    301:                        slow[s + 1] = slow[s];
                    302:                }
1.1.1.3   root      303:        }
1.1.1.21! root      304:        slow[0] = ev;
1.1       root      305: }
                    306: 
1.1.1.8   root      307: void
1.1.1.21! root      308: Scheduler::PushSlow(Event *ev)
1.1.1.8   root      309: {
1.1.1.14  root      310:        CT(pslow);
                    311: 
1.1.1.21! root      312:        slow[++slow_top] = ev;
        !           313:        slow_top_vtime = ev->vtime;
1.1.1.8   root      314: }
                    315: 
1.1.1.14  root      316: // 指定のイベントを停止する。
                    317: // 指定されたイベントが登録されていなければ何もしない。
1.1       root      318: void
1.1.1.21! root      319: Scheduler::StopEvent(Event *ev)
1.1       root      320: {
1.1.1.21! root      321:        ev->active = false;
1.1.1.14  root      322: 
1.1.1.21! root      323:        if (__predict_false(ev == fast)) {
1.1.1.14  root      324:                CT(stop1);
                    325:                fast = NULL;
1.1       root      326:        } else {
1.1.1.14  root      327:                CT(stop2);
                    328:                StopSlowEvent(ev);
1.1       root      329:        }
                    330: }
                    331: 
1.1.1.9   root      332: void
1.1.1.21! root      333: Scheduler::StopSlowEvent(Event *ev)
1.1.1.9   root      334: {
1.1.1.14  root      335:        CT(sslow);
                    336: 
                    337:        int s = slow_top;
                    338: 
                    339:        for (; s >= 0; s--) {
1.1.1.21! root      340:                if (ev == slow[s]) {
1.1.1.14  root      341:                        for (; s < slow_top; s++) {
                    342:                                slow[s] = slow[s + 1];
                    343:                        }
                    344:                        slow_top--;
                    345:                        if (slow_top < 0) {
                    346:                                slow_top_vtime = UINT64_MAX;
                    347:                        } else {
                    348:                                slow_top_vtime = slow[slow_top]->vtime;
                    349:                        }
                    350:                        break;
                    351:                }
1.1.1.9   root      352:        }
                    353: }
                    354: 
1.1.1.14  root      355: // メッセージハンドラを登録する。
1.1.1.9   root      356: void
1.1.1.14  root      357: Scheduler::ConnectMessage(MessageID msgid, Device *dev, MessageCallback_t func)
1.1.1.9   root      358: {
1.1.1.16  root      359:        assert(msgid < MessageID::MAX);
                    360: 
1.1.1.14  root      361:        auto& mh = message_handlers[msgid];
1.1.1.16  root      362:        assertmsg(mh.dev == NULL,
                    363:                "%s: msgid=%d connected again", __func__, (int)msgid);
1.1.1.14  root      364:        mh.dev = dev;
                    365:        mh.func = func;
1.1.1.9   root      366: }
                    367: 
1.1.1.14  root      368: // メッセージをディスパッチして、登録されていればハンドラを呼び出す。
1.1.1.9   root      369: void
1.1.1.14  root      370: Scheduler::DispatchMessage()
1.1.1.9   root      371: {
1.1.1.14  root      372:        uint64 msg;
1.1.1.9   root      373: 
1.1.1.14  root      374:        while (msgq.Dequeue(&msg)) {
                    375:                MessageID msgid = (MessageID)(msg & 0xff);
                    376:                uint32 arg = (msg >> 32);
1.1.1.9   root      377: 
1.1.1.16  root      378:                // MessageID::MPU_TRACE_ALL だけ特別対応。
                    379:                // MPU_TRACE メッセージの宛先は(最大)2つあるが、
                    380:                // スレッドを越える時は1メッセージにしておきたいので、
                    381:                // MPU_TRACE_ALL が来たらここで分岐。
                    382:                if (msgid == MessageID::MPU_TRACE_ALL) {
                    383:                        InvokeMessage(MessageID::MPU_TRACE_MAIN, arg);
                    384:                        InvokeMessage(MessageID::MPU_TRACE_XP, arg);
                    385:                } else {
                    386:                        assert(msgid < MessageID::MAX);
                    387:                        InvokeMessage(msgid, arg);
1.1.1.14  root      388:                }
1.1.1.9   root      389:        }
                    390: }
                    391: 
1.1.1.16  root      392: // メッセージハンドラを呼び出す。登録されてなければ何もしない。
                    393: void
                    394: Scheduler::InvokeMessage(MessageID msgid, uint32 arg)
                    395: {
                    396:        auto h = message_handlers[msgid];
                    397:        if (h.dev != NULL) {
                    398:                (h.dev->*(h.func))(msgid, arg);
                    399:        }
                    400: }
                    401: 
1.1.1.14  root      402: // メッセージを送る。
                    403: // VM スレッド以外から呼び出しても良い。
1.1       root      404: void
1.1.1.14  root      405: Scheduler::SendMessage(MessageID msgid, uint32 arg)
1.1       root      406: {
1.1.1.21! root      407:        std::lock_guard<std::mutex> lock(mtx);
1.1       root      408: 
1.1.1.16  root      409:        if (msgid < MessageID::MAX_REQUEST) {
                    410:                request |= 1U << (uint)msgid;
                    411:        } else {
                    412:                uint64 msg = (uint64)msgid | (((uint64)arg) << 32);
                    413:                if (msgq.Enqueue(msg) == false) {
                    414:                        putlog(0, "Message queue exhausted !! msgid=%d", (int)msgid);
                    415:                }
                    416:                request |= REQUEST_MESSAGE;
1.1       root      417:        }
1.1.1.14  root      418:        cv.notify_one();
1.1       root      419: }
                    420: 
1.1.1.14  root      421: // 指定時間が経過するか、リクエストが起きるまでスリープ
1.1       root      422: void
1.1.1.14  root      423: Scheduler::Sleep(uint64 time)
1.1       root      424: {
1.1.1.14  root      425:        std::unique_lock<std::mutex> lock(mtx);
                    426:        cv.wait_for(lock, std::chrono::nanoseconds(time), [&] {
                    427:                return (request != 0);
                    428:        });
                    429:        // リクエストフラグが立ってもここでは何もしない
1.1       root      430: }
                    431: 
1.1.1.5   root      432: void
1.1.1.10  root      433: Scheduler::MonitorUpdate(Monitor *, TextScreen& screen)
1.1       root      434: {
1.1.1.14  root      435:        int y;
1.1       root      436: 
1.1.1.10  root      437:        screen.Clear();
1.1       root      438: 
1.1.1.16  root      439:        y = syncer->MonitorUpdateSub(screen, vtime);
1.1.1.7   root      440: 
1.1.1.14  root      441:        // 0         1         2         3
                    442:        // 012345678901234567890123456789
1.1.1.15  root      443:        // Event Time     Remain Time
                    444:        //  3.123'456'789  3.123'456'789
1.1.1.14  root      445:        //
                    446:        // 3         4         5         6         7
                    447:        // 01234567890123456789012345678901234567890123456789
                    448:        // Description                                  Count
                    449:        // 012345678901234567890123456789 999,999,999,999,999
                    450:        //                         18,446,744,073,709,551,615
                    451:        y++;
                    452:        screen.Puts(0, y, "Event Time");
                    453:        screen.Puts(15, y, "Remain Time");
                    454:        screen.Puts(30, y, "Description");
                    455:        screen.Puts(75, y, "Count");
1.1       root      456:        y++;
1.1.1.6   root      457: 
1.1.1.21! root      458:        for (auto *ev : evman->all) {
1.1       root      459:                uint64 rem;
1.1.1.4   root      460:                TA attr;
1.1.1.15  root      461: 
1.1.1.14  root      462:                if (ev->IsRunning()) {
1.1.1.15  root      463:                        attr = TA::Normal;
1.1.1.14  root      464:                        if (ev->vtime > vtime) {
                    465:                                rem = ev->vtime - vtime;
1.1.1.6   root      466:                        } else {
                    467:                                // XXX 実際には起きないけど、この表示をするにあたって
                    468:                                // スケジューラスレッドと一切調停していないので、仮想時刻が
1.1.1.14  root      469:                                // ev->vtime (イベント発生時刻) をすぎていることがある。
1.1.1.6   root      470:                                // すぎてるので残り時間 0 と表示しておく。
                    471:                                rem = 0;
                    472:                        }
1.1       root      473:                } else {
1.1.1.15  root      474:                        attr = TA::Disable;
1.1       root      475:                        rem = 0;
                    476:                }
1.1.1.14  root      477: 
                    478:                if (ev->count != ev->last_count) {
                    479:                        attr = TA::Normal;
                    480:                        ev->last_count = ev->count;
                    481:                }
                    482: 
                    483:                // 先にイベント回数を表示。
                    484:                // 21文字以上になったら上位桁が長い Description で消されても
                    485:                // 大勢に影響はないだろう。
                    486:                std::string countstr = format_number(ev->count);
                    487:                screen.Print(54, y, attr, "%26s", countstr.c_str());
1.1.1.15  root      488:                screen.Print(0, y, attr, "%14s %14s %s ",
1.1.1.14  root      489:                        SecToStr(ev->time).c_str(),
1.1.1.9   root      490:                        SecToStr(rem).c_str(),
1.1.1.14  root      491:                        ev->GetName().c_str());
                    492:                y++;
1.1       root      493:        }
                    494: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.