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

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.22! root       12: // 仮想時間はすべて tsec で表し、StartTime() から単調増加する。
1.1.1.14  root       13: // VM 界からは仮想時間は gScheduler->GetVirtTime() で取得する。
1.1       root       14: //
1.1.1.22! root       15: // 実時間は Syncer が管理し、こちらも tsec で表す。
1.1.1.14  root       16: // このストップウォッチも StartTime() から単調増加する。
                     17: // 実時間、仮想時間とも電源オフ中でも単調増加することに注意。
1.1.1.9   root       18: //
1.1.1.22! root       19: // 「実経過時間」は gRealtime.Elapsed_nsec() で取得できるが tsec で保持する。
1.1.1.14  root       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);
1.1.1.22! root       75:        monitor->SetCallback(&Scheduler::MonitorScreen);
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.22! root      159:                auto dev  = ev->GetOwner();
        !           160:                auto func = ev->GetCallback();
        !           161:                (dev->*(func))(ev);
1.1       root      162:        }
1.1.1.9   root      163: }
1.1       root      164: 
1.1.1.14  root      165: // 時間の始まり
                    166: void
                    167: Scheduler::StartTime()
1.1.1.9   root      168: {
1.1.1.14  root      169:        // イベントキューを空にする
1.1.1.21  root      170:        for (auto *ev : evman->all) {
1.1.1.14  root      171:                if (ev->active) {
1.1.1.21  root      172:                        StopEvent(ev);
1.1.1.9   root      173:                }
1.1.1.14  root      174:                ev->count = 0;
1.1.1.9   root      175:        }
1.1.1.14  root      176: 
                    177:        // 時間をリセットする。
                    178:        // 呼び出しの依存関係に注意。
                    179:        vtime = 0;                                      // required by Sync
1.1.1.16  root      180:        syncer->StartTime();            // required by RTC
                    181:        GetRTCDevice()->StartTime();
1.1.1.9   root      182: }
1.1       root      183: 
1.1.1.14  root      184: // スレッド終了指示
                    185: // (当然他スレッドから呼ぶことになる)
1.1.1.9   root      186: void
1.1.1.14  root      187: Scheduler::Terminate()
1.1.1.9   root      188: {
1.1.1.21  root      189:        std::lock_guard<std::mutex> lock(mtx);
1.1.1.14  root      190:        request |= REQUEST_EXIT;
                    191:        cv.notify_one();
1.1.1.9   root      192: }
1.1       root      193: 
1.1.1.14  root      194: // 指定のイベントを開始する。
                    195: // すでに同イベントが登録されている場合は古いイベントを削除してから
                    196: // 新しいイベントを再登録となる。
                    197: // イベントはワンショットのみ。
1.1.1.9   root      198: void
1.1.1.21  root      199: Scheduler::RestartEvent(Event *ev)
1.1.1.9   root      200: {
1.1.1.21  root      201:        if (ev->IsRunning()) {
1.1.1.14  root      202:                StopEvent(ev);
1.1.1.9   root      203:        }
1.1.1.14  root      204: 
                    205:        StartEvent(ev);
1.1       root      206: }
                    207: 
1.1.1.14  root      208: // 指定のイベントを開始する。
                    209: // このイベントが登録されてないことが確定できる場合のみこちらが使える。
                    210: // イベントはワンショットのみ。
1.1       root      211: void
1.1.1.21  root      212: Scheduler::StartEvent(Event *ev)
1.1       root      213: {
1.1.1.14  root      214:        CT(start);
                    215: #ifdef CT_ON
                    216:        if (ct_start % 100'000'000 == 0) {
1.1.1.17  root      217:                printf("get*=%" PRIu64 " [%" PRIu64 ", %" PRIu64 "]\n",
1.1.1.14  root      218:                        (ct_get1 + ct_get2), ct_get1, ct_get2);
1.1.1.17  root      219:                printf("start*=%" PRIu64
                    220:                        " [%" PRIu64 ", %" PRIu64 ", %" PRIu64 ", %" PRIu64 "]\n",
1.1.1.14  root      221:                        ct_start, ct_start1, ct_start2, ct_start3, ct_start4);
1.1.1.17  root      222:                printf("stop*=%" PRIu64 " [%" PRIu64 ", %" PRIu64 "]\n",
1.1.1.14  root      223:                        (ct_stop1 + ct_stop2), ct_stop1, ct_stop2);
1.1.1.17  root      224:                printf("eslow=%" PRIu64 " sslow=%" PRIu64 " pslow=%" PRIu64 "\n",
1.1.1.14  root      225:                        ct_eslow, ct_sslow, ct_pslow);
1.1.1.17  root      226:                printf("slow_top=%d vtime=%" PRIu64 "\n", slow_top, slow_top_vtime);
1.1.1.14  root      227:        }
                    228: #endif
                    229: 
                    230:        // この assert を有効にすると 10 ポイント性能が低下する(502%->492%)
1.1.1.21  root      231:        //assertmsg(ev->IsRunning() == false, "%s", ev->GetName().c_str());
1.1.1.14  root      232: 
1.1.1.22! root      233:        // vtime は仮想絶対時刻 [tsec]、time は仮想相対時間 [tsec]
1.1.1.21  root      234:        ev->vtime = vtime + ev->time;
1.1.1.14  root      235: 
1.1.1.21  root      236:        ev->active = true;
1.1.1.14  root      237: 
1.1.1.21  root      238:        if (__predict_true(ev->vtime <= slow_top_vtime)) {
1.1.1.14  root      239:                if (__predict_true(fast == NULL)) {
                    240:                        CT(start1);
1.1.1.21  root      241:                        fast = ev;
1.1.1.14  root      242:                } else {
1.1.1.21  root      243:                        if (__predict_false(ev->vtime <= fast->vtime)) {
1.1.1.14  root      244:                                CT(start2);
1.1.1.21  root      245:                                PushSlow(fast);
                    246:                                fast = ev;
1.1.1.14  root      247:                        } else {
                    248:                                CT(start3);
                    249:                                PushSlow(ev);
                    250:                        }
                    251:                }
                    252:        } else {
                    253:                CT(start4);
                    254:                EnqueueSlow(ev);
1.1.1.10  root      255:        }
                    256: }
                    257: 
1.1.1.14  root      258: // 実時間間隔を指定してイベントを開始する。
                    259: // rt_now はイベント発行者の実時間での現在時刻で、
                    260: // rt_period は次回のイベントまでの実時間間隔。
                    261: void
1.1.1.21  root      262: Scheduler::StartRealtimeEvent(Event *ev, uint64 rt_now, uint64 rt_period)
1.1.1.14  root      263: {
                    264:        // 実時間をもとに仮想時間軸上の推定を行う。
                    265: 
1.1.1.16  root      266:        uint64 rtime = syncer->GetRealTime();
1.1.1.14  root      267: 
                    268:        if (rtime > rt_now + rt_period) {
                    269:                // 実時間がさらに 1 period 以上進んでいる。
                    270:                // 実時間に追いつかないといけないので、イベントの
                    271:                // 周期を短くして回復運転させる。
                    272:                // 周期を短くしすぎるとゲストが処理できなくなるので、
                    273:                // 10% カットに留める。
1.1.1.21  root      274:                ev->time = rt_period - rt_period / 10;
1.1.1.14  root      275:        } else if (rtime < rt_now - rt_period) {
                    276:                // イベントがさらに 1 period 以上進んでいる。
                    277:                // 実時間を追い越してしまっているので、イベントの
                    278:                // 周期を長くして待つ。長くする方はいくらでも長くしていいので、
                    279:                // 連続した場合はどんどん長くしていく。
1.1.1.21  root      280:                ev->time += rt_period;
1.1.1.14  root      281:        } else {
                    282:                // おおむね同期している
1.1.1.21  root      283:                ev->time = rt_period;
1.1.1.14  root      284:        }
                    285: 
                    286:        RestartEvent(ev);
                    287: }
                    288: 
                    289: // ev は slow_top には来ない前提
1.1.1.10  root      290: void
1.1.1.21  root      291: Scheduler::EnqueueSlow(Event *ev)
1.1.1.10  root      292: {
1.1.1.14  root      293:        CT(eslow);
                    294: 
                    295:        int s = slow_top;
                    296:        slow[++slow_top] = slow[s];
                    297: 
                    298:        for (; --s >= 0; ) {
1.1.1.21  root      299:                if (ev->vtime <= slow[s]->vtime) {
                    300:                        slow[s + 1] = ev;
1.1.1.14  root      301:                        return;
                    302:                } else {
                    303:                        slow[s + 1] = slow[s];
                    304:                }
1.1.1.3   root      305:        }
1.1.1.21  root      306:        slow[0] = ev;
1.1       root      307: }
                    308: 
1.1.1.8   root      309: void
1.1.1.21  root      310: Scheduler::PushSlow(Event *ev)
1.1.1.8   root      311: {
1.1.1.14  root      312:        CT(pslow);
                    313: 
1.1.1.21  root      314:        slow[++slow_top] = ev;
                    315:        slow_top_vtime = ev->vtime;
1.1.1.8   root      316: }
                    317: 
1.1.1.14  root      318: // 指定のイベントを停止する。
                    319: // 指定されたイベントが登録されていなければ何もしない。
1.1       root      320: void
1.1.1.21  root      321: Scheduler::StopEvent(Event *ev)
1.1       root      322: {
1.1.1.21  root      323:        ev->active = false;
1.1.1.14  root      324: 
1.1.1.21  root      325:        if (__predict_false(ev == fast)) {
1.1.1.14  root      326:                CT(stop1);
                    327:                fast = NULL;
1.1       root      328:        } else {
1.1.1.14  root      329:                CT(stop2);
                    330:                StopSlowEvent(ev);
1.1       root      331:        }
                    332: }
                    333: 
1.1.1.9   root      334: void
1.1.1.21  root      335: Scheduler::StopSlowEvent(Event *ev)
1.1.1.9   root      336: {
1.1.1.14  root      337:        CT(sslow);
                    338: 
                    339:        int s = slow_top;
                    340: 
                    341:        for (; s >= 0; s--) {
1.1.1.21  root      342:                if (ev == slow[s]) {
1.1.1.14  root      343:                        for (; s < slow_top; s++) {
                    344:                                slow[s] = slow[s + 1];
                    345:                        }
                    346:                        slow_top--;
                    347:                        if (slow_top < 0) {
                    348:                                slow_top_vtime = UINT64_MAX;
                    349:                        } else {
                    350:                                slow_top_vtime = slow[slow_top]->vtime;
                    351:                        }
                    352:                        break;
                    353:                }
1.1.1.9   root      354:        }
                    355: }
                    356: 
1.1.1.14  root      357: // メッセージハンドラを登録する。
1.1.1.9   root      358: void
1.1.1.14  root      359: Scheduler::ConnectMessage(MessageID msgid, Device *dev, MessageCallback_t func)
1.1.1.9   root      360: {
1.1.1.16  root      361:        assert(msgid < MessageID::MAX);
                    362: 
1.1.1.14  root      363:        auto& mh = message_handlers[msgid];
1.1.1.16  root      364:        assertmsg(mh.dev == NULL,
                    365:                "%s: msgid=%d connected again", __func__, (int)msgid);
1.1.1.14  root      366:        mh.dev = dev;
                    367:        mh.func = func;
1.1.1.9   root      368: }
                    369: 
1.1.1.14  root      370: // メッセージをディスパッチして、登録されていればハンドラを呼び出す。
1.1.1.9   root      371: void
1.1.1.14  root      372: Scheduler::DispatchMessage()
1.1.1.9   root      373: {
1.1.1.14  root      374:        uint64 msg;
1.1.1.9   root      375: 
1.1.1.14  root      376:        while (msgq.Dequeue(&msg)) {
                    377:                MessageID msgid = (MessageID)(msg & 0xff);
                    378:                uint32 arg = (msg >> 32);
1.1.1.9   root      379: 
1.1.1.16  root      380:                // MessageID::MPU_TRACE_ALL だけ特別対応。
                    381:                // MPU_TRACE メッセージの宛先は(最大)2つあるが、
                    382:                // スレッドを越える時は1メッセージにしておきたいので、
                    383:                // MPU_TRACE_ALL が来たらここで分岐。
                    384:                if (msgid == MessageID::MPU_TRACE_ALL) {
                    385:                        InvokeMessage(MessageID::MPU_TRACE_MAIN, arg);
                    386:                        InvokeMessage(MessageID::MPU_TRACE_XP, arg);
                    387:                } else {
                    388:                        assert(msgid < MessageID::MAX);
                    389:                        InvokeMessage(msgid, arg);
1.1.1.14  root      390:                }
1.1.1.9   root      391:        }
                    392: }
                    393: 
1.1.1.16  root      394: // メッセージハンドラを呼び出す。登録されてなければ何もしない。
                    395: void
                    396: Scheduler::InvokeMessage(MessageID msgid, uint32 arg)
                    397: {
                    398:        auto h = message_handlers[msgid];
                    399:        if (h.dev != NULL) {
                    400:                (h.dev->*(h.func))(msgid, arg);
                    401:        }
                    402: }
                    403: 
1.1.1.14  root      404: // メッセージを送る。
                    405: // VM スレッド以外から呼び出しても良い。
1.1       root      406: void
1.1.1.14  root      407: Scheduler::SendMessage(MessageID msgid, uint32 arg)
1.1       root      408: {
1.1.1.21  root      409:        std::lock_guard<std::mutex> lock(mtx);
1.1       root      410: 
1.1.1.16  root      411:        if (msgid < MessageID::MAX_REQUEST) {
                    412:                request |= 1U << (uint)msgid;
                    413:        } else {
                    414:                uint64 msg = (uint64)msgid | (((uint64)arg) << 32);
                    415:                if (msgq.Enqueue(msg) == false) {
                    416:                        putlog(0, "Message queue exhausted !! msgid=%d", (int)msgid);
                    417:                }
                    418:                request |= REQUEST_MESSAGE;
1.1       root      419:        }
1.1.1.14  root      420:        cv.notify_one();
1.1       root      421: }
                    422: 
1.1.1.14  root      423: // 指定時間が経過するか、リクエストが起きるまでスリープ
1.1       root      424: void
1.1.1.14  root      425: Scheduler::Sleep(uint64 time)
1.1       root      426: {
1.1.1.14  root      427:        std::unique_lock<std::mutex> lock(mtx);
                    428:        cv.wait_for(lock, std::chrono::nanoseconds(time), [&] {
                    429:                return (request != 0);
                    430:        });
                    431:        // リクエストフラグが立ってもここでは何もしない
1.1       root      432: }
                    433: 
1.1.1.5   root      434: void
1.1.1.22! root      435: Scheduler::MonitorScreen(Monitor *, TextScreen& screen)
1.1       root      436: {
1.1.1.14  root      437:        int y;
1.1       root      438: 
1.1.1.10  root      439:        screen.Clear();
1.1       root      440: 
1.1.1.22! root      441:        y = syncer->MonitorScreenSub(screen, vtime);
1.1.1.7   root      442: 
1.1.1.14  root      443:        // 0         1         2         3
                    444:        // 012345678901234567890123456789
1.1.1.15  root      445:        // Event Time     Remain Time
                    446:        //  3.123'456'789  3.123'456'789
1.1.1.14  root      447:        //
                    448:        // 3         4         5         6         7
                    449:        // 01234567890123456789012345678901234567890123456789
                    450:        // Description                                  Count
                    451:        // 012345678901234567890123456789 999,999,999,999,999
                    452:        //                         18,446,744,073,709,551,615
                    453:        y++;
                    454:        screen.Puts(0, y, "Event Time");
                    455:        screen.Puts(15, y, "Remain Time");
                    456:        screen.Puts(30, y, "Description");
                    457:        screen.Puts(75, y, "Count");
1.1       root      458:        y++;
1.1.1.6   root      459: 
1.1.1.21  root      460:        for (auto *ev : evman->all) {
1.1       root      461:                uint64 rem;
1.1.1.4   root      462:                TA attr;
1.1.1.15  root      463: 
1.1.1.14  root      464:                if (ev->IsRunning()) {
1.1.1.15  root      465:                        attr = TA::Normal;
1.1.1.14  root      466:                        if (ev->vtime > vtime) {
                    467:                                rem = ev->vtime - vtime;
1.1.1.6   root      468:                        } else {
                    469:                                // XXX 実際には起きないけど、この表示をするにあたって
                    470:                                // スケジューラスレッドと一切調停していないので、仮想時刻が
1.1.1.14  root      471:                                // ev->vtime (イベント発生時刻) をすぎていることがある。
1.1.1.6   root      472:                                // すぎてるので残り時間 0 と表示しておく。
                    473:                                rem = 0;
                    474:                        }
1.1       root      475:                } else {
1.1.1.15  root      476:                        attr = TA::Disable;
1.1       root      477:                        rem = 0;
                    478:                }
1.1.1.14  root      479: 
                    480:                if (ev->count != ev->last_count) {
                    481:                        attr = TA::Normal;
                    482:                        ev->last_count = ev->count;
                    483:                }
                    484: 
                    485:                // 先にイベント回数を表示。
                    486:                // 21文字以上になったら上位桁が長い Description で消されても
                    487:                // 大勢に影響はないだろう。
                    488:                std::string countstr = format_number(ev->count);
                    489:                screen.Print(54, y, attr, "%26s", countstr.c_str());
1.1.1.15  root      490:                screen.Print(0, y, attr, "%14s %14s %s ",
1.1.1.14  root      491:                        SecToStr(ev->time).c_str(),
1.1.1.9   root      492:                        SecToStr(rem).c_str(),
1.1.1.14  root      493:                        ev->GetName().c_str());
                    494:                y++;
1.1       root      495:        }
                    496: }

unix.superglobalmegacorp.com

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