@gracker/smartperfetto 1.0.21 → 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/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/types.d.ts +5 -1
- package/dist/agentv3/types.d.ts.map +1 -1
- package/dist/agentv3/types.js.map +1 -1
- package/package.json +1 -1
- package/skills/composite/selection_range_cpu_sched_summary.skill.yaml +428 -0
- package/strategies/selection-area.template.md +24 -9
|
@@ -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
|
|
@@ -7,28 +7,40 @@
|
|
|
7
7
|
{{durationMs}} - Duration in ms, e.g. "19.30"
|
|
8
8
|
{{trackCount}} - Number of selected tracks (number or "未知")
|
|
9
9
|
{{trackSummary}} - Pre-formatted track list grouped by process (string, may be empty)
|
|
10
|
+
{{sourceLabel}} - Selection source label, e.g. Perfetto area/time-range selection or current visible timeline window
|
|
10
11
|
-->
|
|
11
12
|
## 用户选区上下文
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
用户当前问题带有一个明确的时间范围 scope(来源: {{sourceLabel}}):
|
|
14
15
|
- **起始时间:** {{startNs}} ns
|
|
15
16
|
- **结束时间:** {{endNs}} ns
|
|
16
17
|
- **持续时间:** {{durationMs}} ms
|
|
17
18
|
- **选中 Track 数:** {{trackCount}}{{trackSummary}}
|
|
18
19
|
|
|
19
20
|
**分析约束:**
|
|
20
|
-
-
|
|
21
|
+
- 选区/窗口只定义时间和可选 track scope;用户真正要看的指标由用户问题决定,不要用固定 pattern 代替意图判断
|
|
22
|
+
- SQL 查询必须限制在上述时间范围。对 `slice` / `thread_state` / `sched_slice` 这类带持续时间的表,优先使用 overlap clipping:`ts < {{endNs}} AND ts + dur > {{startNs}}`,并用 `MIN(ts + dur, {{endNs}}) - MAX(ts, {{startNs}})` 计算区间内贡献
|
|
21
23
|
- 上述时间戳是 trace_processor 原始时间戳(ns),可直接用于 slice/thread_state/sched 等所有表的 ts 列
|
|
22
24
|
- 分析结论应聚焦于用户选择的这段区间
|
|
23
25
|
- 如果需要全局上下文(如整体 VSync 周期)来做对比,可以额外查询,但核心分析范围是选区内
|
|
24
|
-
- 当用户提到"选中的区间"/"这一段"/"选择的范围"/"marked area"等,指的就是上述时间窗口
|
|
26
|
+
- 当用户提到"选中的区间"/"这一段"/"选择的范围"/"marked area"/"current window"等,指的就是上述时间窗口
|
|
27
|
+
- 如果前端请求附带了 `traceContext` datasets,优先复用其中已经预取的选区数据;缺少用户所问的指标时,再调用工具补齐
|
|
25
28
|
|
|
26
|
-
|
|
29
|
+
**快速路径建议:**
|
|
30
|
+
- 对 CPU 摆核、task/core placement、各核平均频率、频率分布、Running task/process 排名、Running 四象限这类选区问题,优先调用:
|
|
31
|
+
`invoke_skill(skillId="selection_range_cpu_sched_summary", params={start_ts: {{startNs}}, end_ts: {{endNs}}})`
|
|
32
|
+
- 如果用户限定某个进程或线程,把它作为 `package` 或 `thread_name` 参数传给该 Skill;没有限定时保持未过滤,让结果按数据排序
|
|
33
|
+
- 如果用户只问一个 Skill 未覆盖的小指标,可以直接 `execute_sql`,但仍必须使用上述时间范围和 overlap clipping
|
|
34
|
+
|
|
35
|
+
**选区内常用 SQL 查询模板(需要自定义 SQL 时使用):**
|
|
27
36
|
```sql
|
|
28
37
|
-- 1) 选区内某线程的调度状态分布(大小核、Running/Sleeping/Runnable)
|
|
29
|
-
SELECT cpu, state,
|
|
38
|
+
SELECT cpu, state,
|
|
39
|
+
SUM(MIN(ts + dur, {{endNs}}) - MAX(ts, {{startNs}}))/1e6 AS total_ms,
|
|
40
|
+
COUNT(*) AS count
|
|
30
41
|
FROM thread_state
|
|
31
|
-
WHERE utid = <UTID>
|
|
42
|
+
WHERE utid = <UTID>
|
|
43
|
+
AND ts < {{endNs}} AND ts + dur > {{startNs}}
|
|
32
44
|
GROUP BY cpu, state ORDER BY total_ms DESC;
|
|
33
45
|
|
|
34
46
|
-- 2) 选区内 CPU 频率变化(使用 counter + cpu_counter_track,不要用 cpu_frequency_counters)
|
|
@@ -38,9 +50,12 @@ WHERE ct.name = 'cpufreq' AND c.ts >= {{startNs}} AND c.ts <= {{endNs}}
|
|
|
38
50
|
ORDER BY ct.cpu, c.ts;
|
|
39
51
|
|
|
40
52
|
-- 3) 选区内某线程的 Slice 热点(通过 thread_track 关联)
|
|
41
|
-
SELECT s.name,
|
|
53
|
+
SELECT s.name,
|
|
54
|
+
(MIN(s.ts + s.dur, {{endNs}}) - MAX(s.ts, {{startNs}}))/1e6 AS dur_ms,
|
|
55
|
+
s.ts, s.depth
|
|
42
56
|
FROM slice s JOIN thread_track tt ON s.track_id = tt.id
|
|
43
|
-
WHERE tt.utid = <UTID>
|
|
57
|
+
WHERE tt.utid = <UTID>
|
|
58
|
+
AND s.ts < {{endNs}} AND s.ts + s.dur > {{startNs}}
|
|
44
59
|
ORDER BY s.dur DESC LIMIT 20;
|
|
45
60
|
```
|
|
46
|
-
> 注意: 不要猜测表名。如果不确定表是否存在,先用 `lookup_sql_schema` 工具查询。
|
|
61
|
+
> 注意: 不要猜测表名。如果不确定表是否存在,先用 `lookup_sql_schema` 工具查询。
|