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

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

unix.superglobalmegacorp.com

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