@gracker/smartperfetto 1.0.15 → 1.0.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (189) hide show
  1. package/dist/agent/agents/base/baseAgent.d.ts.map +1 -1
  2. package/dist/agent/agents/base/baseAgent.js +5 -1
  3. package/dist/agent/agents/base/baseAgent.js.map +1 -1
  4. package/dist/agent/context/enhancedSessionContext.d.ts +5 -0
  5. package/dist/agent/context/enhancedSessionContext.d.ts.map +1 -1
  6. package/dist/agent/context/enhancedSessionContext.js +13 -0
  7. package/dist/agent/context/enhancedSessionContext.js.map +1 -1
  8. package/dist/agent/core/conclusionContract.d.ts +23 -1
  9. package/dist/agent/core/conclusionContract.d.ts.map +1 -1
  10. package/dist/agent/core/conclusionGenerator.d.ts.map +1 -1
  11. package/dist/agent/core/conclusionGenerator.js +223 -27
  12. package/dist/agent/core/conclusionGenerator.js.map +1 -1
  13. package/dist/agent/core/executors/directSkillExecutor.d.ts.map +1 -1
  14. package/dist/agent/core/executors/directSkillExecutor.js +6 -12
  15. package/dist/agent/core/executors/directSkillExecutor.js.map +1 -1
  16. package/dist/agent/core/orchestratorTypes.d.ts +6 -0
  17. package/dist/agent/core/orchestratorTypes.d.ts.map +1 -1
  18. package/dist/agent/core/orchestratorTypes.js.map +1 -1
  19. package/dist/agent/experts/crossDomain/moduleExpertInvoker.d.ts.map +1 -1
  20. package/dist/agent/experts/crossDomain/moduleExpertInvoker.js +4 -1
  21. package/dist/agent/experts/crossDomain/moduleExpertInvoker.js.map +1 -1
  22. package/dist/agent/scene/sceneStage1Runner.d.ts +1 -1
  23. package/dist/agent/scene/sceneStage1Runner.d.ts.map +1 -1
  24. package/dist/agent/scene/sceneStage1Runner.js +1 -1
  25. package/dist/agent/scene/sceneStage1Runner.js.map +1 -1
  26. package/dist/agent/scene/sceneStoryService.d.ts +1 -1
  27. package/dist/agent/scene/sceneStoryService.d.ts.map +1 -1
  28. package/dist/agent/scene/sceneStoryService.js +4 -1
  29. package/dist/agent/scene/sceneStoryService.js.map +1 -1
  30. package/dist/agent/types/agentProtocol.d.ts.map +1 -1
  31. package/dist/agent/types/agentProtocol.js +4 -1
  32. package/dist/agent/types/agentProtocol.js.map +1 -1
  33. package/dist/agent/types.d.ts +7 -0
  34. package/dist/agent/types.d.ts.map +1 -1
  35. package/dist/agent/types.js.map +1 -1
  36. package/dist/agentOpenAI/openAiConfig.d.ts +2 -0
  37. package/dist/agentOpenAI/openAiConfig.d.ts.map +1 -1
  38. package/dist/agentOpenAI/openAiConfig.js +3 -0
  39. package/dist/agentOpenAI/openAiConfig.js.map +1 -1
  40. package/dist/agentOpenAI/openAiRuntime.d.ts +8 -0
  41. package/dist/agentOpenAI/openAiRuntime.d.ts.map +1 -1
  42. package/dist/agentOpenAI/openAiRuntime.js +293 -58
  43. package/dist/agentOpenAI/openAiRuntime.js.map +1 -1
  44. package/dist/agentRuntime/runtimeHealth.d.ts +1 -0
  45. package/dist/agentRuntime/runtimeHealth.d.ts.map +1 -1
  46. package/dist/agentv3/artifactStore.d.ts +5 -0
  47. package/dist/agentv3/artifactStore.d.ts.map +1 -1
  48. package/dist/agentv3/artifactStore.js +3 -0
  49. package/dist/agentv3/artifactStore.js.map +1 -1
  50. package/dist/agentv3/claudeMcpServer.d.ts.map +1 -1
  51. package/dist/agentv3/claudeMcpServer.js +125 -86
  52. package/dist/agentv3/claudeMcpServer.js.map +1 -1
  53. package/dist/agentv3/claudeRuntime.d.ts.map +1 -1
  54. package/dist/agentv3/claudeRuntime.js +147 -65
  55. package/dist/agentv3/claudeRuntime.js.map +1 -1
  56. package/dist/agentv3/claudeSseBridge.d.ts +6 -0
  57. package/dist/agentv3/claudeSseBridge.d.ts.map +1 -1
  58. package/dist/agentv3/claudeSseBridge.js +1 -0
  59. package/dist/agentv3/claudeSseBridge.js.map +1 -1
  60. package/dist/agentv3/sessionStateSnapshot.d.ts +23 -0
  61. package/dist/agentv3/sessionStateSnapshot.d.ts.map +1 -1
  62. package/dist/assistant/application/agentAnalyzeSessionService.d.ts +6 -0
  63. package/dist/assistant/application/agentAnalyzeSessionService.d.ts.map +1 -1
  64. package/dist/assistant/application/agentAnalyzeSessionService.js +9 -3
  65. package/dist/assistant/application/agentAnalyzeSessionService.js.map +1 -1
  66. package/dist/assistant/application/assistantApplicationService.d.ts.map +1 -1
  67. package/dist/assistant/application/assistantApplicationService.js +3 -1
  68. package/dist/assistant/application/assistantApplicationService.js.map +1 -1
  69. package/dist/cli-user/commands/report.js +64 -0
  70. package/dist/cli-user/commands/report.js.map +1 -1
  71. package/dist/cli-user/io/paths.d.ts +3 -0
  72. package/dist/cli-user/io/paths.d.ts.map +1 -1
  73. package/dist/cli-user/io/paths.js +6 -0
  74. package/dist/cli-user/io/paths.js.map +1 -1
  75. package/dist/cli-user/io/sessionStore.d.ts +1 -0
  76. package/dist/cli-user/io/sessionStore.d.ts.map +1 -1
  77. package/dist/cli-user/io/sessionStore.js +5 -0
  78. package/dist/cli-user/io/sessionStore.js.map +1 -1
  79. package/dist/cli-user/repl/renderer.d.ts +8 -0
  80. package/dist/cli-user/repl/renderer.d.ts.map +1 -1
  81. package/dist/cli-user/repl/renderer.js.map +1 -1
  82. package/dist/cli-user/services/cliAnalyzeService.d.ts +3 -0
  83. package/dist/cli-user/services/cliAnalyzeService.d.ts.map +1 -1
  84. package/dist/cli-user/services/cliAnalyzeService.js +103 -1
  85. package/dist/cli-user/services/cliAnalyzeService.js.map +1 -1
  86. package/dist/cli-user/services/turnPersistence.d.ts +0 -10
  87. package/dist/cli-user/services/turnPersistence.d.ts.map +1 -1
  88. package/dist/cli-user/services/turnPersistence.js +62 -0
  89. package/dist/cli-user/services/turnPersistence.js.map +1 -1
  90. package/dist/routes/agentReportRoutes.d.ts +1 -0
  91. package/dist/routes/agentReportRoutes.d.ts.map +1 -1
  92. package/dist/routes/agentReportRoutes.js +13 -2
  93. package/dist/routes/agentReportRoutes.js.map +1 -1
  94. package/dist/routes/agentResumeRoutes.d.ts.map +1 -1
  95. package/dist/routes/agentResumeRoutes.js +51 -5
  96. package/dist/routes/agentResumeRoutes.js.map +1 -1
  97. package/dist/routes/agentRoutes.d.ts.map +1 -1
  98. package/dist/routes/agentRoutes.js +524 -130
  99. package/dist/routes/agentRoutes.js.map +1 -1
  100. package/dist/scripts/verifyAgentSseScrolling.js +142 -2
  101. package/dist/scripts/verifyAgentSseScrolling.js.map +1 -1
  102. package/dist/services/agentEventStore.d.ts.map +1 -1
  103. package/dist/services/agentEventStore.js +13 -3
  104. package/dist/services/agentEventStore.js.map +1 -1
  105. package/dist/services/agentReportData.d.ts +3 -0
  106. package/dist/services/agentReportData.d.ts.map +1 -1
  107. package/dist/services/agentReportData.js.map +1 -1
  108. package/dist/services/agentResultNormalizer.d.ts +15 -3
  109. package/dist/services/agentResultNormalizer.d.ts.map +1 -1
  110. package/dist/services/agentResultNormalizer.js +344 -6
  111. package/dist/services/agentResultNormalizer.js.map +1 -1
  112. package/dist/services/analysisResultSnapshotPipeline.d.ts +3 -0
  113. package/dist/services/analysisResultSnapshotPipeline.d.ts.map +1 -1
  114. package/dist/services/analysisResultSnapshotPipeline.js +3 -0
  115. package/dist/services/analysisResultSnapshotPipeline.js.map +1 -1
  116. package/dist/services/analysisResultSnapshotStore.d.ts.map +1 -1
  117. package/dist/services/analysisResultSnapshotStore.js +34 -2
  118. package/dist/services/analysisResultSnapshotStore.js.map +1 -1
  119. package/dist/services/enterpriseSchema.d.ts.map +1 -1
  120. package/dist/services/enterpriseSchema.js +11 -0
  121. package/dist/services/enterpriseSchema.js.map +1 -1
  122. package/dist/services/evidence/evidenceContractBuilder.d.ts +11 -0
  123. package/dist/services/evidence/evidenceContractBuilder.d.ts.map +1 -0
  124. package/dist/services/evidence/evidenceContractBuilder.js +546 -0
  125. package/dist/services/evidence/evidenceContractBuilder.js.map +1 -0
  126. package/dist/services/finalResultQualityGate.d.ts +18 -0
  127. package/dist/services/finalResultQualityGate.d.ts.map +1 -0
  128. package/dist/services/finalResultQualityGate.js +283 -0
  129. package/dist/services/finalResultQualityGate.js.map +1 -0
  130. package/dist/services/htmlReportGenerator.d.ts +8 -1
  131. package/dist/services/htmlReportGenerator.d.ts.map +1 -1
  132. package/dist/services/htmlReportGenerator.js +129 -42
  133. package/dist/services/htmlReportGenerator.js.map +1 -1
  134. package/dist/services/persistAgentSession.d.ts +2 -0
  135. package/dist/services/persistAgentSession.d.ts.map +1 -1
  136. package/dist/services/persistAgentSession.js +17 -1
  137. package/dist/services/persistAgentSession.js.map +1 -1
  138. package/dist/services/processIdentity/identityContractMapper.d.ts +14 -0
  139. package/dist/services/processIdentity/identityContractMapper.d.ts.map +1 -0
  140. package/dist/services/processIdentity/identityContractMapper.js +135 -0
  141. package/dist/services/processIdentity/identityContractMapper.js.map +1 -0
  142. package/dist/services/processIdentity/types.d.ts +5 -0
  143. package/dist/services/processIdentity/types.d.ts.map +1 -1
  144. package/dist/services/processIdentity/types.js.map +1 -1
  145. package/dist/services/skillEngine/skillExecutor.d.ts +14 -2
  146. package/dist/services/skillEngine/skillExecutor.d.ts.map +1 -1
  147. package/dist/services/skillEngine/skillExecutor.js +133 -13
  148. package/dist/services/skillEngine/skillExecutor.js.map +1 -1
  149. package/dist/services/skillEngine/types.d.ts +2 -0
  150. package/dist/services/skillEngine/types.d.ts.map +1 -1
  151. package/dist/services/verifier/claimVerificationRunner.d.ts +20 -0
  152. package/dist/services/verifier/claimVerificationRunner.d.ts.map +1 -0
  153. package/dist/services/verifier/claimVerificationRunner.js +88 -0
  154. package/dist/services/verifier/claimVerificationRunner.js.map +1 -0
  155. package/dist/services/verifier/deterministicClaimVerifier.d.ts +8 -0
  156. package/dist/services/verifier/deterministicClaimVerifier.d.ts.map +1 -0
  157. package/dist/services/verifier/deterministicClaimVerifier.js +178 -0
  158. package/dist/services/verifier/deterministicClaimVerifier.js.map +1 -0
  159. package/dist/types/claimVerification.d.ts +38 -0
  160. package/dist/types/claimVerification.d.ts.map +1 -0
  161. package/dist/types/claimVerification.js +6 -0
  162. package/dist/types/claimVerification.js.map +1 -0
  163. package/dist/types/dataContract.d.ts +32 -0
  164. package/dist/types/dataContract.d.ts.map +1 -1
  165. package/dist/types/dataContract.js +7 -0
  166. package/dist/types/dataContract.js.map +1 -1
  167. package/dist/types/evidenceContract.d.ts +100 -0
  168. package/dist/types/evidenceContract.d.ts.map +1 -0
  169. package/dist/types/evidenceContract.js +6 -0
  170. package/dist/types/evidenceContract.js.map +1 -0
  171. package/dist/types/identityContract.d.ts +57 -0
  172. package/dist/types/identityContract.d.ts.map +1 -0
  173. package/dist/types/identityContract.js +6 -0
  174. package/dist/types/identityContract.js.map +1 -0
  175. package/dist/types/multiTraceComparison.d.ts +3 -0
  176. package/dist/types/multiTraceComparison.d.ts.map +1 -1
  177. package/package.json +3 -2
  178. package/skills/atomic/process_identity_resolver.skill.yaml +130 -1
  179. package/skills/atomic/process_slice_cpu_hotspots.skill.yaml +321 -0
  180. package/skills/atomic/startup_slow_reasons.skill.yaml +102 -17
  181. package/skills/composite/startup_analysis.skill.yaml +16 -0
  182. package/strategies/anr.strategy.md +2 -2
  183. package/strategies/game.strategy.md +1 -1
  184. package/strategies/general.strategy.md +1 -1
  185. package/strategies/prompt-openai-final-report-continuation-en.template.md +12 -0
  186. package/strategies/prompt-openai-final-report-continuation-zh.template.md +12 -0
  187. package/strategies/prompt-output-format.template.md +1 -1
  188. package/strategies/scrolling.strategy.md +1 -0
  189. package/strategies/startup.strategy.md +4 -1
@@ -0,0 +1,321 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-or-later
2
+ # Copyright (C) 2024-2026 Gracker (Chris)
3
+ # This file is part of SmartPerfetto. See LICENSE for details.
4
+
5
+ # =============================================================================
6
+ # 进程 Slice CPU 热点(原子 Skill)
7
+ # =============================================================================
8
+ # 按进程统计 named slice 的实际 Running CPU time。不同于 wall duration,
9
+ # 这里把 slice 时间段和 thread_state=Running 区间求交,避免把睡眠、IO 等
10
+ # 非执行时间误算成 CPU 消耗。
11
+
12
+ name: process_slice_cpu_hotspots
13
+ version: "1.0"
14
+ type: atomic
15
+ category: cpu
16
+ tier: B
17
+
18
+ meta:
19
+ display_name: "进程 Slice CPU 热点"
20
+ description: "按进程聚合 named slice 的实际 Running CPU 时间"
21
+ icon: "query_stats"
22
+ tags: [cpu, slice, thread_state, running, hotspot, atomic]
23
+
24
+ triggers:
25
+ keywords:
26
+ zh: [slice CPU, 函数 CPU, 热点 slice, CPU 热点, Running 时间, named slice]
27
+ en: [slice cpu, function cpu, hot slices, cpu hotspots, running time, named slice]
28
+ patterns:
29
+ - ".*(slice|函数|方法).*(CPU|cpu|消耗|热点).*"
30
+ - ".*(CPU|cpu).*(slice|function|method|named).*"
31
+
32
+ prerequisites:
33
+ modules:
34
+ - sched
35
+ required_tables:
36
+ - slice
37
+ - thread_track
38
+ - thread
39
+ - process
40
+ - thread_state
41
+
42
+ identity:
43
+ policy: verify_if_present
44
+ scope: process
45
+ aliases: [package, process_name]
46
+ rewriteTo: recommended_process_name_param
47
+
48
+ inputs:
49
+ - name: package
50
+ type: string
51
+ required: false
52
+ description: "目标应用包名或进程名前缀"
53
+ - name: process_name
54
+ type: string
55
+ required: false
56
+ description: "目标进程名;当 package 为空时使用"
57
+ - name: upid
58
+ type: integer
59
+ required: false
60
+ description: "可选 trace 内进程 ID;优先级高于 package/process_name"
61
+ - name: slice_name
62
+ type: string
63
+ required: false
64
+ description: "可选 slice 名称过滤;默认字面包含匹配,包含 % 时按 SQL LIKE 模式匹配"
65
+ - name: thread_scope
66
+ type: string
67
+ required: false
68
+ default: all
69
+ description: "线程范围:all/main/render/main_render"
70
+ - name: start_ts
71
+ type: timestamp
72
+ required: false
73
+ description: "分析起始时间戳(ns),默认 trace_start()"
74
+ - name: end_ts
75
+ type: timestamp
76
+ required: false
77
+ description: "分析结束时间戳(ns),默认 trace_end()"
78
+ - name: min_cpu_ns
79
+ type: integer
80
+ required: false
81
+ default: 0
82
+ description: "聚合后最小 CPU 时间阈值(ns)"
83
+ - name: top_k
84
+ type: integer
85
+ required: false
86
+ default: 10
87
+ description: "返回 TopK 条目"
88
+
89
+ display:
90
+ level: detail
91
+ layer: list
92
+ title: "进程 Slice CPU 热点"
93
+ columns:
94
+ - name: process_name
95
+ label: "进程"
96
+ type: string
97
+ format: truncate
98
+ - name: slice_name
99
+ label: "Slice"
100
+ type: string
101
+ format: truncate
102
+ - name: count
103
+ label: "次数"
104
+ type: number
105
+ format: compact
106
+ - name: thread_count
107
+ label: "线程数"
108
+ type: number
109
+ format: compact
110
+ - name: sample_threads
111
+ label: "样例线程"
112
+ type: string
113
+ format: truncate
114
+ - name: total_cpu_ms
115
+ label: "CPU时间"
116
+ type: duration
117
+ format: duration_ms
118
+ unit: ms
119
+ - name: total_wall_ms
120
+ label: "Wall时间"
121
+ type: duration
122
+ format: duration_ms
123
+ unit: ms
124
+ - name: avg_cpu_ms
125
+ label: "平均CPU"
126
+ type: duration
127
+ format: duration_ms
128
+ unit: ms
129
+ - name: max_cpu_ms
130
+ label: "最大CPU"
131
+ type: duration
132
+ format: duration_ms
133
+ unit: ms
134
+ - name: cpu_efficiency_pct
135
+ label: "CPU/Wall"
136
+ type: percentage
137
+ format: percentage
138
+ - name: selected_cpu_share_pct
139
+ label: "所选CPU占比"
140
+ type: percentage
141
+ format: percentage
142
+ - name: first_ts
143
+ label: "首次出现"
144
+ type: timestamp
145
+ - name: last_ts
146
+ label: "最后出现"
147
+ type: timestamp
148
+
149
+ sql: |
150
+ WITH
151
+ raw_input AS (
152
+ SELECT
153
+ COALESCE(${start_ts}, trace_start()) AS raw_start_ts,
154
+ COALESCE(${end_ts}, trace_end()) AS raw_end_ts,
155
+ ${upid} AS target_upid,
156
+ NULLIF(COALESCE(NULLIF('${process_name|}', ''), NULLIF('${package|}', '')), '') AS target_process,
157
+ NULLIF('${slice_name|}', '') AS target_slice,
158
+ CASE
159
+ WHEN '${thread_scope|all}' IN ('all', 'main', 'render', 'main_render') THEN '${thread_scope|all}'
160
+ ELSE 'all'
161
+ END AS thread_scope,
162
+ MAX(COALESCE(${min_cpu_ns|0}, 0), 0) AS min_cpu_ns,
163
+ MIN(MAX(COALESCE(${top_k|10}, 10), 1), 100) AS top_k
164
+ ),
165
+ input AS (
166
+ SELECT
167
+ MIN(raw_start_ts, raw_end_ts) AS start_ts,
168
+ MAX(raw_start_ts, raw_end_ts) AS end_ts,
169
+ target_upid,
170
+ target_process,
171
+ target_slice,
172
+ thread_scope,
173
+ min_cpu_ns,
174
+ top_k
175
+ FROM raw_input
176
+ ),
177
+ target_threads AS (
178
+ SELECT
179
+ p.upid,
180
+ p.pid,
181
+ p.name AS process_name,
182
+ t.utid,
183
+ t.tid,
184
+ COALESCE(t.name, '') AS thread_name
185
+ FROM process p
186
+ JOIN thread t ON t.upid = p.upid
187
+ CROSS JOIN input i
188
+ WHERE (
189
+ (
190
+ i.target_upid IS NOT NULL
191
+ AND p.upid = i.target_upid
192
+ )
193
+ OR (
194
+ i.target_upid IS NULL
195
+ AND (
196
+ i.target_process IS NULL
197
+ OR p.name GLOB i.target_process || '*'
198
+ OR p.name LIKE '%' || i.target_process || '%'
199
+ )
200
+ )
201
+ )
202
+ AND (
203
+ i.thread_scope = 'all'
204
+ OR (
205
+ i.thread_scope IN ('main', 'main_render')
206
+ AND (t.is_main_thread = 1 OR t.tid = p.pid)
207
+ )
208
+ OR (
209
+ i.thread_scope IN ('render', 'main_render')
210
+ AND (
211
+ t.name = 'RenderThread'
212
+ OR t.name = 'GPU completion'
213
+ OR t.name GLOB '[0-9]*.ui'
214
+ OR t.name GLOB '[0-9]*.raster'
215
+ )
216
+ )
217
+ )
218
+ ),
219
+ candidate_slices AS (
220
+ SELECT
221
+ s.id,
222
+ s.name AS slice_name,
223
+ s.ts,
224
+ s.dur,
225
+ tt.upid,
226
+ tt.process_name,
227
+ tt.utid,
228
+ tt.thread_name
229
+ FROM slice s
230
+ JOIN thread_track track ON s.track_id = track.id
231
+ JOIN target_threads tt ON track.utid = tt.utid
232
+ CROSS JOIN input i
233
+ WHERE s.dur > 0
234
+ AND s.ts < i.end_ts
235
+ AND s.ts + s.dur > i.start_ts
236
+ AND (
237
+ i.target_slice IS NULL
238
+ OR (
239
+ INSTR(i.target_slice, '%') > 0
240
+ AND s.name LIKE i.target_slice
241
+ )
242
+ OR (
243
+ INSTR(i.target_slice, '%') = 0
244
+ AND INSTR(s.name, i.target_slice) > 0
245
+ )
246
+ )
247
+ ),
248
+ per_slice_cpu AS (
249
+ SELECT
250
+ cs.id,
251
+ cs.process_name,
252
+ cs.slice_name,
253
+ cs.utid,
254
+ cs.thread_name,
255
+ MAX(cs.ts, i.start_ts) AS clipped_start_ts,
256
+ MIN(cs.ts + cs.dur, i.end_ts) AS clipped_end_ts,
257
+ MIN(cs.ts + cs.dur, i.end_ts) - MAX(cs.ts, i.start_ts) AS wall_ns,
258
+ COALESCE(SUM(
259
+ MIN(MIN(cs.ts + cs.dur, i.end_ts), ts.ts + ts.dur)
260
+ - MAX(MAX(cs.ts, i.start_ts), ts.ts)
261
+ ), 0) AS cpu_ns
262
+ FROM candidate_slices cs
263
+ CROSS JOIN input i
264
+ LEFT JOIN thread_state ts ON ts.utid = cs.utid
265
+ AND ts.state = 'Running'
266
+ AND ts.dur > 0
267
+ AND ts.ts < MIN(cs.ts + cs.dur, i.end_ts)
268
+ AND ts.ts + ts.dur > MAX(cs.ts, i.start_ts)
269
+ GROUP BY
270
+ cs.id,
271
+ cs.process_name,
272
+ cs.slice_name,
273
+ cs.utid,
274
+ cs.thread_name,
275
+ cs.ts,
276
+ cs.dur,
277
+ i.start_ts,
278
+ i.end_ts
279
+ ),
280
+ aggregate_cpu AS (
281
+ SELECT
282
+ process_name,
283
+ slice_name,
284
+ COUNT(*) AS count,
285
+ COUNT(DISTINCT utid) AS thread_count,
286
+ SUBSTR(GROUP_CONCAT(DISTINCT COALESCE(NULLIF(thread_name, ''), '<unnamed>')), 1, 240) AS sample_threads,
287
+ SUM(cpu_ns) AS total_cpu_ns,
288
+ SUM(wall_ns) AS total_wall_ns,
289
+ AVG(cpu_ns) AS avg_cpu_ns,
290
+ MAX(cpu_ns) AS max_cpu_ns,
291
+ MIN(clipped_start_ts) AS first_ts,
292
+ MAX(clipped_end_ts) AS last_ts
293
+ FROM per_slice_cpu
294
+ GROUP BY process_name, slice_name
295
+ HAVING SUM(cpu_ns) >= (SELECT min_cpu_ns FROM input)
296
+ ),
297
+ selected_total AS (
298
+ SELECT SUM(total_cpu_ns) AS total_cpu_ns
299
+ FROM aggregate_cpu
300
+ )
301
+ SELECT
302
+ process_name,
303
+ slice_name,
304
+ count,
305
+ thread_count,
306
+ sample_threads,
307
+ ROUND(total_cpu_ns / 1e6, 2) AS total_cpu_ms,
308
+ ROUND(total_wall_ns / 1e6, 2) AS total_wall_ms,
309
+ ROUND(avg_cpu_ns / 1e6, 2) AS avg_cpu_ms,
310
+ ROUND(max_cpu_ns / 1e6, 2) AS max_cpu_ms,
311
+ ROUND(100.0 * total_cpu_ns / NULLIF(total_wall_ns, 0), 1) AS cpu_efficiency_pct,
312
+ ROUND(100.0 * total_cpu_ns / NULLIF((SELECT total_cpu_ns FROM selected_total), 0), 1) AS selected_cpu_share_pct,
313
+ printf('%d', first_ts) AS first_ts,
314
+ printf('%d', last_ts) AS last_ts
315
+ FROM aggregate_cpu
316
+ WHERE total_cpu_ns > 0
317
+ ORDER BY total_cpu_ns DESC
318
+ LIMIT (SELECT top_k FROM input)
319
+
320
+ output:
321
+ format: structured
@@ -71,17 +71,96 @@ steps:
71
71
  type: duration
72
72
  format: duration_ms
73
73
  unit: ms
74
+ - name: ts
75
+ label: "启动开始时间(ns)"
76
+ type: timestamp
77
+ hidden: true
78
+ - name: dur
79
+ label: "启动耗时(ns)"
80
+ type: duration
81
+ hidden: true
82
+ - name: upid
83
+ label: "进程UPID"
84
+ type: number
85
+ hidden: true
74
86
  sql: |
87
+ WITH startup_type_signals AS (
88
+ SELECT
89
+ st.startup_id,
90
+ MAX(CASE WHEN sl.name = 'bindApplication' THEN 1 ELSE 0 END) as has_bind_app,
91
+ MAX(CASE WHEN sl.name GLOB 'performCreate:*' THEN 1 ELSE 0 END) as has_perform_create,
92
+ MAX(CASE WHEN sl.name GLOB 'handleRelaunchActivity*'
93
+ OR sl.name GLOB 'relaunchActivity*' THEN 1 ELSE 0 END) as has_relaunch
94
+ FROM android_startup_threads st
95
+ JOIN thread_track tt ON tt.utid = st.utid
96
+ JOIN slice sl ON sl.track_id = tt.id
97
+ WHERE st.is_main_thread = 1
98
+ AND sl.ts + sl.dur > st.ts AND sl.ts < st.ts + st.dur
99
+ AND (sl.name = 'bindApplication'
100
+ OR sl.name GLOB 'performCreate:*'
101
+ OR sl.name GLOB 'handleRelaunchActivity*'
102
+ OR sl.name GLOB 'relaunchActivity*')
103
+ GROUP BY st.startup_id
104
+ ),
105
+ process_age AS (
106
+ SELECT
107
+ s.startup_id,
108
+ MAX(CASE
109
+ WHEN p.start_ts IS NOT NULL
110
+ AND p.start_ts >= s.ts - 5000000000
111
+ AND p.start_ts <= s.ts + s.dur
112
+ THEN 1 ELSE 0
113
+ END) as process_created_during_startup
114
+ FROM android_startups s
115
+ LEFT JOIN android_startup_processes asp ON asp.startup_id = s.startup_id
116
+ LEFT JOIN process p ON p.upid = asp.upid
117
+ GROUP BY s.startup_id
118
+ ),
119
+ startup_process AS (
120
+ SELECT startup_id, MAX(upid) as upid
121
+ FROM android_startup_processes
122
+ GROUP BY startup_id
123
+ ),
124
+ validated AS (
125
+ SELECT
126
+ s.startup_id,
127
+ s.package,
128
+ s.ts,
129
+ CASE
130
+ WHEN COALESCE(sts.has_bind_app, 0) = 1 THEN 'cold'
131
+ WHEN COALESCE(sts.has_perform_create, 0) = 1 AND COALESCE(sts.has_bind_app, 0) = 0 THEN 'warm'
132
+ WHEN COALESCE(sts.has_relaunch, 0) = 1 THEN 'warm'
133
+ WHEN COALESCE(pa.process_created_during_startup, 0) = 1 THEN 'cold'
134
+ ELSE s.startup_type
135
+ END as startup_type,
136
+ s.dur,
137
+ ttd.time_to_initial_display,
138
+ ttd.time_to_full_display,
139
+ COALESCE(sp.upid, (
140
+ SELECT p2.upid
141
+ FROM process p2
142
+ WHERE p2.name GLOB s.package || '*'
143
+ ORDER BY p2.start_ts DESC
144
+ LIMIT 1
145
+ )) as upid
146
+ FROM android_startups s
147
+ LEFT JOIN startup_process sp ON sp.startup_id = s.startup_id
148
+ LEFT JOIN android_startup_time_to_display ttd USING (startup_id)
149
+ LEFT JOIN startup_type_signals sts USING (startup_id)
150
+ LEFT JOIN process_age pa USING (startup_id)
151
+ )
75
152
  SELECT
76
- s.startup_id,
77
- s.package,
78
- s.startup_type,
79
- ROUND(s.dur / 1e6, 1) as dur_ms,
80
- ROUND(ttd.time_to_initial_display / 1e6, 1) as ttid_ms,
81
- ROUND(ttd.time_to_full_display / 1e6, 1) as ttfd_ms
82
- FROM android_startups s
83
- LEFT JOIN android_startup_time_to_display ttd USING (startup_id)
84
- ORDER BY s.dur DESC
153
+ startup_id,
154
+ package,
155
+ startup_type,
156
+ ts,
157
+ dur,
158
+ upid,
159
+ ROUND(dur / 1e6, 1) as dur_ms,
160
+ ROUND(time_to_initial_display / 1e6, 1) as ttid_ms,
161
+ ROUND(time_to_full_display / 1e6, 1) as ttfd_ms
162
+ FROM validated
163
+ ORDER BY dur DESC
85
164
  save_as: startup_overview
86
165
  optional: true
87
166
 
@@ -91,6 +170,7 @@ steps:
91
170
  - id: slow_reason_checks
92
171
  type: atomic
93
172
  name: "慢启动原因检测"
173
+ condition: startup_overview.data.length > 0
94
174
  display:
95
175
  level: key
96
176
  layer: list
@@ -113,11 +193,16 @@ steps:
113
193
  type: string
114
194
  sql: |
115
195
  WITH startup_info AS (
116
- SELECT s.startup_id, s.package, s.ts, s.dur, s.startup_type,
117
- p.upid
118
- FROM android_startups s
119
- JOIN process p ON p.name GLOB s.package || '*'
120
- ORDER BY s.dur DESC LIMIT 1
196
+ SELECT
197
+ startup_id,
198
+ package,
199
+ ts,
200
+ dur,
201
+ startup_type,
202
+ upid
203
+ FROM ${startup_overview}
204
+ ORDER BY dur DESC
205
+ LIMIT 1
121
206
  ),
122
207
  main_thread AS (
123
208
  SELECT t.utid, t.tid FROM thread t
@@ -310,7 +395,7 @@ steps:
310
395
  JOIN thread_track tt2 ON ba.track_id = tt2.id
311
396
  JOIN main_thread mt2 ON tt2.utid = mt2.utid
312
397
  WHERE ba.name = 'bindApplication'
313
- AND ba.ts >= si.ts AND ba.ts < si.ts + si.dur
398
+ AND ba.ts + ba.dur > si.ts AND ba.ts < si.ts + si.dur
314
399
  )
315
400
  ) WHERE cp_count > 3
316
401
 
@@ -341,7 +426,7 @@ steps:
341
426
  JOIN thread_track tt2 ON ba.track_id = tt2.id
342
427
  JOIN main_thread mt2 ON tt2.utid = mt2.utid
343
428
  WHERE ba.name = 'bindApplication'
344
- AND ba.ts >= si.ts AND ba.ts < si.ts + si.dur
429
+ AND ba.ts + ba.dur > si.ts AND ba.ts < si.ts + si.dur
345
430
  AND ts_inner.ts >= ba.ts AND ts_inner.ts < ba.ts + ba.dur
346
431
  ) THEN ts_inner.dur ELSE 0 END) > SUM(ts_inner.dur) / 2 THEN 1 ELSE 0 END as in_bind_app,
347
432
  -- SR04 是否已覆盖:futex wait 中有多少被 Lock contention slice 时间重叠解释
@@ -410,7 +495,7 @@ steps:
410
495
  FROM slice ba
411
496
  JOIN thread_track tt_ba ON ba.track_id = tt_ba.id
412
497
  JOIN main_thread mt_ba ON tt_ba.utid = mt_ba.utid
413
- JOIN startup_info si ON ba.ts >= si.ts AND ba.ts < si.ts + si.dur
498
+ JOIN startup_info si ON ba.ts + ba.dur > si.ts AND ba.ts < si.ts + si.dur
414
499
  JOIN slice s ON s.track_id = ba.track_id
415
500
  AND s.ts >= ba.ts AND s.ts < ba.ts + ba.dur
416
501
  AND s.dur > 5000000 -- > 5ms
@@ -131,6 +131,22 @@ steps:
131
131
  - name: type_display
132
132
  label: "启动类型"
133
133
  type: string
134
+ - name: startup_type
135
+ label: "修正后类型"
136
+ type: string
137
+ hidden: true
138
+ - name: original_type
139
+ label: "原始类型"
140
+ type: string
141
+ hidden: true
142
+ - name: type_reclassified
143
+ label: "类型已修正"
144
+ type: number
145
+ hidden: true
146
+ - name: type_confidence
147
+ label: "类型置信度"
148
+ type: string
149
+ hidden: true
134
150
  - name: dur_ms
135
151
  label: "耗时"
136
152
  type: duration
@@ -108,7 +108,7 @@ fetch_artifact(artifactId, detail="rows", offset=0, limit=50)
108
108
  |--------|------|------|--------|
109
109
  | Q4 Sleeping 极高 | >80% | **主线程被阻塞**(ANR 最常见原因) | → 第二步:用 blocked_functions 定位 |
110
110
  | Q3 Runnable 高 | >30% | CPU 饥饿——可运行但得不到 CPU | → 检查 `sched_latency`、`cpu_health`、后台进程抢占 |
111
- | Q1+Q2 Running 高 | >70% | CPU-bound——主线程在执行重计算 | → 检查 `main_thread_slices`、热点函数 |
111
+ | Q1+Q2 Running 高 | >70% | CPU-bound——主线程在执行重计算 | → 检查 `main_thread_slices`,并调用 `invoke_skill("process_slice_cpu_hotspots", { process_name, start_ts, end_ts, thread_scope: "main" })` 定位主线程热点函数/slice 的 Running CPU time |
112
112
  | 混合 | 无明显主导 | 多因素共同导致 | → 依次排查 Q4→Q3→Q1 |
113
113
 
114
114
  ### 第二步:当 Q4 占比高时 — 用 blocked_functions + 线程状态定位
@@ -197,4 +197,4 @@ fetch_artifact(artifactId, detail="rows", offset=0, limit=50)
197
197
  - 忽略 `wakeup_chain` 数据(这是定位间接依赖链的关键)
198
198
  - 把所有 ANR 统一用同一个决策路径分析,不区分 ANR 类型
199
199
  - 忽略 `app_freeze_check`(应用完全冻结 vs 部分响应是重要区分)
200
- - 不交叉检查 CPU/内存/IO 系统上下文就下结论
200
+ - 不交叉检查 CPU/内存/IO 系统上下文就下结论
@@ -100,7 +100,7 @@ invoke_skill("mali_gpu_power_state")
100
100
  | CPU 频率下降 | `invoke_skill("thermal_throttling")` | 游戏长时间运行容易触发热节流 |
101
101
  | 内存压力 | `invoke_skill("memory_analysis")` | 游戏内存占用大,可能触发 LMK |
102
102
  | CPU 调度 | `invoke_skill("cpu_analysis")` | 游戏线程调度到小核会造成帧率波动 |
103
- | 线程/进程 CPU 利用率 | `invoke_skill("cpu_thread_utilization_period")` / `invoke_skill("cpu_process_utilization_period")` | 判断 UnityMain/GameThread/RenderThread 是否 CPU-bound |
103
+ | 线程/进程 CPU 利用率 | `invoke_skill("cpu_thread_utilization_period")` / `invoke_skill("cpu_process_utilization_period")`;需要函数/slice 级热点时补 `invoke_skill("process_slice_cpu_hotspots", { process_name, start_ts, end_ts })` | 判断 UnityMain/GameThread/RenderThread 是否 CPU-bound,并用 Running CPU time 定位 named slice 热点 |
104
104
  | 功耗归因 | `invoke_skill("wattson_thread_power_attribution")` | 仅在 power_rails + cpu_freq_idle 可用时做线程能耗归因 |
105
105
  | 独立 GL swap 间隔 | `invoke_skill("gl_standalone_swap_jank")` | NativeActivity/GLSurfaceView 或引擎自管 swap 时检查生产端 present 节奏 |
106
106
 
@@ -19,7 +19,7 @@ keywords: []
19
19
 
20
20
  | 用户关注方向 | 推荐路径 | 说明 |
21
21
  |-------------|---------|------|
22
- | **CPU / 调度 / 线程** | `invoke_skill("cpu_analysis")` → 如果发现 throttling → `invoke_skill("thermal_throttling")` | 交叉检查热节流和 CPU 频率 |
22
+ | **CPU / 调度 / 线程** | `invoke_skill("cpu_analysis")` → 需要函数/slice CPU 热点时 `invoke_skill("process_slice_cpu_hotspots", { process_name: "<包名或进程名>" })` → 如果发现 throttling → `invoke_skill("thermal_throttling")` | Running CPU time 区分真实计算热点和 wall-time 阻塞,再交叉检查热节流和 CPU 频率 |
23
23
  | **内存 / OOM / 泄漏** | `invoke_skill("memory_analysis")` → 如果有 heap dump → `invoke_skill("android_heap_graph_summary")` → 如果有 LMK → `invoke_skill("lmk_analysis")` → 如果涉及 GPU 内存 → `invoke_skill("dmabuf_analysis")` | 层层深入内存问题;heap graph 用 retained/cumulative size 定位 retainer |
24
24
  | **IO / 磁盘 / 存储** | `invoke_skill("block_io_analysis")` 或 `invoke_skill("io_pressure")` | 磁盘 IO 和系统 IO 压力 |
25
25
  | **GPU / 渲染** | `invoke_skill("gpu_analysis")` | GPU 频率、利用率、Fence 等待 |
@@ -0,0 +1,12 @@
1
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
2
+ <!-- Copyright (C) 2024-2026 Gracker (Chris) | SmartPerfetto -->
3
+
4
+ System check: every analysis phase is completed/skipped, but there is still no complete user-facing final report.
5
+
6
+ Now output only the final report body. The first line must be `## Final Conclusion`. Do not call tools, do not call update_plan_phase, do not narrate the process, and do not output phase-by-phase logs.
7
+
8
+ The report must include: final conclusion, key evidence chain, root-cause breakdown, ruled-out factors, recommendations, and confidence/limitations.
9
+
10
+ Do not merely restate phase summaries; synthesize the collected concrete values and evidence into a readable conclusion.
11
+
12
+ Length requirement: at most 700 English words. Use 2-3 bullets per section; do not expand into a phase-by-phase log, do not copy artifact tables, do not output the evidence table index, and do not repeat raw SQL. If the evidence is sufficient, conclude directly.
@@ -0,0 +1,12 @@
1
+ <!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
2
+ <!-- Copyright (C) 2024-2026 Gracker (Chris) | SmartPerfetto -->
3
+
4
+ 系统校验:所有分析阶段已经 completed/skipped,但当前还没有面向用户的完整最终报告。
5
+
6
+ 请现在只输出最终报告正文;第一行必须是 `## 综合结论`。不要再调用工具,不要再调用 update_plan_phase,不要解释过程,不要输出“验证逻辑/现在进入 Phase/完成综合结论输出/分阶段证据摘要”。
7
+
8
+ 报告必须包含:综合结论、关键证据链、根因拆解、已排除因素、优化建议、置信度/限制。
9
+
10
+ 不要只复述阶段摘要;必须把已采集到的具体数值和证据串成可读结论。
11
+
12
+ 长度要求:最多 1200 个中文字符。每个小节 2-3 条要点即可;不要展开逐阶段流水账,不要复制 artifact 表格,不要重复 SQL 原文,不要输出证据表索引。若证据已经足够,直接收束。
@@ -84,7 +84,7 @@ graph LR
84
84
  ```
85
85
 
86
86
  ### 结论结构
87
- 结论必须完整但克制:优先输出能支撑决策的证据链,避免把已经展示过的大表逐行搬进最终报告。目标长度控制在约 6000 中文字符内;如果证据很多,用聚合表和证据索引压缩,不要生成会在 token 上限处截断的超长报告。
87
+ 结论必须完整但克制:优先输出能支撑决策的证据链,避免把已经展示过的大表逐行搬进最终报告。中文目标长度控制在约 2500-3500 字符,英文目标长度控制在约 1200-1800 words;如果证据很多,用聚合表和证据索引压缩,不要生成会在 token 上限处截断的超长报告。
88
88
 
89
89
  1. **概览**: 一句话总结性能状况。如果架构检测置信度 < 80%,在概览中标注(如"⚠️ 架构检测置信度 50%,分析策略可能不完全匹配"),帮助用户理解分析的局限性
90
90
  2. **关键发现**: 按严重程度排列的发现列表(含根因推理链 + 📚 背景知识)
@@ -224,6 +224,7 @@ invoke_skill("scrolling_analysis", { start_ts: "<trace_start>", end_ts: "<trace_
224
224
  | UI thread 时间分解 | `invoke_skill("frame_ui_time_breakdown")` | 看 UI thread 在每帧的耗时分布 |
225
225
  | 每帧阻塞调用 | `invoke_skill("frame_blocking_calls")` | 将掉帧帧与 Binder/GC/锁竞争/futex/文件 IO 阻塞区间做重叠匹配 |
226
226
  | CPU process/thread 周期利用率 | `invoke_skill("cpu_process_utilization_period")` / `invoke_skill("cpu_thread_utilization_period")` | 用于 workload_heavy、后台抢占、线程归因 |
227
+ | 进程 slice CPU 热点 | `invoke_skill("process_slice_cpu_hotspots", { process_name, start_ts, end_ts })` | 用 `thread_state=Running` 求交,确认掉帧窗口内真正消耗 CPU 的 named slice |
227
228
  | CPU cluster 拓扑 | `invoke_skill("cpu_cluster_mapping_view")` | 解释大小核分布,辅助 small_core_placement |
228
229
  | GPU work period | `invoke_skill("android_gpu_work_period_track")` | 只有 `gpu_work_period` capability 可用时才做 GPU active region 判断 |
229
230
  | Mali power state | `invoke_skill("mali_gpu_power_state")` | Mali 设备专用;无数据时标注设备/trace 不支持 |
@@ -102,12 +102,14 @@ plan_template:
102
102
  | 热启动 (hot) | 两者均不存在 → 保留 Perfetto 原始分类 | Activity.onRestart() → onStart() → onResume() |
103
103
 
104
104
  **判定逻辑(优先级从高到低):**
105
- 1. 如果 Skill 返回的 `startup_type` 已经过重分类(`startup_events_in_range` 的 SQL 层重分类),直接信任
105
+ 1. 如果 Skill 返回的 `startup_type/type_display` 已经过重分类(`startup_events_in_range` 的 SQL 层重分类,或 `startup_quality.issue_codes` 包含 `R009_TYPE_RECLASSIFIED`),直接信任;除非同一条 SQL 明确复现了 Skill 的 overlap 口径并证明修正信号不存在,否则不得推翻。
106
106
  2. 否则检查 trace 信号:`bindApplication` 存在 → cold;仅 `performCreate:*` 存在 → warm;均无 → hot
107
107
  3. 热启动无正向信号(没有专属的 trace slice),仅靠排除法判定——这是合理的,因为热启动不触发 Activity 重建
108
108
 
109
109
  **⚠️ LMK 边界场景:** 进程被 LMK 回收后重启时,ActivityManager 可能仍持有 Activity 记录,导致 Perfetto 报告 `warm`。但 `bindApplication` slice 存在说明进程经历了完整初始化(Zygote fork → handleBindApplication),实为 cold start。此时**必须以 `bindApplication` 信号为准**,覆盖 Perfetto 原始分类。
110
110
 
111
+ **⚠️ 验证口径陷阱:** `bindApplication` 可能早于 `android_startups.ts` 约几十到数百毫秒开始。用 `thread_slice.ts BETWEEN start_ts AND end_ts` 的窄窗口查询返回 0 行,不能证明 `bindApplication` 不存在。若要自行验证,必须使用 `android_startup_threads` 与 `slice` 的 overlap 条件(`sl.ts + sl.dur > st.ts AND sl.ts < st.ts + st.dur`),或至少把起点扩展到 `start_ts - 500ms`。当 `startup_analysis` 已给出 `type_display=冷启动`、`type_reclassified=1`、`startup_breakdown.reason=bind_application` 或 `R009_TYPE_RECLASSIFIED` 时,结论必须按冷启动写,不得输出“R009 误判/维持温启动”。
112
+
111
113
  #### 启动场景关键 Stdlib 表
112
114
 
113
115
  写 execute_sql 时优先使用(完整列表见方法论模板):`android_startup_opinionated_breakdown`、`android_garbage_collection_events`、`android_oom_adj_intervals`、`android_screen_state`、`slice_self_dur`、`cpu_process_utilization_in_interval(ts, dur)`、`cpu_frequency_counters`、`android_dvfs_counter_stats`
@@ -131,6 +133,7 @@ invoke_skill("startup_analysis", { enable_startup_details: false })
131
133
  可能的根因:异步帧渲染排队、SurfaceFlinger 合成延迟、GPU 渲染耗时、dequeueBuffer 等待。结论中必须量化说明 gap 中各阶段的耗时占比。
132
134
  - **R009_TYPE_RECLASSIFIED**(启动类型重分类):如果温启动存在 bindApplication slice,说明进程实际被重建过,可能是冷启动被误分类。分析时应质疑启动类型并说明重分类依据。
133
135
  - **温启动 + bindApplication 矛盾**:即使未触发 R009,如果主线程热点中出现 bindApplication(478ms+),也应主动质疑:温启动不应有 Application 初始化开销。可能原因:① 进程被回收后重启(实为冷启动);② framework atrace 标记不准确。
136
+ - **禁止反向误判**:如果 `startup_analysis.get_startups` 显示 `type_display=冷启动`,且 `startup_breakdown` 包含 `bind_application` 耗时,后续任何 raw SQL 只有在使用 overlap/扩展窗口并命中同一进程主线程后,才允许挑战冷启动结论。窄窗口 0 行只能写成“该 SQL 口径未覆盖 bindApplication 起点”,不能写成“bindApplication 不存在”。
134
137
 
135
138
  **Phase 2 — 获取启动详情(需要传参):**
136
139
  ```