aboutsummaryrefslogtreecommitdiff
path: root/source/ui/DebugMenu.mc
blob: 452cb1d9b1994bf07c9c4976e56e0d080d3ef9fa (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Author:  cirakg & claude ai
// Summary: Debug-only menu items: load demo entries, the performance overlay and the on-watch benchmark.
//
// Release builds compile the empty (:release) module instead, so none of this
// reaches the Store build. The benchmark is how the watch's real speed gets
// measured (docs/PERFORMANCE.md): sideload a debug build and run it.

import Toybox.Lang;
import Toybox.System;
import Toybox.Timer;
import Toybox.WatchUi;

(:debug)
module DebugMenu {

    function addItems(menu as WatchUi.Menu2) as Void {
        menu.addItem(new WatchUi.MenuItem("Debug: demo entries", "Adds fake entries", :debugDemo, null));
        menu.addItem(new WatchUi.MenuItem("Debug: overlay", Diag.overlayOn ? "On" : "Off", :debugOverlay, null));
        menu.addItem(new WatchUi.MenuItem("Debug: benchmark", "Takes a few seconds", :debugBench, null));
    }

    function handle(id as Object?) as Void {
        if (id == :debugDemo) {
            try {
                Fixtures.load(AppState.theVault());
            } catch (e instanceof VaultError) {
                // Entry cap or full store: load what fits.
            }
            AppState.theCodes().clear();
            WatchUi.popView(WatchUi.SLIDE_DOWN);
        } else if (id == :debugOverlay) {
            Diag.overlayOn = !Diag.overlayOn;
            WatchUi.popView(WatchUi.SLIDE_DOWN);
        } else if (id == :debugBench) {
            var runner = new BenchRunner();
            bench = runner;
            WatchUi.switchToView(new InfoView("Benchmark", ["Measuring…"], "bench_running"), new InfoDelegate(),
                WatchUi.SLIDE_LEFT);
            runner.start();
        }
    }

    const BENCH_HEADERS = 20;

    // The running benchmark (kept so its timer isn't collected).
    var bench as BenchRunner? = null;

    // Times the operations the budgets depend on, one per timer event, so no
    // event comes near the watchdog limit (it is enforced on the watch and in
    // normal simulator runs).
    class BenchRunner {

        private var _lines as Array<String> = [] as Array<String>;
        private var _step as Number = 0;
        private var _timer as Timer.Timer? = null;

        function initialize() {
        }

        function start() as Void {
            var t = new Timer.Timer();
            t.start(method(:tick), 200, true);
            _timer = t;
        }

        function tick() as Void {
            var t = System.getTimer();
            if (_step == 0) {
                for (var i = 0; i < 5; i++) {
                    Otp.totp(Hashes.SHA1, new [20]b, 1800000000l, 30, 6);
                }
                _lines.add("TOTP SHA-1: " + (System.getTimer() - t) / 5 + " ms");
            } else if (_step == 1) {
                Otp.totp(Hashes.SHA512, new [64]b, 1800000000l, 30, 6);
                _lines.add("TOTP SHA-512: " + (System.getTimer() - t) + " ms");
            } else if (_step == 2) {
                _lines.add("PIN derivation: " + Kdf.calibrate(1000, Kdf.ITERATIONS_PER_STEP) + " iterations per second");
            } else if (_step == 3) {
                // At most BENCH_HEADERS: all 110 of the UI test's entries in
                // one event tripped the watchdog.
                var vault = AppState.theVault();
                var ids = vault.ids();
                var n = ids.size() < BENCH_HEADERS ? ids.size() : BENCH_HEADERS;
                for (var i = 0; i < n; i++) {
                    vault.header(ids[i]);
                }
                _lines.add("Headers: " + n + " in " + (System.getTimer() - t) + " ms");
            } else if (_step == 4) {
                SelfTest.run();
                _lines.add("Self-test: " + (System.getTimer() - t) + " ms");
            } else {
                var stats = System.getSystemStats();
                _lines.add("Memory: " + stats.usedMemory / 1024 + " of " + stats.totalMemory / 1024 + " KB");
                var timer = _timer;
                if (timer != null) {
                    timer.stop();
                }
                bench = null;
                WatchUi.switchToView(new InfoView("Benchmark", _lines, "bench"), new InfoDelegate(), WatchUi.SLIDE_IMMEDIATE);
                return;
            }
            _step++;
        }
    }
}

(:release)
module DebugMenu {

    function addItems(menu as WatchUi.Menu2) as Void {
    }

    function handle(id as Object?) as Void {
    }
}