@gracker/smartperfetto 1.0.20 → 1.0.22
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.
- package/dist/agent/config/domainManifest.d.ts +5 -3
- package/dist/agent/config/domainManifest.d.ts.map +1 -1
- package/dist/agent/config/domainManifest.js +120 -5
- package/dist/agent/config/domainManifest.js.map +1 -1
- package/dist/agent/core/orchestratorTypes.d.ts +5 -0
- package/dist/agent/core/orchestratorTypes.d.ts.map +1 -1
- package/dist/agent/core/orchestratorTypes.js.map +1 -1
- package/dist/agent/scene/buildSmartChatReport.d.ts +13 -0
- package/dist/agent/scene/buildSmartChatReport.d.ts.map +1 -0
- package/dist/agent/scene/buildSmartChatReport.js +333 -0
- package/dist/agent/scene/buildSmartChatReport.js.map +1 -0
- package/dist/agent/scene/sceneAnalysisJobRunner.d.ts +8 -4
- package/dist/agent/scene/sceneAnalysisJobRunner.d.ts.map +1 -1
- package/dist/agent/scene/sceneAnalysisJobRunner.js +78 -3
- package/dist/agent/scene/sceneAnalysisJobRunner.js.map +1 -1
- package/dist/agent/scene/sceneIntervalBuilder.d.ts +14 -5
- package/dist/agent/scene/sceneIntervalBuilder.d.ts.map +1 -1
- package/dist/agent/scene/sceneIntervalBuilder.js +578 -1
- package/dist/agent/scene/sceneIntervalBuilder.js.map +1 -1
- package/dist/agent/scene/sceneStage1Verifier.d.ts +8 -0
- package/dist/agent/scene/sceneStage1Verifier.d.ts.map +1 -0
- package/dist/agent/scene/sceneStage1Verifier.js +245 -0
- package/dist/agent/scene/sceneStage1Verifier.js.map +1 -0
- package/dist/agent/scene/sceneStoryService.d.ts +20 -2
- package/dist/agent/scene/sceneStoryService.d.ts.map +1 -1
- package/dist/agent/scene/sceneStoryService.js +238 -25
- package/dist/agent/scene/sceneStoryService.js.map +1 -1
- package/dist/agent/scene/smartCancelBridge.d.ts +13 -0
- package/dist/agent/scene/smartCancelBridge.d.ts.map +1 -0
- package/dist/agent/scene/smartCancelBridge.js +44 -0
- package/dist/agent/scene/smartCancelBridge.js.map +1 -0
- package/dist/agent/scene/smartDeepDiveDispatch.d.ts +15 -0
- package/dist/agent/scene/smartDeepDiveDispatch.d.ts.map +1 -0
- package/dist/agent/scene/smartDeepDiveDispatch.js +170 -0
- package/dist/agent/scene/smartDeepDiveDispatch.js.map +1 -0
- package/dist/agent/scene/types.d.ts +97 -6
- package/dist/agent/scene/types.d.ts.map +1 -1
- package/dist/agent/types.d.ts +1 -1
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/agentv3/claudeMcpServer.d.ts.map +1 -1
- package/dist/agentv3/claudeMcpServer.js +3 -2
- package/dist/agentv3/claudeMcpServer.js.map +1 -1
- package/dist/agentv3/claudeSystemPrompt.d.ts.map +1 -1
- package/dist/agentv3/claudeSystemPrompt.js +8 -0
- package/dist/agentv3/claudeSystemPrompt.js.map +1 -1
- package/dist/agentv3/queryComplexityClassifier.d.ts +1 -1
- package/dist/agentv3/queryComplexityClassifier.d.ts.map +1 -1
- package/dist/agentv3/queryComplexityClassifier.js +20 -7
- package/dist/agentv3/queryComplexityClassifier.js.map +1 -1
- package/dist/agentv3/strategyLoader.d.ts +3 -0
- package/dist/agentv3/strategyLoader.d.ts.map +1 -1
- package/dist/agentv3/strategyLoader.js +17 -4
- package/dist/agentv3/strategyLoader.js.map +1 -1
- package/dist/agentv3/types.d.ts +5 -1
- package/dist/agentv3/types.d.ts.map +1 -1
- package/dist/agentv3/types.js.map +1 -1
- package/dist/config/index.d.ts +12 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +6 -0
- package/dist/config/index.js.map +1 -1
- package/dist/routes/agent/finalizeAgentDrivenSession.d.ts +67 -0
- package/dist/routes/agent/finalizeAgentDrivenSession.d.ts.map +1 -0
- package/dist/routes/agent/finalizeAgentDrivenSession.js +103 -0
- package/dist/routes/agent/finalizeAgentDrivenSession.js.map +1 -0
- package/dist/routes/agent/normalizeAnalyzeOptions.d.ts +42 -0
- package/dist/routes/agent/normalizeAnalyzeOptions.d.ts.map +1 -0
- package/dist/routes/agent/normalizeAnalyzeOptions.js +185 -0
- package/dist/routes/agent/normalizeAnalyzeOptions.js.map +1 -0
- package/dist/routes/agentRoutes.d.ts.map +1 -1
- package/dist/routes/agentRoutes.js +285 -125
- package/dist/routes/agentRoutes.js.map +1 -1
- package/dist/scripts/verifyAgentSseScrolling.js +131 -8
- package/dist/scripts/verifyAgentSseScrolling.js.map +1 -1
- package/dist/services/sceneReport/sceneJobArtifactStore.d.ts +22 -0
- package/dist/services/sceneReport/sceneJobArtifactStore.d.ts.map +1 -0
- package/dist/services/sceneReport/sceneJobArtifactStore.js +65 -0
- package/dist/services/sceneReport/sceneJobArtifactStore.js.map +1 -0
- package/dist/services/sceneReport/sceneReportMemoryCache.d.ts +5 -3
- package/dist/services/sceneReport/sceneReportMemoryCache.d.ts.map +1 -1
- package/dist/services/sceneReport/sceneReportMemoryCache.js +15 -10
- package/dist/services/sceneReport/sceneReportMemoryCache.js.map +1 -1
- package/dist/services/sceneReport/sceneReportStore.d.ts +9 -4
- package/dist/services/sceneReport/sceneReportStore.d.ts.map +1 -1
- package/dist/services/sceneReport/sceneReportStore.js +27 -7
- package/dist/services/sceneReport/sceneReportStore.js.map +1 -1
- package/dist/services/traceProcessor/sqlSemaphore.d.ts +16 -0
- package/dist/services/traceProcessor/sqlSemaphore.d.ts.map +1 -0
- package/dist/services/traceProcessor/sqlSemaphore.js +63 -0
- package/dist/services/traceProcessor/sqlSemaphore.js.map +1 -0
- package/dist/types/dataContract.d.ts +1 -1
- package/dist/types/dataContract.d.ts.map +1 -1
- package/dist/types/dataContract.js +2 -0
- package/dist/types/dataContract.js.map +1 -1
- package/package.json +1 -1
- package/skills/README.md +13 -5
- package/skills/composite/device_state_snapshot.skill.yaml +204 -0
- package/skills/composite/scene_reconstruction.skill.yaml +5 -1
- package/skills/composite/selection_range_cpu_sched_summary.skill.yaml +428 -0
- package/strategies/scene-reconstruction-verifier.template.md +18 -0
- package/strategies/scrolling.strategy.md +5 -1
- package/strategies/selection-area.template.md +24 -9
- package/strategies/smart.strategy.md +53 -0
- package/skills/atomic/device_state_snapshot.skill.yaml +0 -171
|
@@ -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]
|
|
@@ -0,0 +1,428 @@
|
|
|
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
|
+
name: selection_range_cpu_sched_summary
|
|
6
|
+
version: "1.0"
|
|
7
|
+
type: composite
|
|
8
|
+
category: kernel
|
|
9
|
+
tier: B
|
|
10
|
+
|
|
11
|
+
meta:
|
|
12
|
+
display_name: "选区 CPU 调度与频率摘要"
|
|
13
|
+
description: "面向用户选区/可见窗口的快速 CPU 摆核、Running 排名、四象限和频率分布分析"
|
|
14
|
+
icon: "speed"
|
|
15
|
+
tags: [selection, range, cpu, sched, frequency, quadrant, migration, quick]
|
|
16
|
+
|
|
17
|
+
triggers:
|
|
18
|
+
keywords:
|
|
19
|
+
zh: [选区, 这一段, 这段, 摆核, 核心摆放, 平均频率, 频率分布, Running 排名, 四象限]
|
|
20
|
+
en: [selection range, current window, cpu placement, core placement, average frequency, frequency distribution, running ranking, quadrant]
|
|
21
|
+
patterns:
|
|
22
|
+
- ".*(选区|这段|这一段).*(CPU|摆核|核心|频率|Running|四象限).*"
|
|
23
|
+
- ".*(selected|current).*(range|window).*(cpu|core|frequency|running|quadrant).*"
|
|
24
|
+
|
|
25
|
+
prerequisites:
|
|
26
|
+
required_tables:
|
|
27
|
+
- thread_state
|
|
28
|
+
- thread
|
|
29
|
+
- process
|
|
30
|
+
modules:
|
|
31
|
+
- sched
|
|
32
|
+
- linux.cpu.frequency
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
inputs:
|
|
36
|
+
- name: start_ts
|
|
37
|
+
type: timestamp
|
|
38
|
+
required: true
|
|
39
|
+
description: "选区起始时间戳(ns)"
|
|
40
|
+
- name: end_ts
|
|
41
|
+
type: timestamp
|
|
42
|
+
required: true
|
|
43
|
+
description: "选区结束时间戳(ns)"
|
|
44
|
+
- name: package
|
|
45
|
+
type: string
|
|
46
|
+
required: false
|
|
47
|
+
description: "可选进程名过滤,支持 GLOB 前缀匹配"
|
|
48
|
+
- name: thread_name
|
|
49
|
+
type: string
|
|
50
|
+
required: false
|
|
51
|
+
description: "可选线程名包含匹配"
|
|
52
|
+
- name: top_k
|
|
53
|
+
type: number
|
|
54
|
+
required: false
|
|
55
|
+
description: "线程/进程排名返回数量"
|
|
56
|
+
- name: freq_bucket_mhz
|
|
57
|
+
type: number
|
|
58
|
+
required: false
|
|
59
|
+
description: "频率分布桶大小,单位 MHz"
|
|
60
|
+
|
|
61
|
+
steps:
|
|
62
|
+
- id: init_cpu_topology
|
|
63
|
+
type: skill
|
|
64
|
+
name: "初始化 CPU 拓扑"
|
|
65
|
+
skill: cpu_topology_view
|
|
66
|
+
params:
|
|
67
|
+
start_ts: "${start_ts}"
|
|
68
|
+
end_ts: "${end_ts}"
|
|
69
|
+
display:
|
|
70
|
+
level: hidden
|
|
71
|
+
optional: true
|
|
72
|
+
|
|
73
|
+
- id: running_thread_quadrants
|
|
74
|
+
type: atomic
|
|
75
|
+
name: "Running 线程四象限与摆核"
|
|
76
|
+
optional: true
|
|
77
|
+
display:
|
|
78
|
+
level: key
|
|
79
|
+
layer: overview
|
|
80
|
+
title: "选区 Running 线程四象限"
|
|
81
|
+
columns:
|
|
82
|
+
- name: thread_name
|
|
83
|
+
label: "线程"
|
|
84
|
+
type: string
|
|
85
|
+
- name: process_name
|
|
86
|
+
label: "进程"
|
|
87
|
+
type: string
|
|
88
|
+
- name: tid
|
|
89
|
+
label: "TID"
|
|
90
|
+
type: number
|
|
91
|
+
- name: total_cpu_ms
|
|
92
|
+
label: "CPU 时间"
|
|
93
|
+
type: duration
|
|
94
|
+
format: duration_ms
|
|
95
|
+
unit: ms
|
|
96
|
+
- name: q1_perf_running_ms
|
|
97
|
+
label: "Q1 性能核运行"
|
|
98
|
+
type: duration
|
|
99
|
+
format: duration_ms
|
|
100
|
+
unit: ms
|
|
101
|
+
- name: q2_little_running_ms
|
|
102
|
+
label: "Q2 小核运行"
|
|
103
|
+
type: duration
|
|
104
|
+
format: duration_ms
|
|
105
|
+
unit: ms
|
|
106
|
+
- name: q3_runnable_ms
|
|
107
|
+
label: "Q3 等待调度"
|
|
108
|
+
type: duration
|
|
109
|
+
format: duration_ms
|
|
110
|
+
unit: ms
|
|
111
|
+
- name: q4a_io_blocked_ms
|
|
112
|
+
label: "Q4a IO 阻塞"
|
|
113
|
+
type: duration
|
|
114
|
+
format: duration_ms
|
|
115
|
+
unit: ms
|
|
116
|
+
- name: q4b_sleeping_ms
|
|
117
|
+
label: "Q4b 睡眠等待"
|
|
118
|
+
type: duration
|
|
119
|
+
format: duration_ms
|
|
120
|
+
unit: ms
|
|
121
|
+
- name: perf_core_pct
|
|
122
|
+
label: "性能核占比"
|
|
123
|
+
type: percentage
|
|
124
|
+
format: percentage
|
|
125
|
+
- name: running_cpus
|
|
126
|
+
label: "运行 CPU"
|
|
127
|
+
type: string
|
|
128
|
+
- name: running_core_types
|
|
129
|
+
label: "核心类型"
|
|
130
|
+
type: string
|
|
131
|
+
- name: migrations
|
|
132
|
+
label: "核迁移"
|
|
133
|
+
type: number
|
|
134
|
+
- name: cross_cluster_migrations
|
|
135
|
+
label: "跨簇迁移"
|
|
136
|
+
type: number
|
|
137
|
+
sql: |
|
|
138
|
+
WITH
|
|
139
|
+
target_threads AS (
|
|
140
|
+
SELECT
|
|
141
|
+
t.utid,
|
|
142
|
+
t.tid,
|
|
143
|
+
COALESCE(t.name, '<unknown>') AS thread_name,
|
|
144
|
+
p.upid,
|
|
145
|
+
p.pid,
|
|
146
|
+
COALESCE(p.name, '<unknown>') AS process_name
|
|
147
|
+
FROM thread t
|
|
148
|
+
LEFT JOIN process p ON t.upid = p.upid
|
|
149
|
+
WHERE ('${package|}' = '' OR COALESCE(p.name, '') GLOB '${package|}*')
|
|
150
|
+
AND ('${thread_name|}' = '' OR COALESCE(t.name, '') GLOB '*${thread_name|}*')
|
|
151
|
+
),
|
|
152
|
+
states AS (
|
|
153
|
+
SELECT
|
|
154
|
+
tt.utid,
|
|
155
|
+
tt.tid,
|
|
156
|
+
tt.thread_name,
|
|
157
|
+
tt.process_name,
|
|
158
|
+
ts.ts,
|
|
159
|
+
ts.state,
|
|
160
|
+
ts.cpu,
|
|
161
|
+
COALESCE(ct.core_type, 'unknown') AS core_type,
|
|
162
|
+
MIN(ts.ts + ts.dur, ${end_ts}) - MAX(ts.ts, ${start_ts}) AS clipped_dur
|
|
163
|
+
FROM thread_state ts
|
|
164
|
+
JOIN target_threads tt ON ts.utid = tt.utid
|
|
165
|
+
LEFT JOIN _cpu_topology ct ON ts.cpu = ct.cpu_id
|
|
166
|
+
WHERE ts.ts < ${end_ts}
|
|
167
|
+
AND ts.ts + ts.dur > ${start_ts}
|
|
168
|
+
AND ts.dur > 0
|
|
169
|
+
),
|
|
170
|
+
running_events AS (
|
|
171
|
+
SELECT
|
|
172
|
+
utid,
|
|
173
|
+
ts,
|
|
174
|
+
cpu,
|
|
175
|
+
core_type,
|
|
176
|
+
LAG(cpu) OVER (PARTITION BY utid ORDER BY ts) AS prev_cpu,
|
|
177
|
+
LAG(core_type) OVER (PARTITION BY utid ORDER BY ts) AS prev_core_type
|
|
178
|
+
FROM states
|
|
179
|
+
WHERE state = 'Running' AND clipped_dur > 0
|
|
180
|
+
),
|
|
181
|
+
migrations AS (
|
|
182
|
+
SELECT
|
|
183
|
+
utid,
|
|
184
|
+
SUM(CASE WHEN prev_cpu IS NOT NULL AND cpu != prev_cpu THEN 1 ELSE 0 END) AS migrations,
|
|
185
|
+
SUM(CASE WHEN prev_cpu IS NOT NULL AND cpu != prev_cpu AND core_type != prev_core_type THEN 1 ELSE 0 END) AS cross_cluster_migrations
|
|
186
|
+
FROM running_events
|
|
187
|
+
GROUP BY utid
|
|
188
|
+
)
|
|
189
|
+
SELECT
|
|
190
|
+
s.thread_name,
|
|
191
|
+
s.process_name,
|
|
192
|
+
s.tid,
|
|
193
|
+
ROUND(SUM(CASE WHEN s.state = 'Running' THEN s.clipped_dur ELSE 0 END) / 1e6, 2) AS total_cpu_ms,
|
|
194
|
+
ROUND(SUM(CASE WHEN s.state = 'Running' AND s.core_type IN ('prime', 'big', 'medium') THEN s.clipped_dur ELSE 0 END) / 1e6, 2) AS q1_perf_running_ms,
|
|
195
|
+
ROUND(SUM(CASE WHEN s.state = 'Running' AND s.core_type = 'little' THEN s.clipped_dur ELSE 0 END) / 1e6, 2) AS q2_little_running_ms,
|
|
196
|
+
ROUND(SUM(CASE WHEN s.state IN ('R', 'R+') THEN s.clipped_dur ELSE 0 END) / 1e6, 2) AS q3_runnable_ms,
|
|
197
|
+
ROUND(SUM(CASE WHEN s.state IN ('D', 'DK') THEN s.clipped_dur ELSE 0 END) / 1e6, 2) AS q4a_io_blocked_ms,
|
|
198
|
+
ROUND(SUM(CASE WHEN s.state IN ('S', 'I') THEN s.clipped_dur ELSE 0 END) / 1e6, 2) AS q4b_sleeping_ms,
|
|
199
|
+
ROUND(100.0 * SUM(CASE WHEN s.state = 'Running' AND s.core_type IN ('prime', 'big', 'medium') THEN s.clipped_dur ELSE 0 END)
|
|
200
|
+
/ NULLIF(SUM(CASE WHEN s.state = 'Running' THEN s.clipped_dur ELSE 0 END), 0), 1) AS perf_core_pct,
|
|
201
|
+
GROUP_CONCAT(DISTINCT CASE WHEN s.state = 'Running' THEN s.cpu END) AS running_cpus,
|
|
202
|
+
GROUP_CONCAT(DISTINCT CASE WHEN s.state = 'Running' THEN s.core_type END) AS running_core_types,
|
|
203
|
+
COALESCE(m.migrations, 0) AS migrations,
|
|
204
|
+
COALESCE(m.cross_cluster_migrations, 0) AS cross_cluster_migrations
|
|
205
|
+
FROM states s
|
|
206
|
+
LEFT JOIN migrations m ON s.utid = m.utid
|
|
207
|
+
WHERE s.clipped_dur > 0
|
|
208
|
+
GROUP BY s.utid
|
|
209
|
+
HAVING total_cpu_ms > 0
|
|
210
|
+
ORDER BY total_cpu_ms DESC
|
|
211
|
+
LIMIT ${top_k|20}
|
|
212
|
+
save_as: running_thread_quadrants
|
|
213
|
+
|
|
214
|
+
- id: running_process_ranking
|
|
215
|
+
type: atomic
|
|
216
|
+
name: "Running 进程排名"
|
|
217
|
+
optional: true
|
|
218
|
+
display:
|
|
219
|
+
level: summary
|
|
220
|
+
layer: list
|
|
221
|
+
title: "选区 Running 进程排名"
|
|
222
|
+
columns:
|
|
223
|
+
- name: process_name
|
|
224
|
+
label: "进程"
|
|
225
|
+
type: string
|
|
226
|
+
- name: pid
|
|
227
|
+
label: "PID"
|
|
228
|
+
type: number
|
|
229
|
+
- name: running_ms
|
|
230
|
+
label: "Running 时间"
|
|
231
|
+
type: duration
|
|
232
|
+
format: duration_ms
|
|
233
|
+
unit: ms
|
|
234
|
+
- name: thread_count
|
|
235
|
+
label: "线程数"
|
|
236
|
+
type: number
|
|
237
|
+
sql: |
|
|
238
|
+
SELECT
|
|
239
|
+
COALESCE(p.name, '<unknown>') AS process_name,
|
|
240
|
+
p.pid,
|
|
241
|
+
ROUND(SUM(MIN(ts.ts + ts.dur, ${end_ts}) - MAX(ts.ts, ${start_ts})) / 1e6, 2) AS running_ms,
|
|
242
|
+
COUNT(DISTINCT ts.utid) AS thread_count
|
|
243
|
+
FROM thread_state ts
|
|
244
|
+
JOIN thread t ON ts.utid = t.utid
|
|
245
|
+
LEFT JOIN process p ON t.upid = p.upid
|
|
246
|
+
WHERE ts.ts < ${end_ts}
|
|
247
|
+
AND ts.ts + ts.dur > ${start_ts}
|
|
248
|
+
AND ts.dur > 0
|
|
249
|
+
AND ts.state = 'Running'
|
|
250
|
+
AND ('${package|}' = '' OR COALESCE(p.name, '') GLOB '${package|}*')
|
|
251
|
+
AND ('${thread_name|}' = '' OR COALESCE(t.name, '') GLOB '*${thread_name|}*')
|
|
252
|
+
GROUP BY p.upid
|
|
253
|
+
ORDER BY running_ms DESC
|
|
254
|
+
LIMIT ${top_k|20}
|
|
255
|
+
save_as: running_process_ranking
|
|
256
|
+
|
|
257
|
+
- id: cpu_freq_by_core
|
|
258
|
+
type: atomic
|
|
259
|
+
name: "各核 duration-weighted 频率"
|
|
260
|
+
optional: true
|
|
261
|
+
display:
|
|
262
|
+
level: summary
|
|
263
|
+
layer: list
|
|
264
|
+
title: "选区各核平均频率"
|
|
265
|
+
columns:
|
|
266
|
+
- name: cpu
|
|
267
|
+
label: "CPU"
|
|
268
|
+
type: number
|
|
269
|
+
- name: core_type
|
|
270
|
+
label: "核心类型"
|
|
271
|
+
type: string
|
|
272
|
+
- name: avg_freq_mhz
|
|
273
|
+
label: "平均频率"
|
|
274
|
+
type: number
|
|
275
|
+
- name: min_freq_mhz
|
|
276
|
+
label: "最低频率"
|
|
277
|
+
type: number
|
|
278
|
+
- name: max_freq_mhz
|
|
279
|
+
label: "最高频率"
|
|
280
|
+
type: number
|
|
281
|
+
- name: covered_ms
|
|
282
|
+
label: "覆盖时长"
|
|
283
|
+
type: duration
|
|
284
|
+
format: duration_ms
|
|
285
|
+
unit: ms
|
|
286
|
+
sql: |
|
|
287
|
+
WITH
|
|
288
|
+
cpu_tracks AS (
|
|
289
|
+
SELECT id, cpu
|
|
290
|
+
FROM cpu_counter_track
|
|
291
|
+
WHERE name = 'cpufreq' AND cpu IS NOT NULL
|
|
292
|
+
),
|
|
293
|
+
freq_points AS (
|
|
294
|
+
SELECT
|
|
295
|
+
t.cpu,
|
|
296
|
+
${start_ts} AS ts,
|
|
297
|
+
(
|
|
298
|
+
SELECT c2.value
|
|
299
|
+
FROM counter c2
|
|
300
|
+
WHERE c2.track_id = t.id AND c2.ts <= ${start_ts}
|
|
301
|
+
ORDER BY c2.ts DESC
|
|
302
|
+
LIMIT 1
|
|
303
|
+
) AS freq_khz,
|
|
304
|
+
0 AS source_order
|
|
305
|
+
FROM cpu_tracks t
|
|
306
|
+
UNION ALL
|
|
307
|
+
SELECT t.cpu, c.ts, c.value AS freq_khz, 1 AS source_order
|
|
308
|
+
FROM counter c
|
|
309
|
+
JOIN cpu_tracks t ON c.track_id = t.id
|
|
310
|
+
WHERE c.ts >= ${start_ts} AND c.ts < ${end_ts}
|
|
311
|
+
),
|
|
312
|
+
freq_spans AS (
|
|
313
|
+
SELECT
|
|
314
|
+
cpu,
|
|
315
|
+
freq_khz,
|
|
316
|
+
ts,
|
|
317
|
+
LEAD(ts, 1, ${end_ts}) OVER (PARTITION BY cpu ORDER BY ts, source_order) AS next_ts
|
|
318
|
+
FROM freq_points
|
|
319
|
+
WHERE freq_khz IS NOT NULL AND freq_khz > 0
|
|
320
|
+
),
|
|
321
|
+
clipped AS (
|
|
322
|
+
SELECT
|
|
323
|
+
cpu,
|
|
324
|
+
freq_khz,
|
|
325
|
+
MIN(next_ts, ${end_ts}) - MAX(ts, ${start_ts}) AS dur_ns
|
|
326
|
+
FROM freq_spans
|
|
327
|
+
WHERE ts < ${end_ts} AND next_ts > ${start_ts}
|
|
328
|
+
)
|
|
329
|
+
SELECT
|
|
330
|
+
c.cpu,
|
|
331
|
+
COALESCE(ct.core_type, 'unknown') AS core_type,
|
|
332
|
+
ROUND(SUM(c.freq_khz * c.dur_ns) / NULLIF(SUM(c.dur_ns), 0) / 1000, 0) AS avg_freq_mhz,
|
|
333
|
+
ROUND(MIN(c.freq_khz) / 1000, 0) AS min_freq_mhz,
|
|
334
|
+
ROUND(MAX(c.freq_khz) / 1000, 0) AS max_freq_mhz,
|
|
335
|
+
ROUND(SUM(c.dur_ns) / 1e6, 2) AS covered_ms
|
|
336
|
+
FROM clipped c
|
|
337
|
+
LEFT JOIN _cpu_topology ct ON c.cpu = ct.cpu_id
|
|
338
|
+
WHERE c.dur_ns > 0
|
|
339
|
+
GROUP BY c.cpu
|
|
340
|
+
ORDER BY c.cpu
|
|
341
|
+
save_as: cpu_freq_by_core
|
|
342
|
+
|
|
343
|
+
- id: cpu_freq_distribution
|
|
344
|
+
type: atomic
|
|
345
|
+
name: "各核频率分布"
|
|
346
|
+
optional: true
|
|
347
|
+
display:
|
|
348
|
+
level: detail
|
|
349
|
+
layer: deep
|
|
350
|
+
title: "选区各核频率分布"
|
|
351
|
+
columns:
|
|
352
|
+
- name: cpu
|
|
353
|
+
label: "CPU"
|
|
354
|
+
type: number
|
|
355
|
+
- name: core_type
|
|
356
|
+
label: "核心类型"
|
|
357
|
+
type: string
|
|
358
|
+
- name: freq_mhz_bucket
|
|
359
|
+
label: "频率桶"
|
|
360
|
+
type: number
|
|
361
|
+
- name: duration_ms
|
|
362
|
+
label: "时长"
|
|
363
|
+
type: duration
|
|
364
|
+
format: duration_ms
|
|
365
|
+
unit: ms
|
|
366
|
+
- name: pct_of_range
|
|
367
|
+
label: "区间占比"
|
|
368
|
+
type: percentage
|
|
369
|
+
format: percentage
|
|
370
|
+
sql: |
|
|
371
|
+
WITH
|
|
372
|
+
cpu_tracks AS (
|
|
373
|
+
SELECT id, cpu
|
|
374
|
+
FROM cpu_counter_track
|
|
375
|
+
WHERE name = 'cpufreq' AND cpu IS NOT NULL
|
|
376
|
+
),
|
|
377
|
+
freq_points AS (
|
|
378
|
+
SELECT
|
|
379
|
+
t.cpu,
|
|
380
|
+
${start_ts} AS ts,
|
|
381
|
+
(
|
|
382
|
+
SELECT c2.value
|
|
383
|
+
FROM counter c2
|
|
384
|
+
WHERE c2.track_id = t.id AND c2.ts <= ${start_ts}
|
|
385
|
+
ORDER BY c2.ts DESC
|
|
386
|
+
LIMIT 1
|
|
387
|
+
) AS freq_khz,
|
|
388
|
+
0 AS source_order
|
|
389
|
+
FROM cpu_tracks t
|
|
390
|
+
UNION ALL
|
|
391
|
+
SELECT t.cpu, c.ts, c.value AS freq_khz, 1 AS source_order
|
|
392
|
+
FROM counter c
|
|
393
|
+
JOIN cpu_tracks t ON c.track_id = t.id
|
|
394
|
+
WHERE c.ts >= ${start_ts} AND c.ts < ${end_ts}
|
|
395
|
+
),
|
|
396
|
+
freq_spans AS (
|
|
397
|
+
SELECT
|
|
398
|
+
cpu,
|
|
399
|
+
freq_khz,
|
|
400
|
+
ts,
|
|
401
|
+
LEAD(ts, 1, ${end_ts}) OVER (PARTITION BY cpu ORDER BY ts, source_order) AS next_ts
|
|
402
|
+
FROM freq_points
|
|
403
|
+
WHERE freq_khz IS NOT NULL AND freq_khz > 0
|
|
404
|
+
),
|
|
405
|
+
clipped AS (
|
|
406
|
+
SELECT
|
|
407
|
+
cpu,
|
|
408
|
+
CAST(ROUND(freq_khz / (${freq_bucket_mhz|100} * 1000.0)) * ${freq_bucket_mhz|100} AS INTEGER) AS freq_mhz_bucket,
|
|
409
|
+
MIN(next_ts, ${end_ts}) - MAX(ts, ${start_ts}) AS dur_ns
|
|
410
|
+
FROM freq_spans
|
|
411
|
+
WHERE ts < ${end_ts} AND next_ts > ${start_ts}
|
|
412
|
+
)
|
|
413
|
+
SELECT
|
|
414
|
+
c.cpu,
|
|
415
|
+
COALESCE(ct.core_type, 'unknown') AS core_type,
|
|
416
|
+
c.freq_mhz_bucket,
|
|
417
|
+
ROUND(SUM(c.dur_ns) / 1e6, 2) AS duration_ms,
|
|
418
|
+
ROUND(100.0 * SUM(c.dur_ns) / NULLIF(${end_ts} - ${start_ts}, 0), 1) AS pct_of_range
|
|
419
|
+
FROM clipped c
|
|
420
|
+
LEFT JOIN _cpu_topology ct ON c.cpu = ct.cpu_id
|
|
421
|
+
WHERE c.dur_ns > 0
|
|
422
|
+
GROUP BY c.cpu, c.freq_mhz_bucket
|
|
423
|
+
ORDER BY c.cpu, duration_ms DESC
|
|
424
|
+
LIMIT 100
|
|
425
|
+
save_as: cpu_freq_distribution
|
|
426
|
+
|
|
427
|
+
output:
|
|
428
|
+
format: structured
|
|
@@ -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
|
```
|