import Foundation // MARK: - 性能采样数据模型 /// 单个章节的性能采样数据,记录渲染和分页的耗时。 public struct RDEPUBTextPerformanceSample: Equatable { /// 章节文件路径 public var chapterHref: String /// HTML 渲染耗时(秒) public var renderDuration: TimeInterval /// CoreText 分页耗时(秒) public var paginateDuration: TimeInterval /// 分页后的页数 public var pageCount: Int /// 富文本字符长度 public var attributedStringLength: Int /// 是否命中分页缓存 public var cacheHit: Bool public init( chapterHref: String, renderDuration: TimeInterval, paginateDuration: TimeInterval, pageCount: Int, attributedStringLength: Int, cacheHit: Bool ) { self.chapterHref = chapterHref self.renderDuration = renderDuration self.paginateDuration = paginateDuration self.pageCount = pageCount self.attributedStringLength = attributedStringLength self.cacheHit = cacheHit } } // MARK: - 性能采样器 /// 书籍构建过程的性能采样器,用于监控每章的渲染和分页耗时。 /// /// 由 `RDEPUBTextBookBuilder` 在构建过程中使用,每章记录一个采样点, /// 构建完成后输出汇总报告。 public final class RDEPUBTextPerformanceSampler { /// 所有章节的采样数据列表 public private(set) var samples: [RDEPUBTextPerformanceSample] = [] /// 整本书构建的总耗时(秒) public var totalBuildDuration: TimeInterval = 0 public init() {} /// 记录单个章节的性能采样,并输出日志 public func record(_ sample: RDEPUBTextPerformanceSample) { samples.append(sample) print("[PERF] \(sample.chapterHref): render=\(formatMS(sample.renderDuration)) paginate=\(formatMS(sample.paginateDuration)) pages=\(sample.pageCount) cache=\(sample.cacheHit ? "HIT" : "MISS")") } /// 生成性能汇总报告,包含总渲染/分页耗时和缓存命中率 public func summary() -> String { let totalRender = samples.reduce(0) { $0 + $1.renderDuration } let totalPaginate = samples.reduce(0) { $0 + $1.paginateDuration } let hitCount = samples.filter(\.cacheHit).count return "[PERF] chapters=\(samples.count) render=\(formatMS(totalRender)) paginate=\(formatMS(totalPaginate)) total=\(formatMS(totalBuildDuration)) cacheHits=\(hitCount)/\(samples.count)" } /// 重置所有采样数据 public func reset() { samples.removeAll() totalBuildDuration = 0 } /// 将秒转换为毫秒格式字符串 private func formatMS(_ duration: TimeInterval) -> String { String(format: "%.0fms", duration * 1000) } }