diff options
Diffstat (limited to 'rsnix/src/klog.rs')
| -rw-r--r-- | rsnix/src/klog.rs | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/rsnix/src/klog.rs b/rsnix/src/klog.rs index 1e23460..0c7dc06 100644 --- a/rsnix/src/klog.rs +++ b/rsnix/src/klog.rs | |||
| @@ -32,6 +32,10 @@ struct Ring { | |||
| 32 | count: usize, | 32 | count: usize, |
| 33 | /// Slot the next line will be written to (oldest once full). | 33 | /// Slot the next line will be written to (oldest once full). |
| 34 | next: usize, | 34 | next: usize, |
| 35 | /// Highest timestamp seen, so the log stays monotonic even before | ||
| 36 | /// the timer is running (early-boot PIT reads are uninitialised). | ||
| 37 | last_ms: u64, | ||
| 38 | ms: [u64; MAX_LINES], | ||
| 35 | lens: [u8; MAX_LINES], | 39 | lens: [u8; MAX_LINES], |
| 36 | bytes: [[u8; MAX_LINE]; MAX_LINES], | 40 | bytes: [[u8; MAX_LINE]; MAX_LINES], |
| 37 | } | 41 | } |
| @@ -41,6 +45,8 @@ static mut RING: Ring = Ring { | |||
| 41 | dropped: 0, | 45 | dropped: 0, |
| 42 | count: 0, | 46 | count: 0, |
| 43 | next: 0, | 47 | next: 0, |
| 48 | last_ms: 0, | ||
| 49 | ms: [0; MAX_LINES], | ||
| 44 | lens: [0; MAX_LINES], | 50 | lens: [0; MAX_LINES], |
| 45 | bytes: [[0; MAX_LINE]; MAX_LINES], | 51 | bytes: [[0; MAX_LINE]; MAX_LINES], |
| 46 | }; | 52 | }; |
| @@ -49,10 +55,16 @@ fn ring() -> &'static mut Ring { | |||
| 49 | unsafe { &mut *core::ptr::addr_of_mut!(RING) } | 55 | unsafe { &mut *core::ptr::addr_of_mut!(RING) } |
| 50 | } | 56 | } |
| 51 | 57 | ||
| 52 | /// Append one line to the ring (line-oriented; newlines are stripped). | 58 | /// Append one line to the ring with its timestamp in ms (line-oriented; |
| 53 | /// Truncated at MAX_LINE bytes. Never allocates, never logs. | 59 | /// newlines are stripped). Truncated at MAX_LINE bytes. Never |
| 54 | pub fn append(line: &str) { | 60 | /// allocates, never logs. Timestamps are clamped to be monotonic. |
| 61 | pub fn append(line: &str, mut ms: u64) { | ||
| 55 | let r = ring(); | 62 | let r = ring(); |
| 63 | if ms > r.last_ms { | ||
| 64 | r.last_ms = ms; | ||
| 65 | } else { | ||
| 66 | ms = r.last_ms; | ||
| 67 | } | ||
| 56 | let b = line.as_bytes(); | 68 | let b = line.as_bytes(); |
| 57 | let n = b.len().min(MAX_LINE); | 69 | let n = b.len().min(MAX_LINE); |
| 58 | if r.count == MAX_LINES { | 70 | if r.count == MAX_LINES { |
| @@ -60,6 +72,7 @@ pub fn append(line: &str) { | |||
| 60 | } else { | 72 | } else { |
| 61 | r.count += 1; | 73 | r.count += 1; |
| 62 | } | 74 | } |
| 75 | r.ms[r.next] = ms; | ||
| 63 | r.bytes[r.next][..n].copy_from_slice(&b[..n]); | 76 | r.bytes[r.next][..n].copy_from_slice(&b[..n]); |
| 64 | r.lens[r.next] = n as u8; | 77 | r.lens[r.next] = n as u8; |
| 65 | r.next = (r.next + 1) % MAX_LINES; | 78 | r.next = (r.next + 1) % MAX_LINES; |
| @@ -68,11 +81,14 @@ pub fn append(line: &str) { | |||
| 68 | 81 | ||
| 69 | /// Append the formatted output of a `serial_println!` — the macro hook. | 82 | /// Append the formatted output of a `serial_println!` — the macro hook. |
| 70 | /// `fmt::Write` may deliver the line in several chunks, so accumulate | 83 | /// `fmt::Write` may deliver the line in several chunks, so accumulate |
| 71 | /// into one line buffer first, then append the whole line. | 84 | /// into one line buffer first, then append the whole line. The |
| 85 | /// timestamp is taken when the line is emitted (monotonic ms since | ||
| 86 | /// boot, from the PIT tick + live-counter interpolation). | ||
| 72 | pub fn append_fmt(args: core::fmt::Arguments<'_>) { | 87 | pub fn append_fmt(args: core::fmt::Arguments<'_>) { |
| 88 | let ms = crate::interrupts::uptime_ms(); | ||
| 73 | let mut line = LineBuf::new(); | 89 | let mut line = LineBuf::new(); |
| 74 | let _ = core::fmt::write(&mut line, args); | 90 | let _ = core::fmt::write(&mut line, args); |
| 75 | append(line.as_str()); | 91 | append(line.as_str(), ms); |
| 76 | } | 92 | } |
| 77 | 93 | ||
| 78 | struct LineBuf { | 94 | struct LineBuf { |
| @@ -124,7 +140,9 @@ pub fn dump() -> String { | |||
| 124 | let idx = (start + i) % MAX_LINES; | 140 | let idx = (start + i) % MAX_LINES; |
| 125 | let n = r.lens[idx] as usize; | 141 | let n = r.lens[idx] as usize; |
| 126 | let text = core::str::from_utf8(&r.bytes[idx][..n]).unwrap_or(""); | 142 | let text = core::str::from_utf8(&r.bytes[idx][..n]).unwrap_or(""); |
| 127 | out += &alloc::format!("{:06} {}\n", first + i as u64, text); | 143 | let s = r.ms[idx] / 1000; |
| 144 | let m = r.ms[idx] % 1000; | ||
| 145 | out += &alloc::format!("[{:04}.{:03}] {:06} {}\n", s, m, first + i as u64, text); | ||
| 128 | } | 146 | } |
| 129 | out | 147 | out |
| 130 | } | 148 | } |
