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

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

unix.superglobalmegacorp.com

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