eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1import UIKit
2
3// 🤖 TEMPORARY diagnostic (DEBUG only): a display link that records every
4// dropped frame with what published/ran just before it, appended to
5// Documents/hitches.log — pulled off the device with `devicectl device copy
6// from` and read on the Mac. Delete once the scroll hitch is nailed.
7#if DEBUG
8final class HitchLogger {
9 static let shared = HitchLogger()
10
11 private var link: CADisplayLink?
12 private var lastTimestamp: CFTimeInterval = 0
13 private var recentNotes: [String] = []
14 private var pending: [String] = []
15 private lazy var file: URL = FileManager.default
16 .urls(for: .documentDirectory, in: .userDomainMask)[0]
17 .appendingPathComponent("hitches.log")
18
19 func start() {
20 guard link == nil else { return }
21 try? FileManager.default.removeItem(at: file)
22 let l = CADisplayLink(target: self, selector: #selector(tick))
23 l.add(to: .main, forMode: .common)
24 link = l
25 note("logger started")
26 }
27
28 /// Breadcrumb: publishes, pins, gestures — whatever ran near a hitch.
29 func note(_ what: String) {
30 let stamp = String(format: "%.3f", CACurrentMediaTime())
31 recentNotes.append("\(stamp) \(what)")
32 if recentNotes.count > 6 { recentNotes.removeFirst() }
33 }
34
35 @objc private func tick(_ l: CADisplayLink) {
36 defer { lastTimestamp = l.timestamp }
37 guard lastTimestamp > 0 else { return }
38 let dt = l.timestamp - lastTimestamp
39 let expected = l.duration > 0 ? l.duration : 1.0 / 60.0
40 guard dt > expected * 1.6 else { return } // a properly dropped frame
41 let ms = Int(dt * 1000)
42 pending.append("HITCH \(ms)ms at \(String(format: "%.3f", l.timestamp)) | recent: "
43 + recentNotes.joined(separator: " · "))
44 flush()
45 }
46
47 private func flush() {
48 guard !pending.isEmpty else { return }
49 let text = pending.joined(separator: "\n") + "\n"
50 pending.removeAll()
51 let file = self.file
52 // Off main — the logger's own synchronous writes were adding stalls
53 // to the very storms it measures.
54 writeQueue.async {
55 if let handle = try? FileHandle(forWritingTo: file) {
56 handle.seekToEndOfFile()
57 handle.write(Data(text.utf8))
58 try? handle.close()
59 } else {
60 try? Data(text.utf8).write(to: file)
61 }
62 }
63 }
64
65 private let writeQueue = DispatchQueue(label: "hitch-log", qos: .utility)
66}
67#endif
68