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

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

unix.superglobalmegacorp.com

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