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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
// Author: cirakg & claude ai
// Summary: Debug-only diagnostics: start-up time, memory, screen markers for UI scripts, and the performance overlay.
//
// Debug builds print one machine-readable line per event to the simulator
// console: "DIAG", the event name, then key=value pairs, for example
// DIAG first_frame startup_ms=1 mem_used=6984 mem_total=781888
// tools/check_budgets.py reads these lines and compares them with
// tools/budgets.json. Plain key=value pairs are used instead of JSON because
// the simulator console escapes quotes. Release builds compile the empty
// (:release) versions instead, so a real watch running a release build never
// logs anything.
//
// UI scripts (docker/scripts/screenshots.sh) wait for "DIAG shown <screen>"
// lines before taking a screenshot, and read the PIN keypad's key positions
// from "DIAG pin_keys" to tap them.
//
// Security rule: only timings and memory counters ever go through here, never
// secrets, codes or entry names. This is the only file allowed to call
// System.println outside tests (enforced by tools/lint_project.py).
import Toybox.Graphics;
import Toybox.Lang;
import Toybox.System;
// (:glance): the app object calls markStart() before the non-glance code is
// loaded (apps with a glance load the rest only for the full app).
(:glance)
module Diag {
// System.getTimer() value when the app object was created.
(:debug)
var startMs as Number = 0;
// Start the start-up timer. Called from OtpWalletApp.initialize().
(:debug)
function markStart() as Void {
startMs = System.getTimer();
}
(:release)
function markStart() as Void {
}
// Report start-up time and memory use after the first complete frame.
// startup_ms covers app object creation to the end of the first draw. The
// time the system needs to load the program before that is invisible to
// the app; app-diag.sh measures it from outside (README section 18).
(:debug)
function firstFrame() as Void {
var stats = System.getSystemStats();
System.println("DIAG first_frame startup_ms=" + (System.getTimer() - startMs)
+ " mem_used=" + stats.usedMemory + " mem_total=" + stats.totalMemory);
}
(:release)
function firstFrame() as Void {
}
// The glance's memory after its first draw (README 18: at most 70 % of
// the glance's 64 KB; `make memtest` checks it).
(:debug)
function glanceMemory() as Void {
var stats = System.getSystemStats();
System.println("DIAG glance mem_used=" + stats.usedMemory + " mem_total=" + stats.totalMemory);
}
(:release)
function glanceMemory() as Void {
}
// A screen finished its first draw since it was shown.
(:debug)
function shown(screen as String) as Void {
System.println("DIAG shown " + screen);
}
(:release)
function shown(screen as String) as Void {
}
// Free-form key=value data for UI scripts (never secrets).
(:debug)
function data(event as String, values as String) as Void {
System.println("DIAG " + event + " " + values);
}
(:release)
function data(event as String, values as String) as Void {
}
// The performance overlay (toggled in the debug menu): draw time of the
// frame that started at startMs, and memory use.
(:debug)
var overlayOn as Boolean = false;
(:debug)
function overlay(dc as Graphics.Dc, frameStartMs as Number) as Void {
if (!overlayOn) {
return;
}
var stats = System.getSystemStats();
var text = (System.getTimer() - frameStartMs) + " ms " + (stats.usedMemory * 100 / stats.totalMemory) + "% mem";
dc.setColor(Graphics.COLOR_YELLOW, Graphics.COLOR_BLACK);
dc.drawText(dc.getWidth() / 2, dc.getHeight() - dc.getFontHeight(Graphics.FONT_XTINY) - 2, Graphics.FONT_XTINY,
text, Graphics.TEXT_JUSTIFY_CENTER);
}
(:release)
function overlay(dc as Graphics.Dc, frameStartMs as Number) as Void {
}
// Peak memory while long work runs (sampled by the import job).
(:debug)
var peakMemory as Number = 0;
(:debug)
function sampleMemory() as Void {
var used = System.getSystemStats().usedMemory;
if (used > peakMemory) {
peakMemory = used;
}
}
(:release)
function sampleMemory() as Void {
}
// Reports an import's size, duration and peak memory for UI scripts.
(:debug)
function importDone(entries as Number, wallMs as Number) as Void {
System.println("DIAG import entries=" + entries + " wall_ms=" + wallMs + " mem_peak=" + peakMemory
+ " mem_total=" + System.getSystemStats().totalMemory);
}
(:release)
function importDone(entries as Number, wallMs as Number) as Void {
}
}
|