一键导入
build-performance
Analyze and optimize Xcode build times by identifying slow compilation units and suggesting improvements
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Analyze and optimize Xcode build times by identifying slow compilation units and suggesting improvements
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Generate comprehensive API documentation using DocC (Swift-DocC) for your PaleoRose project
Analyze and optimize Xcode asset catalogs - find unused assets, missing resolutions, compress images
Generate CI/CD configurations and automation scripts for building, testing, and deploying
Calculate code quality metrics - complexity, coverage, maintainability
Parse and analyze macOS crash logs to identify crash causes and debugging information
Parse and validate XIB/Storyboard files for broken outlets, warnings, accessibility
| description | Analyze and optimize Xcode build times by identifying slow compilation units and suggesting improvements |
Analyze and optimize Xcode build times by identifying slow compilation units and suggesting improvements.
Build Time Analysis
Compilation Bottleneck Detection
Optimization Suggestions
Dependency Optimization
Reporting
When invoked, this skill will:
When the user invokes this skill:
Ask analysis scope:
Choose detail level:
Run analysis
Generate report with recommendations
Apply suggested fixes
# Add to Xcode build settings or .xcconfig file
OTHER_SWIFT_FLAGS = -Xfrontend -debug-time-function-bodies -Xfrontend -debug-time-compilation
# For detailed type checking times
OTHER_SWIFT_FLAGS = -Xfrontend -warn-long-function-bodies=100 -Xfrontend -warn-long-expression-type-checking=100
#!/bin/bash
# measure-build-time.sh
# Clean build with timing
xcodebuild clean build \
-project PaleoRose.xcodeproj \
-scheme PaleoRose \
-configuration Debug \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" \
| tee build-log.txt
# Extract timing information
grep "warning.*took" build-log.txt | \
sed 's/.*warning: //' | \
sort -t' ' -k3 -n -r | \
head -20
#!/usr/bin/swift
import Foundation
struct BuildTimeParser {
struct CompilationTime {
let file: String
let duration: Double
let warnings: [String]
}
struct FunctionTime {
let function: String
let file: String
let line: Int
let duration: Double
}
func parseXcodeBuildLog(_ logPath: String) -> [CompilationTime] {
guard let content = try? String(contentsOfFile: logPath) else {
return []
}
var times: [CompilationTime] = []
// Parse compilation times
let pattern = #"CompileSwift.*?(\S+\.swift).*?(\d+\.\d+) seconds"#
let regex = try! NSRegularExpression(pattern: pattern)
let matches = regex.matches(
in: content,
range: NSRange(content.startIndex..., in: content)
)
for match in matches {
if let fileRange = Range(match.range(at: 1), in: content),
let timeRange = Range(match.range(at: 2), in: content) {
let file = String(content[fileRange])
let duration = Double(String(content[timeRange])) ?? 0
times.append(CompilationTime(
file: file,
duration: duration,
warnings: []
))
}
}
return times.sorted { $0.duration > $1.duration }
}
func parseFunctionTimes(_ logPath: String) -> [FunctionTime] {
guard let content = try? String(contentsOfFile: logPath) else {
return []
}
var times: [FunctionTime] = []
// Parse function body compilation warnings
let pattern = #"(\S+\.swift):(\d+):\d+: warning: .*'(.+?)' took (\d+)ms"#
let regex = try! NSRegularExpression(pattern: pattern)
let matches = regex.matches(
in: content,
range: NSRange(content.startIndex..., in: content)
)
for match in matches {
if let fileRange = Range(match.range(at: 1), in: content),
let lineRange = Range(match.range(at: 2), in: content),
let funcRange = Range(match.range(at: 3), in: content),
let timeRange = Range(match.range(at: 4), in: content) {
times.append(FunctionTime(
function: String(content[funcRange]),
file: String(content[fileRange]),
line: Int(String(content[lineRange])) ?? 0,
duration: Double(String(content[timeRange])) ?? 0
))
}
}
return times.sorted { $0.duration > $1.duration }
}
func generateReport(
files: [CompilationTime],
functions: [FunctionTime]
) -> String {
var report = "# Build Time Analysis Report\n\n"
// File compilation times
report += "## Slowest Files to Compile\n\n"
for (index, file) in files.prefix(20).enumerated() {
report += "\(index + 1). \(file.file): \(file.duration)s\n"
}
// Function compilation times
report += "\n## Slowest Functions to Type-Check\n\n"
for (index, func) in functions.prefix(20).enumerated() {
report += "\(index + 1). \(func.function) (\(func.file):\(func.line)): \(func.duration)ms\n"
}
// Summary stats
let totalTime = files.reduce(0) { $0 + $1.duration }
let avgTime = totalTime / Double(files.count)
report += "\n## Summary\n\n"
report += "- Total files: \(files.count)\n"
report += "- Total compilation time: \(totalTime)s\n"
report += "- Average per file: \(String(format: "%.2f", avgTime))s\n"
report += "- Slowest file: \(files.first?.file ?? "N/A") (\(files.first?.duration ?? 0)s)\n"
return report
}
}
// Usage
let parser = BuildTimeParser()
let files = parser.parseXcodeBuildLog("build-log.txt")
let functions = parser.parseFunctionTimes("build-log.txt")
let report = parser.generateReport(files: files, functions: functions)
print(report)
// Save report
try? report.write(toFile: "build-time-report.md", atomically: true, encoding: .utf8)
// Before: Slow type inference
let graphics = layers
.filter { $0.isVisible }
.flatMap { layer in
(0..<binCount).map { bin in
createGraphic(layer, bin) // Complex inference
}
}
// After: Explicit types help compiler
let graphics: [Graphic] = layers
.filter { $0.isVisible }
.flatMap { (layer: Layer) -> [Graphic] in
(0..<binCount).map { (bin: Int) -> Graphic in
createGraphic(layer, bin)
}
}
// Before: Single complex expression (slow to type-check)
let result = data
.filter { $0.value > threshold && $0.isValid }
.map { calculateComplexValue($0) }
.reduce(initialValue) { acc, val in
acc + val * multiplier - offset
}
// After: Split into steps
let filtered = data.filter { $0.value > threshold && $0.isValid }
let mapped = filtered.map(calculateComplexValue)
let result = mapped.reduce(initialValue) { acc, val in
acc + val * multiplier - offset
}
// Before: Complex generic constraints
func process<T: Codable & Hashable & CustomStringConvertible>(
items: [T]
) where T: Comparable {
// ...
}
// After: Create protocol composition
protocol ProcessableItem: Codable, Hashable, CustomStringConvertible, Comparable {}
func process<T: ProcessableItem>(items: [T]) {
// Faster to compile
}
// Before: Generic internal function (slower)
private func formatValue<T: CustomStringConvertible>(_ value: T) -> String {
return "Value: \(value.description)"
}
// After: Concrete type for internal use
private func formatValue(_ value: String) -> String {
return "Value: \(value)"
}
// Before: Unnecessary @objc (bridges to Obj-C runtime)
class GraphicPetal: Graphic {
@objc var lineWidth: Float = 1.0
@objc func calculateGeometry() { }
}
// After: Remove if not needed by Obj-C
class GraphicPetal: Graphic {
var lineWidth: Float = 1.0
func calculateGeometry() { }
}
// Before: Many small protocol conformances
extension GraphicPetal: CustomStringConvertible { }
extension GraphicPetal: CustomDebugStringConvertible { }
extension GraphicPetal: Equatable { }
extension GraphicPetal: Hashable { }
// After: Consolidate in main declaration
class GraphicPetal: Graphic,
CustomStringConvertible,
CustomDebugStringConvertible,
Equatable,
Hashable {
// All conformances in one place - faster compilation
}
// Before: Everything in one target
// PaleoRose target contains:
// - Graphics (100 files)
// - Database (50 files)
// - UI (80 files)
// Total: 230 files rebuild on any change
// After: Separate frameworks
// PaleoRoseGraphics.framework (100 files)
// PaleoRoseDatabase.framework (50 files)
// PaleoRose app (80 files + frameworks)
// Only changed framework rebuilds
# .xcconfig or Build Settings
# Parallel compilation
SWIFT_COMPILATION_MODE = wholemodule # For release
# OR
SWIFT_COMPILATION_MODE = incremental # For debug (faster incremental)
# Optimization level
SWIFT_OPTIMIZATION_LEVEL = -O # Release
SWIFT_OPTIMIZATION_LEVEL = -Onone # Debug (faster compile)
# Module linking
SWIFT_WHOLE_MODULE_OPTIMIZATION = YES # Release
SWIFT_WHOLE_MODULE_OPTIMIZATION = NO # Debug
# Parallel build
SWIFT_PARALLEL_COMPILATION = YES
# Index while building
COMPILER_INDEX_STORE_ENABLE = NO # Faster build, no indexing
# Debug info
DEBUG_INFORMATION_FORMAT = dwarf # Faster than dwarf-with-dsym for debug
# PaleoRose.xcconfig
# Increase build performance
SWIFT_PARALLEL_COMPILATION = YES
SWIFT_COMPILATION_MODE = incremental
# Only for debug builds
SWIFT_ACTIVE_COMPILATION_CONDITIONS[config=Debug] = DEBUG
SWIFT_OPTIMIZATION_LEVEL[config=Debug] = -Onone
# Optimize release builds
SWIFT_OPTIMIZATION_LEVEL[config=Release] = -O
SWIFT_COMPILATION_MODE[config=Release] = wholemodule
#!/usr/bin/swift
import Foundation
struct BuildTimeTracker {
let projectPath: String
func track() {
print("🔨 Building project...")
let startTime = Date()
// Run build
let result = shell(
"""
cd \(projectPath) && \
xcodebuild clean build \
-project PaleoRose.xcodeproj \
-scheme PaleoRose \
-configuration Debug \
OTHER_SWIFT_FLAGS="-Xfrontend -debug-time-function-bodies" \
| tee build.log
"""
)
let duration = Date().timeIntervalSince(startTime)
print("✅ Build completed in \(duration)s")
// Parse and analyze
analyzeBuildLog()
}
func analyzeBuildLog() {
let parser = BuildTimeParser()
let files = parser.parseXcodeBuildLog("build.log")
// Save historical data
saveHistoricalData(files)
// Generate report
generateReport(files)
}
func saveHistoricalData(_ files: [BuildTimeParser.CompilationTime]) {
let data = BuildTimeData(
date: Date(),
totalDuration: files.reduce(0) { $0 + $1.duration },
fileCount: files.count,
slowestFiles: Array(files.prefix(10))
)
// Append to historical log
// (JSON or SQLite database)
}
func generateReport(_ files: [BuildTimeParser.CompilationTime]) {
print("\n📊 Build Time Report\n")
print("Top 10 Slowest Files:")
for (index, file) in files.prefix(10).enumerated() {
let fileName = URL(fileURLWithPath: file.file).lastPathComponent
print("\(index + 1). \(fileName): \(file.duration)s")
}
// Check for regressions
checkRegressions(files)
}
func checkRegressions(_ files: [BuildTimeParser.CompilationTime]) {
// Compare against historical baseline
// Alert if any file >20% slower than average
}
private func shell(_ command: String) -> String {
let task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", command]
let pipe = Pipe()
task.standardOutput = pipe
task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile()
return String(data: data, encoding: .utf8) ?? ""
}
}
struct BuildTimeData: Codable {
let date: Date
let totalDuration: Double
let fileCount: Int
let slowestFiles: [BuildTimeParser.CompilationTime]
}
# .github/workflows/build-performance.yml
name: Build Performance
on:
pull_request:
push:
branches: [main]
jobs:
measure-build-time:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Measure Build Time
run: |
swift run BuildTimeTracker --project .
- name: Upload Report
uses: actions/upload-artifact@v3
with:
name: build-time-report
path: build-time-report.md
- name: Comment PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
script: |
const fs = require('fs');
const report = fs.readFileSync('build-time-report.md', 'utf8');
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '## Build Time Report\n\n' + report
});
<!DOCTYPE html>
<html>
<head>
<title>Build Time Trends</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
<canvas id="buildTimeChart"></canvas>
<script>
const ctx = document.getElementById('buildTimeChart');
new Chart(ctx, {
type: 'line',
data: {
labels: ['Week 1', 'Week 2', 'Week 3', 'Week 4'],
datasets: [{
label: 'Build Time (seconds)',
data: [120, 115, 108, 95],
borderColor: 'rgb(75, 192, 192)',
tension: 0.1
}]
},
options: {
scales: {
y: {
beginAtZero: true
}
}
}
});
</script>
</body>
</html>
Store optimization settings in .build-optimizer.json:
{
"trackHistory": true,
"historyPath": "./BuildMetrics/history.json",
"thresholds": {
"fileCompilationWarning": 5.0,
"functionTypeCheckWarning": 100
},
"xcodeBuildSettings": {
"debug": {
"SWIFT_COMPILATION_MODE": "incremental",
"SWIFT_OPTIMIZATION_LEVEL": "-Onone"
},
"release": {
"SWIFT_COMPILATION_MODE": "wholemodule",
"SWIFT_OPTIMIZATION_LEVEL": "-O"
}
}
}