Sapling/Sources/SaplingEditor/EditorInstrumentation.swift

144 lines
5.1 KiB
Swift
Raw Normal View History

import Foundation
public enum EditorRenderReason: String, Hashable, Codable, Sendable {
case initial
case sourceChange
case activeLineChange
case viewUpdate
}
public struct EditorRenderPassMetric: Hashable, Sendable {
public var reason: EditorRenderReason
public var durationMilliseconds: Double
public var characterCount: Int
public var lineCount: Int
public var dirtyLineCount: Int
public var activeLineIndex: Int
public var isFullRender: Bool
public var restoredScrollPosition: Bool
public init(
reason: EditorRenderReason,
durationMilliseconds: Double,
characterCount: Int,
lineCount: Int,
dirtyLineCount: Int = 0,
activeLineIndex: Int,
isFullRender: Bool = false,
restoredScrollPosition: Bool = false
) {
self.reason = reason
self.durationMilliseconds = durationMilliseconds
self.characterCount = characterCount
self.lineCount = lineCount
self.dirtyLineCount = dirtyLineCount
self.activeLineIndex = activeLineIndex
self.isFullRender = isFullRender
self.restoredScrollPosition = restoredScrollPosition
}
}
public struct EditorInstrumentationSnapshot: Hashable, Sendable {
public var sourceChangeCount: Int
public var selectionChangeCount: Int
public var selectionUpdateCount: Int
public var activeLineChangeCount: Int
public var renderPassCount: Int
public var fullRenderCount: Int
public var totalDirtyLineCount: Int
public var scrollRestorationCount: Int
public var totalRenderDurationMilliseconds: Double
public var lastRenderDurationMilliseconds: Double
public var lastRenderCharacterCount: Int
public var lastRenderLineCount: Int
public var lastDirtyLineCount: Int
public var lastRenderReason: EditorRenderReason?
public init(
sourceChangeCount: Int = 0,
selectionChangeCount: Int = 0,
selectionUpdateCount: Int = 0,
activeLineChangeCount: Int = 0,
renderPassCount: Int = 0,
fullRenderCount: Int = 0,
totalDirtyLineCount: Int = 0,
scrollRestorationCount: Int = 0,
totalRenderDurationMilliseconds: Double = 0,
lastRenderDurationMilliseconds: Double = 0,
lastRenderCharacterCount: Int = 0,
lastRenderLineCount: Int = 0,
lastDirtyLineCount: Int = 0,
lastRenderReason: EditorRenderReason? = nil
) {
self.sourceChangeCount = sourceChangeCount
self.selectionChangeCount = selectionChangeCount
self.selectionUpdateCount = selectionUpdateCount
self.activeLineChangeCount = activeLineChangeCount
self.renderPassCount = renderPassCount
self.fullRenderCount = fullRenderCount
self.totalDirtyLineCount = totalDirtyLineCount
self.scrollRestorationCount = scrollRestorationCount
self.totalRenderDurationMilliseconds = totalRenderDurationMilliseconds
self.lastRenderDurationMilliseconds = lastRenderDurationMilliseconds
self.lastRenderCharacterCount = lastRenderCharacterCount
self.lastRenderLineCount = lastRenderLineCount
self.lastDirtyLineCount = lastDirtyLineCount
self.lastRenderReason = lastRenderReason
}
public var averageRenderDurationMilliseconds: Double {
guard renderPassCount > 0 else { return 0 }
return totalRenderDurationMilliseconds / Double(renderPassCount)
}
public mutating func recordSourceChange() {
sourceChangeCount += 1
}
public mutating func recordSelectionChange() {
selectionChangeCount += 1
selectionUpdateCount += 1
}
public mutating func recordActiveLineChange() {
activeLineChangeCount += 1
}
public mutating func recordRenderPass(_ metric: EditorRenderPassMetric) {
renderPassCount += 1
if metric.isFullRender {
fullRenderCount += 1
}
totalDirtyLineCount += metric.dirtyLineCount
if metric.restoredScrollPosition {
scrollRestorationCount += 1
}
totalRenderDurationMilliseconds += metric.durationMilliseconds
lastRenderDurationMilliseconds = metric.durationMilliseconds
lastRenderCharacterCount = metric.characterCount
lastRenderLineCount = metric.lineCount
lastDirtyLineCount = metric.dirtyLineCount
lastRenderReason = metric.reason
}
}
#if DEBUG
public enum EditorDiagnostics {
public static var isRenderLoggingEnabled = false
public static func logRenderPass(_ metric: EditorRenderPassMetric) {
guard isRenderLoggingEnabled else { return }
print(
"SaplingEditor render reason=\(metric.reason.rawValue) "
+ "full=\(metric.isFullRender) "
+ "dirtyLines=\(metric.dirtyLineCount)/\(metric.lineCount) "
+ "chars=\(metric.characterCount) "
+ "activeLine=\(metric.activeLineIndex) "
+ "durationMs=\(String(format: "%.3f", metric.durationMilliseconds)) "
+ "scrollRestored=\(metric.restoredScrollPosition)"
)
}
}
#endif