mcpField
S
swift-runtime-performance

swift-runtime-performance

github.com/livsy90开发119114 次安装15 周前更新
代码仓库

关于 swift-runtime-performance

swift-runtime-performance 是用于审查 Swift 运行时开销的 Agent 技能,涵盖分配、ARC、派发、复制和特化。它引导开发者依据测量采取针对性改动,并考虑语义与维护代价。

主要功能

  1. 01分类运行时开销
  2. 02确认代码是否处于热点路径
  3. 03依据性能分析与编译器证据
  4. 04提出针对性的运行时改动
  5. 05说明实现权衡

适用场景

  1. 01审查分配或 ARC 开销
  2. 02调查派发或泛型特化
  3. 03评估写时复制成本
  4. 04检查 Swift 不安全边界

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/livsy90/ios-performance-agent-skills --skill swift-runtime-performance

安装后在 Claude Code 中输入/swift-runtime-performance确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
references/
allocation-and-layout.md
arc-and-ownership.md
concurrency-runtime.md
cow-and-large-values.md
dispatch-and-specialization.md
existentials-generics-opaque-types.md
modularization-and-linking.md
sil-inspection.md
unsafe-swift.md

详细介绍

Swift 运行时性能

用途

使用此技能审查 Swift 代码的运行时性能开销,不要把每个抽象都视为问题。重点关注具体开销,例如内存分配、ARC 流量、派发、特化、复制、优化器可见性和不安全内存边界。

此技能旨在帮助 Agent 区分真正的热路径运行时开销与理论上的微优化。

何时使用此技能

当任务涉及 Swift 运行时行为时,请使用此技能,例如:

  • 堆分配、栈与堆存储、对象布局、装箱值或闭包上下文;
  • ARC 保留/释放流量、所有权、生命周期、弱引用/无主引用或闭包捕获;
  • 热路径中的直接派发、类派发、Objective-C 派发、协议见证派发或动态派发;
  • any Protocol、some Protocol、泛型、类型擦除、特化或未特化的热代码;
  • 写时复制集合、大型值、自定义 COW 存储或重复复制;
  • 优化后的 SIL 检查、编译器优化、内联、去虚拟化或特化方面的证据;
  • 不安全 Swift、指针生命周期、内存绑定、别名、缓冲区变更,或不安全区域周围的安全封装;
  • 影响优化器可见性的模块边界、@inlinable、@usableFromInline、@frozen 或公共 API 弹性方面的权衡。

何时不使用此技能

以下情况请勿使用此技能:

  • 不涉及运行时性能问题的一般 Swift 语法或 API 用法问题;
  • App 启动调查,主要问题是 pre-main、dyld、静态初始化器、SDK 启动、首帧或首次交互;
  • SwiftUI 性能问题,主要问题是身份、失效、状态范围、布局、绘制、动画或滚动;
  • Swift Concurrency 问题,主要问题是任务生命周期、Actor 隔离、MainActor 响应能力、取消、AsyncSequence 清理、重入或执行器行为;
  • 性能分析工作流问题,主要任务是选择工具、解读跟踪记录、设计 signpost、XCTest 度量、MetricKit 或生产环境信号;
  • 广泛的架构问题,除非热路径中存在具体的运行时开销。

如果有更具体的技能,请优先转到该技能,仅在处理运行时子问题时使用此技能。

相邻技能的适用范围

应用运行时建议前,请遵循以下界限:

  • 如果任务围绕 Actor、任务、MainActor、取消、AsyncSequence、continuation、任务组、执行器行为或异步工作下的响应能力,请使用 swift-concurrency-performance。
  • 如果任务围绕冷启动、热启动、pre-main、dyld、框架加载、静态初始化器、AppDelegate、SwiftUI App、首帧、首次交互或启动指标,请使用 ios-launch-performance。
  • 如果任务围绕 SwiftUI body 求值、失效、身份、状态所有权、依赖范围、List、LazyVStack、布局、绘制、动画或视图生命周期工作,请使用 swiftui-performance。
  • 如果任务围绕选择 Instruments 模板、解读跟踪记录、XCTest 度量、MetricKit、signpost、内存图、卡顿、顿挫、CPU、分配、磁盘 I/O、网络或生产遥测,请使用 ios-performance-profiling。
  • 如果相邻领域的任务发现了 Swift 运行时级别的开销,例如分配频繁、ARC 流量、存在类型装箱、协议见证派发、未特化泛型、重复 COW 复制或不安全内存边界,请使用此技能。

核心原则

不要仅根据源代码的表面形式进行优化。

首先确定:

  1. 代码是否位于热路径;
  2. 怀疑存在何种运行时开销;
  3. 能否通过测量、编译器输出或小型基准测试观察到该开销;
  4. 建议的改动是否保留语义并改善测量所涉及的路径;
  5. 该改动会带来何种权衡。

只有当运行时优化能降低重要路径上的开销时,它才有价值。

运行时开销分类

在建议改动前,先对疑似问题进行分类。

使用以下类别:

  • 分配 — 堆对象、装箱、闭包上下文、存在类型容器、临时对象、中间集合。
  • ARC — retain/release 开销、闭包捕获、weak/unowned 访问、桥接对象生命周期、由引用支持的值存储。
  • 分派 — 动态分派、见证表分派、Objective-C 分派、闭包调用、未能去虚拟化。
  • 存在类型与泛型 — any、some、类型擦除、泛型特化、未特化的热点路径、装箱。
  • 复制 — COW 存储、大型值、重复修改集合、防御性复制、桥接复制。
  • 编译器优化 — 内联、特化、去虚拟化、模块可见性、弹性边界、优化后的 SIL 输出。
  • 不安全边界 — 指针生命周期、绑定、对齐、别名、修改、逃逸缓冲区、安全封装。
  • 模块边界 — 公共 API 可见性、@inlinable、@usableFromInline、@frozen、ABI 弹性、优化器可见性。

核心工作流程

  1. 定位用户可见的症状。 确定问题涉及延迟、滚动、重复工作、内存增长、CPU 使用、二进制大小、启动影响,还是理论上的代码审查风险。
  2. 确认热点路径。 询问代码是否频繁运行、是否处理大量元素、是否阻塞交互、是否在启动期间运行,或是否出现在测量结果中。
  3. 对疑似开销进行分类。 使用运行时开销分类,而不是笼统地说代码“很慢”。
  4. 寻找证据。 优先使用 Instruments、Allocations、Time Profiler、优化后的 SIL、基准测试输出、XCTest 性能测试或生产环境信号。
  5. 区分语义与机制。 不要仅因抽象可能产生开销就移除它。先确认它所服务的设计目的。
  6. 提出最小且安全的改动。 优先采用局部改动,以减少分配、ARC 开销、分派、复制或未能特化,同时不损害 API 的清晰度。
  7. 说明权衡。 提及可读性、API 灵活性、可测试性、二进制大小、ABI 稳定性、构建时间或维护成本。
  8. 验证结果。 没有前后对比的验证方案,就不要宣称优化成功。

决策规则

如果代码不在热点路径上

避免低层重写。

说明这个顾虑在理论上可能成立,但没有证据时不太可能造成实际影响。只有怀疑该路径会影响用户可见的性能时,才建议进行测量。

如果问题涉及分配

检查分配是否来自:

  • 类实例;
  • 闭包上下文;
  • 装箱变量;
  • 存在类型存储;
  • 类型擦除包装器;
  • 中间数组、字典、集合、字符串或数据缓冲区;
  • Swift 与 Objective-C/Foundation 类型之间的桥接。

优先减少重复分配,而不是替换所有引用类型。

如果问题涉及 ARC

建议改动前,先检查所有权和生命周期。

留意循环中的重复 retain/release 开销、闭包捕获的大型所有者、热点路径中不必要的 weak 访问,以及由引用支持的值存储。不要把 weak 和 unowned 当作性能优化手段。它们首先是所有权工具。

如果问题涉及分派

确认动态分派是否有意为之。

对于不面向继承设计的应用级类,优先使用 final。仅当泛型、具体类型或内部实现细节既能保留预期抽象,又对测量到的路径有帮助时,才考虑使用它们。

没有证据时,不要扁平化有用的多态结构。

如果问题涉及 any Protocol

确认是否需要运行时异构性。

any Protocol 并非天然有问题。当必须统一存储或传递不同具体类型的值时,它是合适的。如果热点路径可以保持静态类型,则可考虑使用泛型或不透明类型。

如果问题出在泛型上

检查是否确实发生了特化。

当优化器能看到足够的实现细节来特化热路径时,泛型最能发挥作用。模块边界、公开 API 的稳定性要求、函数过大或类型擦除都可能对此造成限制。

如果问题出在写时复制上

检查变更模式和唯一性边界。

当存储被唯一引用时,反复变更 COW 值的成本可能很低;若反复复制,成本则可能很高。自定义 COW 必须保留值语义,并说明线程安全方面的假设。

如果问题出在 SIL 或编译器输出上

得出性能结论时,应使用优化后的 SIL,而非 Debug SIL。

留意分配指令、retain/release 流量、witness 调度、existential 打开、闭包创建、未能完成的特化,以及未能完成的去虚拟化等证据。应将 SIL 视为证据,而不是过度贴合某个编译器版本来改写源代码的借口。

如果问题出在不安全 Swift 上

不要把不安全代码作为首选方案。

只有当安全 API 无法足够高效地表达该操作、测量结果表明抽象带来的成本确实重要,并且能将不安全代码区域限制在安全封装内时,才使用不安全 API。

如果问题出在模块边界上

将运行时优化与架构和构建时问题分开处理。

只有在 API 承诺可以接受时,才使用 @inlinable、@usableFromInline 和 @frozen。这些属性不是通用的“让它更快”开关。

常见注意事项

  • struct 不保证在栈上分配。
  • class 不一定意味着存在性能问题。
  • 值语义仍可能涉及堆存储和 ARC。
  • Array、String、Dictionary、Set 和 Data 可能隐藏由引用支持的存储。
  • any Protocol 是一种有用的抽象,虽然会带来运行时成本,但并非错误。
  • some Protocol 并不能普遍替代 any Protocol。
  • 只有在发生特化时,泛型才能发挥最大作用。
  • 对于未设计为支持继承的应用级类,final 是不错的默认选择,但不应将其吹捧为独立的性能修复方案。
  • @inline(__always) 可能增大代码体积,不应作为首选修复方法。
  • @inlinable 是对 API 和 ABI 的承诺。
  • weak 和 unowned 是所有权工具,不是性能工具。
  • Debug 构建中的行为并不能可靠反映优化后的运行时性能。
  • 随意使用不安全代码可能会让代码变慢、降低优化效果,甚至导致错误。
  • 除非测量结果证明低级代码确有必要,否则不要用它取代易读的架构。

参考资料路由

有选择地阅读参考资料。默认不要加载所有参考文件。

  • references/allocation-and-layout.md — 当任务涉及栈与堆行为、对象布局、闭包盒、存在类型存储、临时分配,或值类型中的隐藏堆存储时阅读。
  • references/arc-and-ownership.md — 当任务涉及保留/释放开销、闭包捕获、弱/无主引用、对象生命周期、引用循环、COW 所有权或桥接生命周期时阅读。
  • references/dispatch-and-specialization.md — 当任务涉及直接派发、类派发、Objective-C 派发、见证表派发、闭包派发、去虚拟化、内联或泛型特化时阅读。
  • references/existentials-generics-opaque-types.md — 当任务涉及 any Protocol、some Protocol、泛型、类型擦除、协议见证表派发、不透明结果类型,或替换存在类型密集的热点路径时阅读。
  • references/cow-and-large-values.md — 当任务涉及写时复制集合、大型结构体、反复修改集合、自定义 COW 存储、唯一性检查或值语义 API 设计时阅读。
  • references/sil-inspection.md — 当仅靠源码层面的推理不够,且任务需要优化后的 SIL 证据来分析分配、ARC、派发、存在类型打开、闭包创建、特化或内联时阅读。
  • references/unsafe-swift.md — 当任务涉及不安全指针、缓冲区访问、内存绑定、对齐、别名、手动生命周期、不安全封装,或用不安全代码替代安全 API 时阅读。
  • references/modularization-and-linking.md — 当任务涉及模块边界上的优化器可见性、公共 API 弹性、@inlinable、@usableFromInline、@frozen、静态与动态库,或模块化带来的运行时权衡时阅读。
  • references/concurrency-runtime.md — 仅当并发相关问题具体涉及 Swift 运行时开销(例如分配、ARC、闭包捕获、SIL 降低或执行器相关开销)时阅读。对于 Actor 设计、MainActor 响应能力、取消、AsyncSequence 清理、延续,或结构化并发工作流,请改用 swift-concurrency-performance。

证据与验证

根据疑似开销选择合适的证据:

  • 当关注对象频繁创建和销毁、盒、闭包上下文、存在类型存储或临时集合时,使用 Allocations。
  • 当关注 CPU 开销、派发开销、复制、桥接或热点函数调用时,使用 Time Profiler。
  • 当关注编译器优化、特化、去虚拟化、ARC 插入、存在类型打开、闭包分配或内联时,使用优化后的 SIL。
  • 当需要隔离紧密循环、集合操作、派发模式,或泛型与存在类型的差异时,使用小型基准测试。
  • 当操作能够确定性地复现时,使用 XCTest 性能测试。
  • 当性能声明影响真实用户路径时,使用前后对比追踪。

除非任务专门讨论仅在 Debug 构建中出现的开发性能,否则不要使用 Debug 构建进行验证。

输出要求

审查代码时,请按以下结构回复:

  1. 总结 — 说明相关问题很可能存在、仅是理论上的,还是无法根据所提供的代码判断。
  2. 疑似运行时开销 — 将问题归类为分配、ARC、派发、存在类型/泛型、复制、编译器优化、不安全边界或模块边界开销。
  3. 热路径评估 — 说明这段代码是否可能影响用户可感知的性能。
  4. 待检查的证据 — 指明可以验证该假设的测量结果、SIL 输出、基准测试或跟踪记录。
  5. 发现 — 说明具体的源代码模式及其可能产生运行时工作的原因。
  6. 建议的更改 — 提出最小且安全的更改。仅在有助于说明建议时提供代码。
  7. 权衡 — 提及可读性、抽象、API 灵活性、二进制大小、ABI 稳定性、构建时间或可维护性。
  8. 验证 — 说明如何通过更改前后的证据确认结果。

回复风格

精准、克制。

建议使用:

  • “这可能会发生分配,因为闭包逃逸了,并捕获了 self。”
  • “这个存在类型可能没有问题,除非此循环属于热路径,或 Instruments 中出现了分配。”
  • “使用优化后的 SIL 检查泛型函数是否跨此模块边界进行了特化。”
  • “如果情况集合是封闭的,并且测量表明此路径属于热路径,那么具体枚举可能会有所帮助。”

避免使用:

  • “结构体总是更快。”
  • “类很慢。”
  • “协议不利于性能。”
  • “总是用泛型替换 any。”
  • “用不安全指针来提速。”
  • “添加 @inline(__always)。”
  • “为了性能,把所有内容都标记为 final。”

正向触发示例

遇到以下提示时,应触发此技能:

  • “请审查这个 Swift 热路径中的 ARC 和分配开销。”
  • “这个信息流存储了 any FeedItem 值,这会产生运行时开销吗?”
  • “这种以协议为主的代码是否应该改用泛型?”
  • “这个自定义 COW 类型会不会意外地复制过多内容?”
  • “你能检查这份优化后的 SIL,并解释其中的保留和分配吗?”
  • “这个跨模块使用的小型泛型函数,使用 @inlinable 是否合理?”
  • “这个大量使用闭包的解析器分配很多,我应该检查什么?”
  • “这种不安全缓冲区优化是否合理?”

负向触发示例

遇到以下提示时,不应触发此技能:

  • “我的 SwiftUI 列表在行更新时会卡顿。”
  • “应用在冷启动后,显示首屏的时间太长。”
  • “我应该如何在这个任务组中处理取消?”
  • “我应该使用哪个 Instruments 模板来诊断卡顿?”
  • “如何创建 Swift 协议?”
  • “如何让这个 SwiftUI 界面更好看?”
  • “我是否应该将此 SDK 初始化移出 AppDelegate?”

将这些任务交给更具体的技能处理,除非用户明确询问 Swift 运行时级别的开销。

评论

支持 Markdown