1use core::sync::atomic::{AtomicU32, Ordering};
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36pub enum Slot {
37 HttpsGet = 0,
39 TlsWriteWait = 1,
41 TlsReadWait = 2,
43 CacheRead = 3,
45 CacheWrite = 4,
47 FetchScript = 5,
49 FontFace = 6,
51 FontParse = 7,
53 ImageDecode = 8,
55 SleepActual = 9,
57 PeekCheck = 10,
59 EthPoll = 11,
61 FirstByte = 12,
64 ReadSleep = 13,
66 ReadRecv = 14,
68 DnsQuery = 15,
70 TcpConnect = 16,
72 TlsHandshake = 17,
74 CssParse = 18,
76 CssKeyCmp = 19,
78 PaintBgImage = 20,
80 PaintGradient = 21,
82 PaintImg = 22,
84 PaintText = 23,
86 DrawCollect = 24,
88 DrawElements = 25,
90}
91
92pub const SLOT_COUNT: usize = 26;
94
95const NAMES: [&str; SLOT_COUNT] = [
97 "https取得",
98 "送信待ち",
99 "受信待ち",
100 "cache読",
101 "cache書",
102 "css/js取得",
103 "fontface",
104 "font解析",
105 "img復号",
106 "sleep実測",
107 "応答確認",
108 "eth poll",
109 "初回応答待ち",
110 "受信sleep",
111 "recv呼出",
112 "DNS",
113 "TCP接続",
114 "TLS握手",
115 "CSS解析",
116 "鍵比較",
117 "背景画像",
118 "グラデ",
119 "img描画",
120 "文字描画",
121 "画像収集",
122 "要素ループ",
123];
124
125const ZERO: AtomicU32 = AtomicU32::new(0);
126static TICKS: [AtomicU32; SLOT_COUNT] = [ZERO; SLOT_COUNT];
127static CALLS: [AtomicU32; SLOT_COUNT] = [ZERO; SLOT_COUNT];
128
129#[inline]
131pub fn start() -> usize {
132 crate::kernel::timer::get_ticks()
133}
134
135#[inline]
137pub fn add(slot: Slot, started: usize) {
138 let d = crate::kernel::timer::get_ticks().wrapping_sub(started);
139 let i = slot as usize;
140 if i < SLOT_COUNT {
141 TICKS[i].fetch_add(d as u32, Ordering::Relaxed);
142 CALLS[i].fetch_add(1, Ordering::Relaxed);
143 }
144}
145
146pub struct Guard {
158 slot: Slot,
159 started: usize,
160}
161
162impl Guard {
163 pub fn new(slot: Slot) -> Self {
164 Self {
165 slot,
166 started: start(),
167 }
168 }
169}
170
171impl Drop for Guard {
172 fn drop(&mut self) {
173 add(self.slot, self.started);
174 }
175}
176
177pub fn snapshot() -> [(&'static str, u32, u32); SLOT_COUNT] {
179 let mut out = [("", 0u32, 0u32); SLOT_COUNT];
180 for i in 0..SLOT_COUNT {
181 out[i] = (
182 NAMES[i],
183 TICKS[i].load(Ordering::Relaxed),
184 CALLS[i].load(Ordering::Relaxed),
185 );
186 }
187 out
188}
189
190pub fn dump(tag: &str) {
194 let s = snapshot();
195 crate::warn!(
196 "[PERF][ALL] {} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{}",
197 tag,
198 s[0].0, s[0].1, s[0].2,
199 s[1].0, s[1].1, s[1].2,
200 s[2].0, s[2].1, s[2].2,
201 s[3].0, s[3].1, s[3].2,
202 s[4].0, s[4].1, s[4].2,
203 s[5].0, s[5].1, s[5].2,
204 s[6].0, s[6].1, s[6].2,
205 s[7].0, s[7].1, s[7].2,
206 s[8].0, s[8].1, s[8].2,
207 );
208 crate::warn!(
209 "[PERF][ALL2] {} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{}",
210 tag,
211 s[9].0, s[9].1, s[9].2,
212 s[10].0, s[10].1, s[10].2,
213 s[11].0, s[11].1, s[11].2,
214 s[12].0, s[12].1, s[12].2,
215 s[13].0, s[13].1, s[13].2,
216 s[14].0, s[14].1, s[14].2,
217 );
218 crate::warn!(
219 "[PERF][ALL3] {} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{}",
220 tag,
221 s[15].0, s[15].1, s[15].2,
222 s[16].0, s[16].1, s[16].2,
223 s[17].0, s[17].1, s[17].2,
224 s[18].0, s[18].1, s[18].2,
225 s[19].0, s[19].1, s[19].2,
226 );
227 crate::warn!(
236 "[PERF][ALL4] {} 送信再送={} seg採用={} seg破棄={} RXフレーム={}",
237 tag,
238 crate::kernel::tls::WRITE_RETX_COUNT.load(core::sync::atomic::Ordering::Relaxed),
239 crate::kernel::net::tcp::SEG_ACCEPTED.load(core::sync::atomic::Ordering::Relaxed),
240 crate::kernel::net::tcp::SEG_DROPPED.load(core::sync::atomic::Ordering::Relaxed),
241 crate::kernel::usb::RX_FRAME_COUNT.load(core::sync::atomic::Ordering::Relaxed),
242 );
243 crate::warn!(
244 "[PERF][PAINT] {} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{} {}={}/{}",
245 tag,
246 s[20].0, s[20].1, s[20].2,
247 s[21].0, s[21].1, s[21].2,
248 s[22].0, s[22].1, s[22].2,
249 s[23].0, s[23].1, s[23].2,
250 s[24].0, s[24].1, s[24].2,
251 s[25].0, s[25].1, s[25].2,
252 );
253 }