@gracker/smartperfetto 1.0.19 → 1.0.21

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 (203) hide show
  1. package/dist/agent/config/domainManifest.d.ts +5 -3
  2. package/dist/agent/config/domainManifest.d.ts.map +1 -1
  3. package/dist/agent/config/domainManifest.js +120 -5
  4. package/dist/agent/config/domainManifest.js.map +1 -1
  5. package/dist/agent/core/conclusionContract.d.ts +1 -0
  6. package/dist/agent/core/conclusionContract.d.ts.map +1 -1
  7. package/dist/agent/core/orchestratorTypes.d.ts +5 -0
  8. package/dist/agent/core/orchestratorTypes.d.ts.map +1 -1
  9. package/dist/agent/core/orchestratorTypes.js.map +1 -1
  10. package/dist/agent/scene/buildSmartChatReport.d.ts +13 -0
  11. package/dist/agent/scene/buildSmartChatReport.d.ts.map +1 -0
  12. package/dist/agent/scene/buildSmartChatReport.js +333 -0
  13. package/dist/agent/scene/buildSmartChatReport.js.map +1 -0
  14. package/dist/agent/scene/sceneAnalysisJobRunner.d.ts +8 -4
  15. package/dist/agent/scene/sceneAnalysisJobRunner.d.ts.map +1 -1
  16. package/dist/agent/scene/sceneAnalysisJobRunner.js +78 -3
  17. package/dist/agent/scene/sceneAnalysisJobRunner.js.map +1 -1
  18. package/dist/agent/scene/sceneIntervalBuilder.d.ts +14 -5
  19. package/dist/agent/scene/sceneIntervalBuilder.d.ts.map +1 -1
  20. package/dist/agent/scene/sceneIntervalBuilder.js +578 -1
  21. package/dist/agent/scene/sceneIntervalBuilder.js.map +1 -1
  22. package/dist/agent/scene/sceneStage1Verifier.d.ts +8 -0
  23. package/dist/agent/scene/sceneStage1Verifier.d.ts.map +1 -0
  24. package/dist/agent/scene/sceneStage1Verifier.js +245 -0
  25. package/dist/agent/scene/sceneStage1Verifier.js.map +1 -0
  26. package/dist/agent/scene/sceneStoryService.d.ts +20 -2
  27. package/dist/agent/scene/sceneStoryService.d.ts.map +1 -1
  28. package/dist/agent/scene/sceneStoryService.js +238 -25
  29. package/dist/agent/scene/sceneStoryService.js.map +1 -1
  30. package/dist/agent/scene/smartCancelBridge.d.ts +13 -0
  31. package/dist/agent/scene/smartCancelBridge.d.ts.map +1 -0
  32. package/dist/agent/scene/smartCancelBridge.js +44 -0
  33. package/dist/agent/scene/smartCancelBridge.js.map +1 -0
  34. package/dist/agent/scene/smartDeepDiveDispatch.d.ts +15 -0
  35. package/dist/agent/scene/smartDeepDiveDispatch.d.ts.map +1 -0
  36. package/dist/agent/scene/smartDeepDiveDispatch.js +170 -0
  37. package/dist/agent/scene/smartDeepDiveDispatch.js.map +1 -0
  38. package/dist/agent/scene/types.d.ts +97 -6
  39. package/dist/agent/scene/types.d.ts.map +1 -1
  40. package/dist/agent/tools/frameAnalyzer.d.ts.map +1 -1
  41. package/dist/agent/tools/frameAnalyzer.js +1 -0
  42. package/dist/agent/tools/frameAnalyzer.js.map +1 -1
  43. package/dist/agent/types.d.ts +1 -1
  44. package/dist/agent/types.d.ts.map +1 -1
  45. package/dist/agent/types.js.map +1 -1
  46. package/dist/agentOpenAI/openAiRuntime.d.ts +24 -0
  47. package/dist/agentOpenAI/openAiRuntime.d.ts.map +1 -1
  48. package/dist/agentOpenAI/openAiRuntime.js +159 -191
  49. package/dist/agentOpenAI/openAiRuntime.js.map +1 -1
  50. package/dist/agentRuntime/index.d.ts +1 -0
  51. package/dist/agentRuntime/index.d.ts.map +1 -1
  52. package/dist/agentRuntime/index.js +16 -1
  53. package/dist/agentRuntime/index.js.map +1 -1
  54. package/dist/agentRuntime/runtimeCommon.d.ts +34 -0
  55. package/dist/agentRuntime/runtimeCommon.d.ts.map +1 -0
  56. package/dist/agentRuntime/runtimeCommon.js +231 -0
  57. package/dist/agentRuntime/runtimeCommon.js.map +1 -0
  58. package/dist/agentv3/claudeConfig.d.ts +6 -2
  59. package/dist/agentv3/claudeConfig.d.ts.map +1 -1
  60. package/dist/agentv3/claudeConfig.js +50 -48
  61. package/dist/agentv3/claudeConfig.js.map +1 -1
  62. package/dist/agentv3/claudeMcpServer.d.ts.map +1 -1
  63. package/dist/agentv3/claudeMcpServer.js +74 -66
  64. package/dist/agentv3/claudeMcpServer.js.map +1 -1
  65. package/dist/agentv3/claudeRuntime.d.ts +18 -2
  66. package/dist/agentv3/claudeRuntime.d.ts.map +1 -1
  67. package/dist/agentv3/claudeRuntime.js +198 -265
  68. package/dist/agentv3/claudeRuntime.js.map +1 -1
  69. package/dist/agentv3/claudeSseBridge.js +1 -1
  70. package/dist/agentv3/claudeSseBridge.js.map +1 -1
  71. package/dist/agentv3/claudeVerifier.d.ts.map +1 -1
  72. package/dist/agentv3/claudeVerifier.js +3 -6
  73. package/dist/agentv3/claudeVerifier.js.map +1 -1
  74. package/dist/agentv3/strategyLoader.d.ts +3 -0
  75. package/dist/agentv3/strategyLoader.d.ts.map +1 -1
  76. package/dist/agentv3/strategyLoader.js +17 -4
  77. package/dist/agentv3/strategyLoader.js.map +1 -1
  78. package/dist/cli-user/bin.js +83 -2
  79. package/dist/cli-user/bin.js.map +1 -1
  80. package/dist/cli-user/commands/analyze.d.ts +2 -0
  81. package/dist/cli-user/commands/analyze.d.ts.map +1 -1
  82. package/dist/cli-user/commands/analyze.js +1 -0
  83. package/dist/cli-user/commands/analyze.js.map +1 -1
  84. package/dist/cli-user/commands/capture.d.ts +37 -2
  85. package/dist/cli-user/commands/capture.d.ts.map +1 -1
  86. package/dist/cli-user/commands/capture.js +184 -95
  87. package/dist/cli-user/commands/capture.js.map +1 -1
  88. package/dist/cli-user/commands/compare.d.ts +2 -0
  89. package/dist/cli-user/commands/compare.d.ts.map +1 -1
  90. package/dist/cli-user/commands/compare.js +1 -0
  91. package/dist/cli-user/commands/compare.js.map +1 -1
  92. package/dist/cli-user/commands/doctor.js +4 -0
  93. package/dist/cli-user/commands/doctor.js.map +1 -1
  94. package/dist/cli-user/services/androidCapture.d.ts +59 -0
  95. package/dist/cli-user/services/androidCapture.d.ts.map +1 -0
  96. package/dist/cli-user/services/androidCapture.js +375 -0
  97. package/dist/cli-user/services/androidCapture.js.map +1 -0
  98. package/dist/cli-user/services/captureConfig.d.ts +38 -0
  99. package/dist/cli-user/services/captureConfig.d.ts.map +1 -0
  100. package/dist/cli-user/services/captureConfig.js +434 -0
  101. package/dist/cli-user/services/captureConfig.js.map +1 -0
  102. package/dist/cli-user/services/captureTools.d.ts +11 -0
  103. package/dist/cli-user/services/captureTools.d.ts.map +1 -0
  104. package/dist/cli-user/services/captureTools.js +247 -0
  105. package/dist/cli-user/services/captureTools.js.map +1 -0
  106. package/dist/cli-user/services/cliAnalyzeService.d.ts +2 -0
  107. package/dist/cli-user/services/cliAnalyzeService.d.ts.map +1 -1
  108. package/dist/cli-user/services/cliAnalyzeService.js +1 -0
  109. package/dist/cli-user/services/cliAnalyzeService.js.map +1 -1
  110. package/dist/cli-user/services/runtimeGuard.d.ts +10 -0
  111. package/dist/cli-user/services/runtimeGuard.d.ts.map +1 -1
  112. package/dist/cli-user/services/runtimeGuard.js +48 -0
  113. package/dist/cli-user/services/runtimeGuard.js.map +1 -1
  114. package/dist/cli-user/services/turnRunner.d.ts +3 -0
  115. package/dist/cli-user/services/turnRunner.d.ts.map +1 -1
  116. package/dist/cli-user/services/turnRunner.js +4 -0
  117. package/dist/cli-user/services/turnRunner.js.map +1 -1
  118. package/dist/cli-user/types.d.ts +57 -0
  119. package/dist/cli-user/types.d.ts.map +1 -1
  120. package/dist/config/index.d.ts +12 -0
  121. package/dist/config/index.d.ts.map +1 -1
  122. package/dist/config/index.js +6 -0
  123. package/dist/config/index.js.map +1 -1
  124. package/dist/perfetto-recording-tools-pin.env +24 -0
  125. package/dist/routes/agent/finalizeAgentDrivenSession.d.ts +67 -0
  126. package/dist/routes/agent/finalizeAgentDrivenSession.d.ts.map +1 -0
  127. package/dist/routes/agent/finalizeAgentDrivenSession.js +103 -0
  128. package/dist/routes/agent/finalizeAgentDrivenSession.js.map +1 -0
  129. package/dist/routes/agent/normalizeAnalyzeOptions.d.ts +42 -0
  130. package/dist/routes/agent/normalizeAnalyzeOptions.d.ts.map +1 -0
  131. package/dist/routes/agent/normalizeAnalyzeOptions.js +185 -0
  132. package/dist/routes/agent/normalizeAnalyzeOptions.js.map +1 -0
  133. package/dist/routes/agentRoutes.d.ts.map +1 -1
  134. package/dist/routes/agentRoutes.js +285 -125
  135. package/dist/routes/agentRoutes.js.map +1 -1
  136. package/dist/scripts/verifyAgentSseScrolling.js +131 -8
  137. package/dist/scripts/verifyAgentSseScrolling.js.map +1 -1
  138. package/dist/services/agentResultNormalizer.d.ts.map +1 -1
  139. package/dist/services/agentResultNormalizer.js +32 -4
  140. package/dist/services/agentResultNormalizer.js.map +1 -1
  141. package/dist/services/evidence/evidenceContractBuilder.d.ts.map +1 -1
  142. package/dist/services/evidence/evidenceContractBuilder.js +17 -3
  143. package/dist/services/evidence/evidenceContractBuilder.js.map +1 -1
  144. package/dist/services/perfettoSqlSkill.d.ts.map +1 -1
  145. package/dist/services/perfettoSqlSkill.js +1 -0
  146. package/dist/services/perfettoSqlSkill.js.map +1 -1
  147. package/dist/services/providerManager/connectionTester.d.ts.map +1 -1
  148. package/dist/services/providerManager/connectionTester.js +4 -68
  149. package/dist/services/providerManager/connectionTester.js.map +1 -1
  150. package/dist/services/providerManager/index.d.ts +1 -0
  151. package/dist/services/providerManager/index.d.ts.map +1 -1
  152. package/dist/services/providerManager/index.js +8 -1
  153. package/dist/services/providerManager/index.js.map +1 -1
  154. package/dist/services/providerManager/providerService.d.ts.map +1 -1
  155. package/dist/services/providerManager/providerService.js +37 -106
  156. package/dist/services/providerManager/providerService.js.map +1 -1
  157. package/dist/services/providerManager/providerSnapshot.d.ts.map +1 -1
  158. package/dist/services/providerManager/providerSnapshot.js +13 -12
  159. package/dist/services/providerManager/providerSnapshot.js.map +1 -1
  160. package/dist/services/providerManager/runtimeCapabilities.d.ts +9 -0
  161. package/dist/services/providerManager/runtimeCapabilities.d.ts.map +1 -0
  162. package/dist/services/providerManager/runtimeCapabilities.js +105 -0
  163. package/dist/services/providerManager/runtimeCapabilities.js.map +1 -0
  164. package/dist/services/sceneReport/sceneJobArtifactStore.d.ts +22 -0
  165. package/dist/services/sceneReport/sceneJobArtifactStore.d.ts.map +1 -0
  166. package/dist/services/sceneReport/sceneJobArtifactStore.js +65 -0
  167. package/dist/services/sceneReport/sceneJobArtifactStore.js.map +1 -0
  168. package/dist/services/sceneReport/sceneReportMemoryCache.d.ts +5 -3
  169. package/dist/services/sceneReport/sceneReportMemoryCache.d.ts.map +1 -1
  170. package/dist/services/sceneReport/sceneReportMemoryCache.js +15 -10
  171. package/dist/services/sceneReport/sceneReportMemoryCache.js.map +1 -1
  172. package/dist/services/sceneReport/sceneReportStore.d.ts +9 -4
  173. package/dist/services/sceneReport/sceneReportStore.d.ts.map +1 -1
  174. package/dist/services/sceneReport/sceneReportStore.js +27 -7
  175. package/dist/services/sceneReport/sceneReportStore.js.map +1 -1
  176. package/dist/services/skillEngine/skillExecutor.d.ts +1 -0
  177. package/dist/services/skillEngine/skillExecutor.d.ts.map +1 -1
  178. package/dist/services/skillEngine/skillExecutor.js +64 -12
  179. package/dist/services/skillEngine/skillExecutor.js.map +1 -1
  180. package/dist/services/traceProcessor/sqlSemaphore.d.ts +16 -0
  181. package/dist/services/traceProcessor/sqlSemaphore.d.ts.map +1 -0
  182. package/dist/services/traceProcessor/sqlSemaphore.js +63 -0
  183. package/dist/services/traceProcessor/sqlSemaphore.js.map +1 -0
  184. package/dist/types/dataContract.d.ts +1 -1
  185. package/dist/types/dataContract.d.ts.map +1 -1
  186. package/dist/types/dataContract.js +2 -0
  187. package/dist/types/dataContract.js.map +1 -1
  188. package/package.json +3 -3
  189. package/prebuilts/android-platform-tools/README.md +13 -0
  190. package/prebuilts/perfetto-recording-tools/README.md +17 -0
  191. package/skills/README.md +13 -5
  192. package/skills/atomic/cpu_topology_detection.skill.yaml +105 -159
  193. package/skills/atomic/cpu_topology_view.skill.yaml +2 -0
  194. package/skills/composite/device_state_snapshot.skill.yaml +204 -0
  195. package/skills/composite/scene_reconstruction.skill.yaml +5 -1
  196. package/strategies/prompt-openai-final-report-continuation-en.template.md +3 -1
  197. package/strategies/prompt-openai-final-report-continuation-zh.template.md +3 -1
  198. package/strategies/prompt-output-format.template.md +1 -1
  199. package/strategies/scene-reconstruction-verifier.template.md +18 -0
  200. package/strategies/scrolling.strategy.md +5 -1
  201. package/strategies/smart.strategy.md +53 -0
  202. package/strategies/startup.strategy.md +4 -4
  203. package/skills/atomic/device_state_snapshot.skill.yaml +0 -171
@@ -5,204 +5,167 @@
5
5
  # =============================================================================
6
6
  # CPU 拓扑动态检测 (CPU Topology Detection)
7
7
  # =============================================================================
8
- # cpufreq 最大值动态推断 CPU 集群类型
8
+ # Public compatibility wrapper around cpu_topology_view.
9
9
  #
10
- # 背景:
11
- # - 现代 SoC 使用异构多核设计 (big.LITTLE, DynamIQ)
12
- # - 不同芯片的 CPU 拓扑差异很大:
13
- # - Snapdragon 8 Gen 3: 2 小核 + 3 中核 + 1 Prime + 2 超大核
14
- # - Dimensity 9300: 4 大核 + 4 超大核 (全大核设计)
15
- # - Tensor G3: 4 小核 + 3 中核 + 1 大核
16
- #
17
- # 检测方法:
18
- # - 通过每个 CPU 核心的最大频率推断其类型
19
- # - 最高频率的 90%+ 归为 prime/big
20
- # - 60%-90% 归为 mid
21
- # - 60% 以下归为 little
10
+ # Keep CPU topology inference centralized in `_cpu_topology`; do not maintain
11
+ # another threshold-based classifier here. The shared view:
12
+ # - builds the CPU universe from observed trace evidence first;
13
+ # - ignores stale CPU table rows unless no observed CPU evidence exists;
14
+ # - classifies common Android layouts such as 6+2, 4+3+1, 4+4, 4+2, 4-only,
15
+ # and 10-core tri-cluster layouts from capacity/frequency scale clusters;
16
+ # - keeps unsupported/insufficient scale evidence explicit as `unknown`.
22
17
  # =============================================================================
23
18
 
24
19
  name: cpu_topology_detection
25
20
  version: "1.0"
26
- type: atomic
21
+ type: composite
27
22
  category: hardware
28
23
  tier: B
29
24
 
30
25
  meta:
31
26
  display_name: "CPU 拓扑检测"
32
- description: " cpufreq 动态检测 CPU 大小核拓扑"
27
+ description: "基于共享 _cpu_topology 视图检测 CPU 大小核拓扑"
33
28
  icon: "memory"
34
29
  tags: [cpu, topology, cluster, atomic]
35
30
 
36
- prerequisites:
37
- required_tables:
38
- - counter
39
- - cpu_counter_track
40
-
41
31
  inputs:
42
32
  - name: start_ts
43
33
  type: timestamp
44
34
  required: false
45
- description: "分析起始时间(可选)"
35
+ description: "分析起始时间(保留兼容;共享拓扑检测使用整条 trace 的观测证据)"
46
36
  - name: end_ts
47
37
  type: timestamp
48
38
  required: false
49
- description: "分析结束时间(可选)"
39
+ description: "分析结束时间(保留兼容;共享拓扑检测使用整条 trace 的观测证据)"
50
40
 
51
41
  steps:
52
- # Step 1: 检测每个 CPU 的最大频率
42
+ - id: init_cpu_topology
43
+ type: skill
44
+ name: "初始化 CPU 拓扑"
45
+ skill: cpu_topology_view
46
+ display:
47
+ level: hidden
48
+ optional: true
49
+
53
50
  - id: detect_cpu_clusters
54
51
  type: atomic
55
52
  name: "检测 CPU 集群"
56
53
  display:
57
54
  level: summary
55
+ layer: overview
58
56
  title: "CPU 拓扑检测结果"
57
+ columns:
58
+ - name: cpu
59
+ label: "CPU"
60
+ type: number
61
+ - name: cluster_type
62
+ label: "核心类型"
63
+ type: string
64
+ - name: max_freq_mhz
65
+ label: "Max Freq"
66
+ type: number
67
+ - name: capacity
68
+ label: "Capacity"
69
+ type: number
70
+ - name: topology_source
71
+ label: "判定来源"
72
+ type: string
73
+ - name: cluster_rank
74
+ label: "簇档位"
75
+ type: number
76
+ - name: cluster_count
77
+ label: "簇数量"
78
+ type: number
59
79
  sql: |
60
- WITH
61
- -- 获取时间范围
62
- time_bounds AS (
63
- SELECT
64
- COALESCE(${start_ts}, (SELECT MIN(ts) FROM counter)) as start_ts,
65
- COALESCE(${end_ts}, (SELECT MAX(ts) FROM counter)) as end_ts
66
- ),
67
- -- 获取每个 CPU 的最大频率
68
- cpu_max_freq AS (
69
- SELECT
70
- t.cpu,
71
- MAX(c.value) as max_freq_khz,
72
- MIN(c.value) as min_freq_khz,
73
- AVG(c.value) as avg_freq_khz,
74
- COUNT(*) as sample_count
75
- FROM counter c
76
- JOIN cpu_counter_track t ON c.track_id = t.id
77
- WHERE t.name = 'cpufreq'
78
- AND c.ts >= (SELECT start_ts FROM time_bounds)
79
- AND c.ts <= (SELECT end_ts FROM time_bounds)
80
- GROUP BY t.cpu
81
- ),
82
- -- 获取全局最大频率用于计算比例
83
- global_max AS (
84
- SELECT MAX(max_freq_khz) as global_max_freq FROM cpu_max_freq
85
- ),
86
- -- 根据最大频率比例推断集群类型
87
- cpu_clusters AS (
88
- SELECT
89
- cpu,
90
- max_freq_khz,
91
- min_freq_khz,
92
- ROUND(max_freq_khz / 1000.0, 0) as max_freq_mhz,
93
- ROUND(100.0 * max_freq_khz / (SELECT global_max_freq FROM global_max), 1) as freq_ratio_pct,
94
- CASE
95
- -- 最高频率的 90%+ 归为 prime (超大核)
96
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.95 THEN 'prime'
97
- -- 75%-95% 归为 big (大核)
98
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.75 THEN 'big'
99
- -- 50%-75% 归为 mid (中核)
100
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.50 THEN 'mid'
101
- -- 50% 以下归为 little (小核)
102
- ELSE 'little'
103
- END as cluster_type,
104
- sample_count
105
- FROM cpu_max_freq
106
- )
107
80
  SELECT
108
- cpu,
109
- cluster_type,
110
- max_freq_mhz,
111
- freq_ratio_pct,
112
- CASE cluster_type
81
+ cpu_id as cpu,
82
+ core_type as cluster_type,
83
+ CASE WHEN max_freq IS NULL THEN NULL ELSE ROUND(max_freq / 1000.0, 0) END as max_freq_mhz,
84
+ capacity,
85
+ topology_source,
86
+ cluster_rank,
87
+ cluster_count,
88
+ CASE core_type
113
89
  WHEN 'prime' THEN '超大核'
114
90
  WHEN 'big' THEN '大核'
115
- WHEN 'mid' THEN '中核'
116
- ELSE '小核'
91
+ WHEN 'medium' THEN '中核'
92
+ WHEN 'little' THEN '小核'
93
+ ELSE '未知'
117
94
  END as cluster_type_cn
118
- FROM cpu_clusters
119
- ORDER BY max_freq_khz DESC, cpu
95
+ FROM _cpu_topology
96
+ ORDER BY
97
+ CASE core_type
98
+ WHEN 'prime' THEN 1
99
+ WHEN 'big' THEN 2
100
+ WHEN 'medium' THEN 3
101
+ WHEN 'little' THEN 4
102
+ ELSE 5
103
+ END,
104
+ cpu_id
120
105
  save_as: cpu_clusters
121
106
 
122
- # Step 2: 集群汇总
123
107
  - id: cluster_summary
124
108
  type: atomic
125
109
  name: "集群汇总"
126
110
  display:
127
111
  level: summary
112
+ layer: overview
128
113
  title: "CPU 集群汇总"
114
+ columns:
115
+ - name: cluster_type
116
+ label: "核心类型"
117
+ type: string
118
+ - name: cpu_count
119
+ label: "CPU 数"
120
+ type: number
121
+ - name: cpus
122
+ label: "CPU 列表"
123
+ type: string
124
+ - name: max_freq_mhz
125
+ label: "最高频率"
126
+ type: number
127
+ - name: min_freq_mhz
128
+ label: "最低频率"
129
+ type: number
130
+ - name: topology_source
131
+ label: "判定来源"
132
+ type: string
129
133
  sql: |
130
- WITH
131
- cpu_max_freq AS (
132
- SELECT
133
- t.cpu,
134
- MAX(c.value) as max_freq_khz
135
- FROM counter c
136
- JOIN cpu_counter_track t ON c.track_id = t.id
137
- WHERE t.name = 'cpufreq'
138
- GROUP BY t.cpu
139
- ),
140
- global_max AS (
141
- SELECT MAX(max_freq_khz) as global_max_freq FROM cpu_max_freq
142
- ),
143
- cpu_clusters AS (
144
- SELECT
145
- cpu,
146
- max_freq_khz,
147
- CASE
148
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.95 THEN 'prime'
149
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.75 THEN 'big'
150
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.50 THEN 'mid'
151
- ELSE 'little'
152
- END as cluster_type
153
- FROM cpu_max_freq
154
- )
155
134
  SELECT
156
- cluster_type,
135
+ core_type as cluster_type,
157
136
  COUNT(*) as cpu_count,
158
- GROUP_CONCAT(cpu, ', ') as cpus,
159
- ROUND(MAX(max_freq_khz) / 1000.0, 0) as max_freq_mhz,
160
- ROUND(MIN(max_freq_khz) / 1000.0, 0) as min_freq_mhz,
161
- CASE cluster_type
137
+ GROUP_CONCAT(cpu_id, ', ') as cpus,
138
+ CASE WHEN MAX(max_freq) IS NULL THEN NULL ELSE ROUND(MAX(max_freq) / 1000.0, 0) END as max_freq_mhz,
139
+ CASE WHEN MIN(max_freq) IS NULL THEN NULL ELSE ROUND(MIN(max_freq) / 1000.0, 0) END as min_freq_mhz,
140
+ GROUP_CONCAT(DISTINCT topology_source) as topology_source,
141
+ CASE core_type
162
142
  WHEN 'prime' THEN 1
163
143
  WHEN 'big' THEN 2
164
- WHEN 'mid' THEN 3
165
- ELSE 4
144
+ WHEN 'medium' THEN 3
145
+ WHEN 'little' THEN 4
146
+ ELSE 5
166
147
  END as cluster_order
167
- FROM cpu_clusters
168
- GROUP BY cluster_type
148
+ FROM _cpu_topology
149
+ GROUP BY core_type
169
150
  ORDER BY cluster_order
170
151
  save_as: cluster_summary
171
152
 
172
- # Step 3: 导出供其他 skill 使用的集群映射
173
153
  - id: cluster_mapping
174
154
  type: atomic
175
155
  name: "集群映射"
176
156
  sql: |
177
- WITH
178
- cpu_max_freq AS (
179
- SELECT
180
- t.cpu,
181
- MAX(c.value) as max_freq_khz
182
- FROM counter c
183
- JOIN cpu_counter_track t ON c.track_id = t.id
184
- WHERE t.name = 'cpufreq'
185
- GROUP BY t.cpu
186
- ),
187
- global_max AS (
188
- SELECT MAX(max_freq_khz) as global_max_freq FROM cpu_max_freq
189
- )
190
157
  SELECT
191
- cpu,
192
- max_freq_khz,
158
+ cpu_id as cpu,
159
+ max_freq as max_freq_khz,
160
+ core_type as cluster_type,
193
161
  CASE
194
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.95 THEN 'prime'
195
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.75 THEN 'big'
196
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.50 THEN 'mid'
197
- ELSE 'little'
198
- END as cluster_type,
199
- -- 简化的 big/little 分类 (兼容旧逻辑)
200
- CASE
201
- WHEN max_freq_khz >= (SELECT global_max_freq FROM global_max) * 0.60 THEN 'big'
202
- ELSE 'little'
203
- END as simple_cluster_type
204
- FROM cpu_max_freq
205
- ORDER BY cpu
162
+ WHEN core_type IN ('prime', 'big', 'medium') THEN 'big'
163
+ WHEN core_type = 'little' THEN 'little'
164
+ ELSE 'unknown'
165
+ END as simple_cluster_type,
166
+ topology_source
167
+ FROM _cpu_topology
168
+ ORDER BY cpu_id
206
169
  save_as: cluster_mapping
207
170
 
208
171
  output:
@@ -214,20 +177,3 @@ output:
214
177
  description: "集群汇总(每种类型的核心数)"
215
178
  - name: cluster_mapping
216
179
  description: "集群映射表(供其他 skill 使用)"
217
-
218
- # =============================================================================
219
- # 使用示例
220
- # =============================================================================
221
- # 其他 skill 可以通过以下 CTE 使用动态检测的集群:
222
- #
223
- # WITH cpu_clusters AS (
224
- # -- 复制 cluster_mapping 的 SQL
225
- # )
226
- # SELECT
227
- # CASE
228
- # WHEN cpu IN (SELECT cpu FROM cpu_clusters WHERE cluster_type = 'prime') THEN 'prime'
229
- # WHEN cpu IN (SELECT cpu FROM cpu_clusters WHERE cluster_type = 'big') THEN 'big'
230
- # WHEN cpu IN (SELECT cpu FROM cpu_clusters WHERE cluster_type = 'mid') THEN 'mid'
231
- # ELSE 'little'
232
- # END as core_type
233
- # FROM ...
@@ -194,6 +194,7 @@ steps:
194
194
  cs.scale_bucket,
195
195
  CASE
196
196
  WHEN cs.scale_bucket IS NULL OR cs.scale_bucket <= 0 THEN 'unknown'
197
+ WHEN sc.cluster_count <= 1 AND (SELECT COUNT(*) FROM cpu_scale) <= 4 THEN 'little'
197
198
  WHEN sc.cluster_count <= 1 THEN 'unknown'
198
199
  WHEN sc.cluster_count = 2 AND sc.cluster_rank = sc.cluster_count THEN 'big'
199
200
  WHEN sc.cluster_rank = 1 THEN 'little'
@@ -205,6 +206,7 @@ steps:
205
206
  END as core_type,
206
207
  CASE
207
208
  WHEN cs.scale_bucket IS NULL OR cs.scale_bucket <= 0 THEN cs.topology_source
209
+ WHEN sc.cluster_count <= 1 AND (SELECT COUNT(*) FROM cpu_scale) <= 4 THEN cs.topology_source || '_uniform_four_little'
208
210
  WHEN sc.cluster_count <= 1 THEN cs.topology_source || '_uniform'
209
211
  ELSE cs.topology_source
210
212
  END as topology_source,
@@ -0,0 +1,204 @@
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
+ # 设备环境状态快照(组合 Skill)
7
+ # =============================================================================
8
+ # 采集指定窗口内的屏幕、电量、温度、频率、内存压力与 idle 状态。
9
+
10
+ name: device_state_snapshot
11
+ version: "2.0"
12
+ type: composite
13
+ category: system_context
14
+ tier: B
15
+
16
+ meta:
17
+ display_name: "设备环境状态快照"
18
+ description: "采集 trace 期间的设备环境信息(屏幕、电量、温度、CPU、内存、idle 窗口等)"
19
+ icon: "devices"
20
+ tags: [device, state, environment, context, composite]
21
+
22
+ prerequisites:
23
+ required_tables:
24
+ - slice
25
+ - counter
26
+ - counter_track
27
+
28
+ inputs:
29
+ - name: start_ts
30
+ type: timestamp
31
+ required: false
32
+ description: "分析起始时间戳(ns)"
33
+ - name: end_ts
34
+ type: timestamp
35
+ required: false
36
+ description: "分析结束时间戳(ns)"
37
+
38
+ steps:
39
+ - id: environment_snapshot
40
+ type: atomic
41
+ name: "设备环境快照"
42
+ display:
43
+ level: summary
44
+ layer: overview
45
+ title: "设备环境状态"
46
+ columns:
47
+ - name: metric
48
+ label: "指标"
49
+ type: string
50
+ - name: value
51
+ label: "值"
52
+ type: string
53
+ - name: ts
54
+ label: "时间戳"
55
+ type: timestamp
56
+ unit: ns
57
+ clickAction: navigate_timeline
58
+ sql: |
59
+ WITH trace_bounds AS (
60
+ SELECT
61
+ COALESCE(${start_ts}, (SELECT MIN(ts) FROM slice)) as t_start,
62
+ COALESCE(${end_ts}, (SELECT MAX(ts + dur) FROM slice)) as t_end
63
+ ),
64
+ screen_state AS (
65
+ SELECT
66
+ 'screen_state' as metric,
67
+ CASE WHEN c.value > 0 THEN 'ON' ELSE 'OFF' END as value,
68
+ c.ts as ts
69
+ FROM counter c
70
+ JOIN counter_track ct ON c.track_id = ct.id
71
+ CROSS JOIN trace_bounds tb
72
+ WHERE (ct.name GLOB '*ScreenState*' OR ct.name GLOB '*screen_state*')
73
+ AND c.ts >= tb.t_start AND c.ts <= tb.t_end
74
+ ORDER BY c.ts DESC
75
+ LIMIT 1
76
+ ),
77
+ battery_info AS (
78
+ SELECT
79
+ 'battery_level' as metric,
80
+ CAST(c.value AS TEXT) as value,
81
+ c.ts as ts
82
+ FROM counter c
83
+ JOIN counter_track ct ON c.track_id = ct.id
84
+ CROSS JOIN trace_bounds tb
85
+ WHERE (ct.name GLOB '*battery_level*' OR ct.name GLOB '*BatteryLevel*')
86
+ AND c.ts >= tb.t_start AND c.ts <= tb.t_end
87
+ ORDER BY c.ts DESC
88
+ LIMIT 1
89
+ ),
90
+ charging_info AS (
91
+ SELECT
92
+ 'charging_state' as metric,
93
+ CASE WHEN c.value > 0 THEN 'CHARGING' ELSE 'NOT_CHARGING' END as value,
94
+ c.ts as ts
95
+ FROM counter c
96
+ JOIN counter_track ct ON c.track_id = ct.id
97
+ CROSS JOIN trace_bounds tb
98
+ WHERE (ct.name GLOB '*battery_status*' OR ct.name GLOB '*charging*' OR ct.name GLOB '*BatteryStatus*')
99
+ AND c.ts >= tb.t_start AND c.ts <= tb.t_end
100
+ ORDER BY c.ts DESC
101
+ LIMIT 1
102
+ ),
103
+ thermal_info AS (
104
+ SELECT
105
+ 'thermal_zone' as metric,
106
+ ct.name || ': ' || CAST(ROUND(MAX(CASE WHEN c.value > 1000 THEN c.value / 1000.0 ELSE c.value END), 1) AS TEXT) || ' C' as value,
107
+ MAX(c.ts) as ts
108
+ FROM counter c
109
+ JOIN counter_track ct ON c.track_id = ct.id
110
+ CROSS JOIN trace_bounds tb
111
+ WHERE (ct.name GLOB '*thermal_zone*' OR ct.name GLOB '*Temperature*' OR ct.name GLOB '*temp*')
112
+ AND c.ts >= tb.t_start AND c.ts <= tb.t_end
113
+ GROUP BY ct.name
114
+ ORDER BY MAX(c.value) DESC
115
+ LIMIT 5
116
+ ),
117
+ memory_info AS (
118
+ SELECT
119
+ 'memory_pressure' as metric,
120
+ ct.name || ': ' || CAST(ROUND(MAX(c.value), 0) AS TEXT) as value,
121
+ MAX(c.ts) as ts
122
+ FROM counter c
123
+ JOIN counter_track ct ON c.track_id = ct.id
124
+ CROSS JOIN trace_bounds tb
125
+ WHERE (ct.name GLOB '*mem.*pressure*' OR ct.name GLOB '*MemFree*' OR ct.name GLOB '*MemAvailable*' OR ct.name GLOB '*psi*mem*')
126
+ AND c.ts >= tb.t_start AND c.ts <= tb.t_end
127
+ GROUP BY ct.name
128
+ ORDER BY MAX(c.value) DESC
129
+ LIMIT 5
130
+ )
131
+ SELECT metric, value, printf('%d', ts) as ts FROM screen_state
132
+ UNION ALL SELECT metric, value, printf('%d', ts) as ts FROM battery_info
133
+ UNION ALL SELECT metric, value, printf('%d', ts) as ts FROM charging_info
134
+ UNION ALL SELECT metric, value, printf('%d', ts) as ts FROM thermal_info
135
+ UNION ALL SELECT metric, value, printf('%d', ts) as ts FROM memory_info
136
+ save_as: environment_snapshot
137
+ synthesize:
138
+ role: overview
139
+ fields:
140
+ - key: metric
141
+ label: 指标
142
+ - key: value
143
+ label: 值
144
+
145
+ - id: idle_window_summary
146
+ type: atomic
147
+ name: "Idle 窗口摘要"
148
+ optional: true
149
+ display:
150
+ level: detail
151
+ layer: list
152
+ title: "Idle / 空闲窗口"
153
+ columns:
154
+ - name: start_ts
155
+ label: "开始"
156
+ type: timestamp
157
+ unit: ns
158
+ clickAction: navigate_timeline
159
+ - name: end_ts
160
+ label: "结束"
161
+ type: timestamp
162
+ unit: ns
163
+ clickAction: navigate_timeline
164
+ - name: dur_ms
165
+ label: "时长"
166
+ type: duration
167
+ unit: ms
168
+ - name: source
169
+ label: "来源"
170
+ type: string
171
+ sql: |
172
+ WITH trace_bounds AS (
173
+ SELECT
174
+ COALESCE(${start_ts}, (SELECT MIN(ts) FROM slice)) as t_start,
175
+ COALESCE(${end_ts}, (SELECT MAX(ts + dur) FROM slice)) as t_end
176
+ )
177
+ SELECT
178
+ printf('%d', s.ts) as start_ts,
179
+ printf('%d', s.ts + s.dur) as end_ts,
180
+ ROUND(s.dur / 1000000.0, 2) as dur_ms,
181
+ s.name as source
182
+ FROM slice s
183
+ CROSS JOIN trace_bounds tb
184
+ WHERE s.dur > 0
185
+ AND s.ts + s.dur > tb.t_start
186
+ AND s.ts < tb.t_end
187
+ AND (
188
+ s.name GLOB '*idle*'
189
+ OR s.name GLOB '*Idle*'
190
+ OR s.name GLOB '*suspend*'
191
+ OR s.name GLOB '*doze*'
192
+ )
193
+ ORDER BY s.dur DESC
194
+ LIMIT 20
195
+ save_as: idle_window_summary
196
+ synthesize:
197
+ role: list
198
+ fields:
199
+ - key: dur_ms
200
+ label: Idle 时长
201
+ format: "{{value}} ms"
202
+
203
+ output:
204
+ format: structured
@@ -573,6 +573,9 @@ steps:
573
573
  - name: gesture_id
574
574
  label: "手势ID"
575
575
  type: number
576
+ - name: app_package
577
+ label: "前台应用"
578
+ type: string
576
579
  - name: category
577
580
  label: "类别"
578
581
  type: string
@@ -633,6 +636,7 @@ steps:
633
636
  ELSE ''
634
637
  END AS event,
635
638
  gesture_id,
639
+ app AS app_package,
636
640
  'scroll_start' AS category,
637
641
  '💡 此时刻手指已移动足够距离,系统开始响应滑动' AS explanation
638
642
  FROM scroll_starts
@@ -2785,4 +2789,4 @@ steps:
2785
2789
 
2786
2790
  output:
2787
2791
  format: layered
2788
- default_expanded: [L1, L2]
2792
+ default_expanded: [L1, L2]
@@ -8,7 +8,9 @@ Now output only the final report body. The first line must be `## Final Conclusi
8
8
  The report must include: final conclusion, key evidence chain, root-cause breakdown, ruled-out factors, recommendations, and confidence/limitations.
9
9
 
10
10
  Continue to obey the scene strategy, Final Report Contract, and latest next_phase_reminder constraints from this run. If the scene strategy or contract requires root-cause distributions, representative samples, phase-duration breakdowns, dual-audience recommendations, architecture branch judgments, or any other scene-specific structure, keep that structure in the final report instead of compressing it into a short summary.
11
+ When the Final Report Contract names required items, prefer explicit matching sections or labels, for example "Phase Duration Breakdown", "[App Layer]", and "[System/Platform Layer]", instead of only implying those items inside prose.
12
+ Output all structures required by the Final Report Contract before long trees, appendices, or expanded details. Do not place required recommendations, audience/layered recommendations, or limitations after a long code block or long tree where a truncated report could lose key conclusions.
11
13
 
12
14
  Do not merely restate phase summaries; synthesize the collected concrete values and evidence into a readable conclusion.
13
15
 
14
- Length target: about 1,200-1,800 English words. Use compact aggregation tables where helpful; do not expand into a phase-by-phase log, do not copy raw artifact tables, do not output the data-source/evidence-table index because the system will generate it, and do not repeat raw SQL. When evidence is abundant, prioritize the key evidence chain, structures required by the scene contract, and the highest-priority root causes.
16
+ Prioritize completeness. Use compact aggregation tables where helpful; do not expand into a phase-by-phase log, do not copy raw artifact tables, do not output the data-source/evidence-table index because the system will generate it, and do not repeat raw SQL. When evidence is abundant, prioritize the key evidence chain, structures required by the scene contract, and the highest-priority root causes; do not omit key conclusions or evidence just to shorten the report.
@@ -8,7 +8,9 @@
8
8
  报告必须包含:综合结论、关键证据链、根因拆解、已排除因素、优化建议、置信度/限制。
9
9
 
10
10
  必须继续遵守本轮场景策略、Final Report Contract 和最后一个 next_phase_reminder 的输出约束。若场景策略或契约要求根因分布、代表样本、阶段耗时拆分、双受众建议、架构分支判断或其他专属结构,最终报告必须保留这些结构,不能降级为短摘要。
11
+ 如果 Final Report Contract 给出了必检项名称,优先用同名小节或清晰标签呈现,例如“阶段耗时分解”、“[App层]”、“[系统/平台层]”,避免只把契约内容隐含在叙述里。
12
+ 先输出 Final Report Contract 要求的必需结构,再输出长树状图、附录或扩展说明;不要把必需的优化建议、分层建议、限制说明放在长代码块或长树之后,以免报告中途截断时缺失关键结论。
11
13
 
12
14
  不要只复述阶段摘要;必须把已采集到的具体数值和证据串成可读结论。
13
15
 
14
- 长度目标:约 2500-3500 个中文字符。可以用小型聚合表压缩信息;不要展开逐阶段流水账,不要复制 artifact 原表,不要重复 SQL 原文,不要输出“数据来源索引/证据表索引”(系统会自动生成)。若证据很多,优先保留关键证据链、场景契约要求的结构和最高优先级根因。
16
+ 完整性优先。可以用小型聚合表压缩信息;不要展开逐阶段流水账,不要复制 artifact 原表,不要重复 SQL 原文,不要输出“数据来源索引/证据表索引”(系统会自动生成)。若证据很多,优先保留关键证据链、场景契约要求的结构和最高优先级根因,不要为了压缩长度裁剪关键结论或证据。
@@ -84,7 +84,7 @@ graph LR
84
84
  ```
85
85
 
86
86
  ### 结论结构
87
- 结论必须完整但克制:优先输出能支撑决策的证据链,避免把已经展示过的大表逐行搬进最终报告。中文目标长度控制在约 2500-3500 字符,英文目标长度控制在约 1200-1800 words;如果证据很多,用聚合表和证据索引压缩,不要生成会在 token 上限处截断的超长报告。
87
+ 结论必须完整但克制:优先输出能支撑决策的证据链,避免把已经展示过的大表逐行搬进最终报告。如果证据很多,用聚合表和证据索引压缩,降低重复信息密度;不要为了压缩长度裁剪关键结论或证据,也不要生成会在 token 上限处截断的超长报告。
88
88
 
89
89
  1. **概览**: 一句话总结性能状况。如果架构检测置信度 < 80%,在概览中标注(如"⚠️ 架构检测置信度 50%,分析策略可能不完全匹配"),帮助用户理解分析的局限性
90
90
  2. **关键发现**: 按严重程度排列的发现列表(含根因推理链 + 📚 背景知识)
@@ -0,0 +1,18 @@
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
+ 你是 Android Perfetto trace 的场景还原复核器。请检查下面的 Smart 场景时间线是否存在明显的拆分、合并、类型或归因问题。
6
+
7
+ 只能基于输入证据判断,不要创造没有证据的场景。不要输出长报告。
8
+
9
+ 请只输出 JSON,格式:{"status":"passed|needs_review","summary":"一句中文复核意见"}。
10
+
11
+ deterministic_summary:
12
+ {{deterministicSummary}}
13
+
14
+ deterministic_issues:
15
+ {{deterministicIssues}}
16
+
17
+ scenes:
18
+ {{scenes}}
@@ -107,7 +107,7 @@ phase_hints:
107
107
  critical: false
108
108
  - id: conclusion
109
109
  keywords: ['结论', 'conclusion', '输出', 'output', '报告', 'report', '总结']
110
- constraints: '输出必须包含:全帧根因分布表(按 reason_code 聚合)+ 代表帧分析(含四象限+频率+根因推理链)+ 按优先级排序的优化建议。每个 CRITICAL/HIGH 必须有量化证据+因果链。'
110
+ constraints: '输出必须包含:全帧根因分布表(按 reason_code 聚合)+ 代表帧分析(含四象限+频率+根因推理链)+ 按优先级排序的优化建议。每个 CRITICAL/HIGH 必须有量化证据+因果链。若深钻证据纠正了 batch reason_code(例如 lock_binder_wait 但 binder_overlap_ms=0,render_slices_json 指向 cache_miss/makePipeline/shader 编译),最终结论必须使用纠正后的根因命名,并明确标注原 reason_code 为误分类。'
111
111
  critical_tools: []
112
112
  critical: false
113
113
 
@@ -347,6 +347,10 @@ Phase 1 的 `batch_frame_root_cause` 已包含每帧的**完整统计数据**(
347
347
  - **reason_code 为 unknown 且帧数 >5%**:必须对至少 1 帧调用 jank_frame_detail 获取更多线索,不能在分布表中仅标记"未分类"就跳过
348
348
  - reason_code 与实际数据矛盾时(如 `lock_binder_wait` 但 Binder 耗时 0ms):应在结论中标注可能的误分类原因
349
349
 
350
+ 如果深钻结果已给出更具体的根因,不要在最终报告继续把原始 `reason_code` 当作根因名称。典型例子:
351
+ - `lock_binder_wait` 但 `binder_overlap_ms=0`,且 `render_slices_json` 出现 `cache_miss: makePipeline` / shader 编译 / Vulkan finish frame / `postAndWait`,最终根因应写成 **shader_compile + sync_wait** 或等价机制,并说明 `lock_binder_wait` 是批量分类误判。
352
+ - `workload_heavy` 但 `main_slices_json` 明确指向应用自定义方法,最终根因应写具体方法名和所处阶段,例如 `CustomScroll_longFrameLoad` 在 ANIMATION 回调同步执行,而不是只写 "workload_heavy"。
353
+
350
354
  `frame_blocking_calls` 是 Phase 1.9 的帧内阻塞证据补充,不占 `jank_frame_detail` 的 2 帧上限。遇到 Binder/IO/futex/锁相关根因时,优先用它确认阻塞调用是否真的与掉帧帧重叠。
351
355
 
352
356
  ```