Profiling Tests and Browser Tests
测试与浏览器测试性能剖析
CPU profiling for elements package tests using the unified profiling library. Identifies performance bottlenecks, generates optimization recommendations, and detects anti-patterns.
使用统一性能剖析库对elements包中的测试进行CPU性能分析,可识别性能瓶颈、生成优化建议并检测反模式。
Profile Browser Tests (Simple)
浏览器测试性能剖析(简易版)
Built-in profiling for all browser tests
对所有浏览器测试进行内置性能剖析
./scripts/browsertest --profile
./scripts/browsertest --profile
Profile specific test file
剖析指定测试文件
./scripts/browsertest --profile packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
./scripts/browsertest --profile packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
Profile with test pattern
按测试模式进行剖析
./scripts/browsertest --profile -t "batch capture"
./scripts/browsertest --profile -t "batch capture"
Profile Browser Tests (Detailed Analysis)
浏览器测试性能剖析(详细分析版)
Full analysis with unified profiling library
使用统一性能剖析库进行全面分析
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
Get JSON output for LLM analysis
获取JSON输出用于LLM分析
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
--json
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
--json
Focus on specific file
聚焦特定文件
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
--focus renderToImage
--json
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
--focus renderToImage
--json
Profile a scenario in sandbox
剖析沙箱中的场景
./scripts/ef profile EFCanvas basic --json
./scripts/ef profile EFCanvas basic --json
With pattern detection
启用模式检测
./scripts/ef profile EFCanvas basic --json --verbose
./scripts/ef profile EFCanvas basic --json --verbose
Compare against baseline
与基准版本对比
./scripts/ef profile EFCanvas basic
--baseline .profiles/baseline.cpuprofile
--json
./scripts/ef profile EFCanvas basic
--baseline .profiles/baseline.cpuprofile
--json
Performance Investigation Workflow
性能排查流程
When investigating performance issues in tests:
1. Capture Initial Profile
1. 捕获初始性能剖析数据
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
--json > profile.json
npx tsx scripts/profile-browsertest.ts
packages/elements/src/preview/renderTimegroupToCanvas.browsertest.ts
--json > profile.json
./scripts/ef profile EFCanvas basic --json > profile.json
./scripts/ef profile EFCanvas basic --json > profile.json
2. Analyze JSON Output
2. 分析JSON输出
Parse the profile to identify:
json
{
"hotspots": [
{
"rank": 1,
"functionName": "updateFrame",
"file": "EFTimegroup.ts",
"line": 234,
"selfTimeMs": 45.2,
"selfTimePct": 31.1,
"callCount": 234
}
],
"byFile": [
{ "file": "EFTimegroup.ts", "timeMs": 82.1, "timePct": 56.5 }
],
"recommendations": [
"• updateFrame called 234 times - consider caching"
],
"patterns": [
{
"name": "Hot Loop Detected",
"severity": "high",
"suggestion": "Review loop logic..."
}
]
}
解析性能剖析数据以识别:
json
{
"hotspots": [
{
"rank": 1,
"functionName": "updateFrame",
"file": "EFTimegroup.ts",
"line": 234,
"selfTimeMs": 45.2,
"selfTimePct": 31.1,
"callCount": 234
}
],
"byFile": [
{ "file": "EFTimegroup.ts", "timeMs": 82.1, "timePct": 56.5 }
],
"recommendations": [
"• updateFrame被调用234次 - 考虑添加缓存"
],
"patterns": [
{
"name": "检测到热循环",
"severity": "high",
"suggestion": "审查循环逻辑..."
}
]
}
3. Prioritize Optimizations
3. 优先处理优化项
Focus on:
- Functions with (critical bottlenecks)
- Functions with and (caching opportunities)
- Files with (architectural issues)
- Patterns with
重点关注:
- 的函数(关键瓶颈)
- 且的函数(缓存优化机会)
- 的文件(架构层面问题)
- 的模式
Apply optimizations based on patterns detected.
5. Validate with Baseline Comparison
5. 通过基准对比验证优化效果
Save baseline before changes
在修改前保存基准版本
./scripts/ef profile EFCanvas basic
--save .profiles/baseline-$(date +%Y%m%d-%H%M%S).cpuprofile
./scripts/ef profile EFCanvas basic
--save .profiles/baseline-$(date +%Y%m%d-%H%M%S).cpuprofile
After optimization, compare
优化完成后进行对比
./scripts/ef profile EFCanvas basic
--baseline .profiles/baseline-TIMESTAMP.cpuprofile
--json
Check comparison output:
- Negative `selfTimeDiffMs` = improvement ✅
- Positive `selfTimeDiffMs` = regression ⚠️
./scripts/ef profile EFCanvas basic
--baseline .profiles/baseline-TIMESTAMP.cpuprofile
--json
查看对比输出:
- 负的`selfTimeDiffMs` = 性能提升 ✅
- 正的`selfTimeDiffMs` = 性能退化 ⚠️
Understanding Profile Metrics
理解性能剖析指标
| Metric | Meaning | Use For |
|---|
| Time in function itself (excluding callees) | Direct optimization target |
| Percentage of total profile time | Prioritization (>15% = critical) |
| Times function appears in call stacks | Caching/memoization decisions |
| Profile samples that caught function | Loop detection (>200 = tight loop) |
| 指标 | 含义 | 适用场景 |
|---|
| 函数自身执行时间(不包含调用其他函数的时间) | 直接优化目标 |
| 占总剖析时间的百分比 | 优先级判定(>15% = 关键级) |
| 函数在调用栈中出现的次数 | 缓存/记忆化决策依据 |
| 捕获到该函数的剖析样本数 | 循环检测(>200 = 密集循环) |
Interpreting Patterns
模式解读
The unified profiling library detects 8 common anti-patterns:
Excessive DOM Manipulation → Batch DOM updates or use DocumentFragment
Layout Thrashing → Separate layout reads from writes
Hot Loop → Optimize loop body or reduce iterations
Death by a Thousand Cuts → Add memoization for frequently-called functions
Heavy JSON Operations → Use structured cloning or reduce serialization
Frequent Style Computation → Cache computed styles
Animation API Overhead → Cache animation objects
File-Level Concentration → Architectural review needed
统一性能剖析库可检测8种常见反模式:
过度DOM操作 → 批量更新DOM或使用DocumentFragment
布局抖动 → 将布局读取与写入操作分离
热循环 → 优化循环体或减少迭代次数
千刀万剐式性能损耗 → 为频繁调用的函数添加记忆化
重型JSON操作 → 使用结构化克隆或减少序列化操作
频繁样式计算 → 缓存计算后的样式
Animation API开销 → 缓存动画对象
文件级耗时集中 → 需要进行架构审查
Common Optimization Patterns
常见优化模式
High Call Count (>100) + Moderate Time (5-15%)
高调用次数(>100)+ 中等耗时(5-15%)
Problem: Function called frequently with small individual cost
Solution: Memoization or caching
typescript
// Before
function expensiveCalculation(x: number) {
return /* complex math */;
}
// After
const cache = new Map<number, number>();
function expensiveCalculation(x: number) {
if (cache.has(x)) return cache.get(x)!;
const result = /* complex math */;
cache.set(x, result);
return result;
}
问题: 函数调用频繁,单次调用成本较低
解决方案: 添加记忆化或缓存
typescript
// 优化前
function expensiveCalculation(x: number) {
return /* 复杂计算 */;
}
// 优化后
const cache = new Map<number, number>();
function expensiveCalculation(x: number) {
if (cache.has(x)) return cache.get(x)!;
const result = /* 复杂计算 */;
cache.set(x, result);
return result;
}
High Self Time (>30%) + Low Call Count (<10)
高自身耗时(>30%)+ 低调用次数(<10)
Problem: Single function doing too much work
Solution: Reduce complexity or defer work
typescript
// Before
function processAll() {
// All work done synchronously
loadData();
transformData();
validateData();
saveData();
}
// After
function processAll() {
loadData(); // Only critical work
queueMicrotask(() => {
transformData();
validateData();
saveData();
});
}
问题: 单个函数承担过多工作
解决方案: 降低复杂度或延迟非关键工作
typescript
// 优化前
function processAll() {
// 所有工作同步执行
loadData();
transformData();
validateData();
saveData();
}
// 优化后
function processAll() {
loadData(); // 仅执行关键工作
queueMicrotask(() => {
transformData();
validateData();
saveData();
});
}
DOM Manipulation Pattern Detected
检测到DOM操作模式
Problem: Multiple DOM updates causing reflows
Solution: Batch updates
typescript
// Before
for (const item of items) {
container.appendChild(createItem(item)); // Multiple reflows
}
// After
const fragment = document.createDocumentFragment();
for (const item of items) {
fragment.appendChild(createItem(item));
}
container.appendChild(fragment); // Single reflow
问题: 多次DOM更新导致重排
解决方案: 批量更新
typescript
// 优化前
for (const item of items) {
container.appendChild(createItem(item)); // 多次重排
}
// 优化后
const fragment = document.createDocumentFragment();
for (const item of items) {
fragment.appendChild(createItem(item));
}
container.appendChild(fragment); // 单次重排
Text Output (Human-Readable)
文本输出(易读版)
bash
./scripts/ef profile EFCanvas basic
Shows:
- Top hotspots by self time
- Time aggregated by file
- Automated recommendations
- Detected patterns (with --verbose)
bash
./scripts/ef profile EFCanvas basic
展示内容:
- 按自身耗时排序的顶级性能热点
- 按文件聚合的耗时统计
- 自动化优化建议
- 检测到的模式(启用--verbose时)
JSON Output (LLM/Script-Friendly)
JSON输出(适用于LLM/脚本分析)
bash
./scripts/ef profile EFCanvas basic --json
Structured data for programmatic analysis:
- Ranked hotspots with metrics
- File-level aggregations
- Recommendations array
- Pattern detection results
bash
./scripts/ef profile EFCanvas basic --json
用于程序化分析的结构化数据:
- 带指标的排序后性能热点
- 文件级聚合数据
- 优化建议数组
- 模式检测结果
Verbose Mode (Enhanced Analysis)
详细模式(增强分析)
bash
./scripts/ef profile EFCanvas basic --json --verbose
Adds:
- Call count information
- Anti-pattern detection
- Detailed suggestions
bash
./scripts/ef profile EFCanvas basic --json --verbose
新增内容:
Specialized Profiling Tools
专用性能剖析工具
Profile Playback Performance
剖析回放性能
bash
npx tsx scripts/profile-playback.ts \
--project improv-edit \
--duration 5000 \
--json
bash
npx tsx scripts/profile-playback.ts \
--project improv-edit \
--duration 5000 \
--json
Profile Export Performance
剖析导出性能
bash
npx tsx scripts/profile-export.ts \
--project design-catalog \
--json
bash
npx tsx scripts/profile-export.ts \
--project design-catalog \
--json
Profile Page Load
剖析页面加载性能
bash
npx tsx scripts/profile-load.ts \
--project improv-edit \
--json
bash
npx tsx scripts/profile-load.ts \
--project improv-edit \
--json
"Profiling functions not available"
- Ensure browser is controlled by Playwright (use , not regular browser)
"Profile data is empty"
- Scenario/test may execute too quickly (<10ms)
- Try longer-running tests or increase test complexity
"High numbers don't make sense"
- Check if times are in microseconds vs milliseconds
- Unified library returns milliseconds
- Legacy interfaces may use microseconds
"Call counts seem wrong"
- Call count is approximate based on call stack traversal
- Use for sampling-based frequency instead
"性能剖析功能不可用"
- 确保浏览器由Playwright控制(使用,而非普通浏览器)
"性能剖析数据为空"
- 场景/测试可能执行过快(<10ms)
- 尝试运行耗时更长的测试或增加测试复杂度
"数值异常无意义"
- 检查时间单位是微秒还是毫秒
- 统一库返回的是毫秒
- 旧接口可能使用微秒
"调用次数统计异常"
- 调用次数是基于调用栈遍历的近似值
- 如需基于采样的频率统计,请使用
- Always save baselines before making changes
- Focus on self time for direct impact (total time includes callees)
- Start with top 3 hotspots for biggest impact
- Use JSON output for programmatic analysis
- Check patterns before manual analysis - they suggest specific fixes
- Validate changes by comparing before/after profiles
- Watch for regressions in baseline comparisons
- 修改前务必保存基准版本
- 聚焦自身耗时以获得直接优化效果(总耗时包含调用其他函数的时间)
- 从Top3性能热点入手以获得最大优化收益
- 使用JSON输出进行程序化分析
- 先查看模式检测结果再进行手动分析——模式会给出具体修复方向
- 通过前后对比验证优化效果
- 在基准对比中关注性能退化情况
- Full profiling guide:
- LLM-specific guide:
elements/LLM_PROFILING_GUIDE.md
- Implementation details:
elements/PROFILING_IMPLEMENTATION_SUMMARY.md
- Library source:
packages/elements/src/profiling/
- 完整性能剖析指南:
- LLM专用指南:
elements/LLM_PROFILING_GUIDE.md
- 实现细节:
elements/PROFILING_IMPLEMENTATION_SUMMARY.md
- 库源码:
packages/elements/src/profiling/