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

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

unix.superglobalmegacorp.com

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