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

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

unix.superglobalmegacorp.com

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