perfetto-analyzer 1.0.0
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/README.md +63 -0
- package/bin/cli.js +117 -0
- package/package.json +31 -0
- package/skill/SKILL.md +234 -0
- package/skill/references/adb-quick-start.md +139 -0
- package/skill/references/metrics-interpretation.md +130 -0
- package/skill/references/perfetto-traces-reference.md +116 -0
- package/skill/scripts/analyze_metrics.py +408 -0
- package/skill/scripts/collect_trace.py +204 -0
- package/skill/scripts/configs/all.textproto +111 -0
- package/skill/scripts/configs/battery.textproto +65 -0
- package/skill/scripts/configs/cpu.textproto +68 -0
- package/skill/scripts/configs/frames.textproto +62 -0
- package/skill/scripts/configs/memory.textproto +57 -0
- package/skill/scripts/generate_report.py +397 -0
- package/skill/scripts/parse_perfetto_pb.py +469 -0
- package/skill/scripts/requirements.txt +1 -0
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Coleta um trace Perfetto de um device Android via adb."""
|
|
3
|
+
|
|
4
|
+
import argparse
|
|
5
|
+
import subprocess
|
|
6
|
+
import sys
|
|
7
|
+
import os
|
|
8
|
+
import time
|
|
9
|
+
import shutil
|
|
10
|
+
|
|
11
|
+
SKILL_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
12
|
+
CONFIGS_DIR = os.path.join(SKILL_DIR, "scripts", "configs")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def run(cmd, check=True, capture=False):
|
|
16
|
+
kwargs = {"check": check}
|
|
17
|
+
if capture:
|
|
18
|
+
kwargs["capture_output"] = True
|
|
19
|
+
kwargs["text"] = True
|
|
20
|
+
return subprocess.run(cmd, **kwargs)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def check_adb():
|
|
24
|
+
if not shutil.which("adb"):
|
|
25
|
+
print("ERRO: 'adb' não encontrado no PATH.", file=sys.stderr)
|
|
26
|
+
print("Instale Android SDK Platform-Tools e adicione ao PATH.", file=sys.stderr)
|
|
27
|
+
sys.exit(1)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def check_device():
|
|
31
|
+
result = run(["adb", "devices"], capture=True)
|
|
32
|
+
lines = result.stdout.strip().splitlines()
|
|
33
|
+
devices = [l for l in lines[1:] if l.strip() and "device" in l]
|
|
34
|
+
if not devices:
|
|
35
|
+
print("ERRO: Nenhum device Android conectado.", file=sys.stderr)
|
|
36
|
+
print("Verifique:", file=sys.stderr)
|
|
37
|
+
print(" 1. Depuração USB ativada no device (Opções do Desenvolvedor)", file=sys.stderr)
|
|
38
|
+
print(" 2. Cabo USB conectado e aceito no device", file=sys.stderr)
|
|
39
|
+
print(" 3. Execute 'adb devices' para verificar", file=sys.stderr)
|
|
40
|
+
sys.exit(1)
|
|
41
|
+
if len(devices) > 1:
|
|
42
|
+
print(f"AVISO: Múltiplos devices detectados. Usando o primeiro: {devices[0].split()[0]}", file=sys.stderr)
|
|
43
|
+
return devices[0].split()[0]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_config_path(trace_type):
|
|
47
|
+
config_map = {
|
|
48
|
+
"memory": "memory.textproto",
|
|
49
|
+
"cpu": "cpu.textproto",
|
|
50
|
+
"frames": "frames.textproto",
|
|
51
|
+
"battery": "battery.textproto",
|
|
52
|
+
"all": "all.textproto",
|
|
53
|
+
}
|
|
54
|
+
filename = config_map.get(trace_type)
|
|
55
|
+
if not filename:
|
|
56
|
+
print(f"ERRO: Tipo de trace '{trace_type}' inválido.", file=sys.stderr)
|
|
57
|
+
print(f"Tipos disponíveis: {', '.join(config_map.keys())}", file=sys.stderr)
|
|
58
|
+
sys.exit(1)
|
|
59
|
+
path = os.path.join(CONFIGS_DIR, filename)
|
|
60
|
+
if not os.path.exists(path):
|
|
61
|
+
print(f"ERRO: Config não encontrada: {path}", file=sys.stderr)
|
|
62
|
+
sys.exit(1)
|
|
63
|
+
return path
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def ensure_app_running(adb, package):
|
|
67
|
+
"""Verifica se o app está aberto; inicia via launcher se não estiver."""
|
|
68
|
+
result = run(adb + ["shell", f"pidof {package}"], capture=True, check=False)
|
|
69
|
+
pid = result.stdout.strip()
|
|
70
|
+
|
|
71
|
+
if pid:
|
|
72
|
+
print(f"App em execução (PID: {pid})")
|
|
73
|
+
return
|
|
74
|
+
|
|
75
|
+
print(f"App não está aberto. Iniciando {package}...")
|
|
76
|
+
run(
|
|
77
|
+
adb + ["shell", "monkey", "-p", package,
|
|
78
|
+
"-c", "android.intent.category.LAUNCHER", "1"],
|
|
79
|
+
capture=True,
|
|
80
|
+
check=False,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
# Aguarda até 15s para o processo aparecer
|
|
84
|
+
for attempt in range(15):
|
|
85
|
+
time.sleep(1)
|
|
86
|
+
result = run(adb + ["shell", f"pidof {package}"], capture=True, check=False)
|
|
87
|
+
if result.stdout.strip():
|
|
88
|
+
print(f"App iniciado (PID: {result.stdout.strip()})")
|
|
89
|
+
# Pausa extra para deixar a UI estabilizar antes de coletar
|
|
90
|
+
time.sleep(2)
|
|
91
|
+
return
|
|
92
|
+
print(f" Aguardando inicialização... {attempt + 1}s", end="\r", flush=True)
|
|
93
|
+
|
|
94
|
+
print(f"\nAVISO: Não foi possível confirmar a abertura do app após 15s. Continuando mesmo assim.")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def inject_package(config_path, package, duration_ms):
|
|
98
|
+
"""Lê o textproto e injeta package e duração se necessário."""
|
|
99
|
+
with open(config_path) as f:
|
|
100
|
+
content = f.read()
|
|
101
|
+
content = content.replace("__PACKAGE__", package)
|
|
102
|
+
content = content.replace("__DURATION_MS__", str(duration_ms))
|
|
103
|
+
tmp_config = "/tmp/perfetto_config_patched.textproto"
|
|
104
|
+
with open(tmp_config, "w") as f:
|
|
105
|
+
f.write(content)
|
|
106
|
+
return tmp_config
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
# O daemon traced escreve em /data/misc/perfetto-traces/ — é o único path que ele tem acesso.
|
|
110
|
+
DEVICE_TRACE_PATH = "/data/misc/perfetto-traces/perfetto_trace.pb"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def collect_trace(device_id, config_path, duration_seconds, output_path):
|
|
114
|
+
adb = ["adb", "-s", device_id]
|
|
115
|
+
|
|
116
|
+
# Limpar arquivo anterior — se foi criado por outro UID, o daemon não consegue sobrescrever.
|
|
117
|
+
run(adb + ["shell", f"rm -f {DEVICE_TRACE_PATH}"], check=False)
|
|
118
|
+
|
|
119
|
+
print(f"[1/3] Coletando trace ({duration_seconds}s) — interaja com o app agora!")
|
|
120
|
+
|
|
121
|
+
with open(config_path, "rb") as config_file:
|
|
122
|
+
config_content = config_file.read()
|
|
123
|
+
|
|
124
|
+
proc = subprocess.Popen(
|
|
125
|
+
adb + ["shell", f"perfetto --txt -c - -o {DEVICE_TRACE_PATH}"],
|
|
126
|
+
stdin=subprocess.PIPE,
|
|
127
|
+
stdout=subprocess.PIPE,
|
|
128
|
+
stderr=subprocess.PIPE,
|
|
129
|
+
)
|
|
130
|
+
proc.stdin.write(config_content)
|
|
131
|
+
proc.stdin.close()
|
|
132
|
+
|
|
133
|
+
# Countdown baseado em tempo real — atualiza só quando o segundo muda
|
|
134
|
+
start = time.monotonic()
|
|
135
|
+
last_sec = -1
|
|
136
|
+
while True:
|
|
137
|
+
elapsed = time.monotonic() - start
|
|
138
|
+
if elapsed >= duration_seconds:
|
|
139
|
+
break
|
|
140
|
+
current_sec = int(elapsed)
|
|
141
|
+
if current_sec != last_sec:
|
|
142
|
+
print(f" ... {current_sec}/{duration_seconds}s", end="\r", flush=True)
|
|
143
|
+
last_sec = current_sec
|
|
144
|
+
time.sleep(0.1)
|
|
145
|
+
print(f" ... {duration_seconds}/{duration_seconds}s")
|
|
146
|
+
print("Finalizando coleta...")
|
|
147
|
+
|
|
148
|
+
# Aguarda o perfetto terminar com timeout fixo para evitar hang
|
|
149
|
+
try:
|
|
150
|
+
proc.wait(timeout=20)
|
|
151
|
+
except subprocess.TimeoutExpired:
|
|
152
|
+
proc.kill()
|
|
153
|
+
proc.wait()
|
|
154
|
+
print("ERRO: Perfetto não finalizou em 20s após a coleta.", file=sys.stderr)
|
|
155
|
+
sys.exit(1)
|
|
156
|
+
|
|
157
|
+
if proc.returncode != 0:
|
|
158
|
+
stderr = proc.stderr.read().decode(errors="replace")
|
|
159
|
+
print(f"ERRO ao coletar trace (exit {proc.returncode}): {stderr}", file=sys.stderr)
|
|
160
|
+
sys.exit(1)
|
|
161
|
+
|
|
162
|
+
print(f"[2/3] Baixando trace do device...")
|
|
163
|
+
run(adb + ["pull", DEVICE_TRACE_PATH, output_path])
|
|
164
|
+
|
|
165
|
+
print(f"[3/3] Limpando arquivo do device...")
|
|
166
|
+
run(adb + ["shell", f"rm -f {DEVICE_TRACE_PATH}"], check=False)
|
|
167
|
+
|
|
168
|
+
size_kb = os.path.getsize(output_path) // 1024
|
|
169
|
+
if size_kb == 0:
|
|
170
|
+
print("ERRO: Trace vazio (0 bytes). Verifique se o traced daemon está ativo.", file=sys.stderr)
|
|
171
|
+
print("Dica: adb shell 'setprop persist.traced.enable 1 && start traced'", file=sys.stderr)
|
|
172
|
+
sys.exit(1)
|
|
173
|
+
|
|
174
|
+
print(f"\nTrace coletado: {output_path} ({size_kb} KB)")
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def main():
|
|
178
|
+
parser = argparse.ArgumentParser(description="Coleta trace Perfetto via adb")
|
|
179
|
+
parser.add_argument("--package", required=True, help="Package do app (ex: com.example.app)")
|
|
180
|
+
parser.add_argument("--type", required=True, choices=["memory", "cpu", "frames", "battery", "all"],
|
|
181
|
+
dest="trace_type", help="Tipo de trace a coletar")
|
|
182
|
+
parser.add_argument("--duration", type=int, default=30, help="Duração em segundos (padrão: 30)")
|
|
183
|
+
parser.add_argument("--output", default="/tmp/perfetto_trace.pb", help="Caminho de saída do .pb")
|
|
184
|
+
args = parser.parse_args()
|
|
185
|
+
|
|
186
|
+
check_adb()
|
|
187
|
+
device_id = check_device()
|
|
188
|
+
adb = ["adb", "-s", device_id]
|
|
189
|
+
|
|
190
|
+
print(f"Device: {device_id}")
|
|
191
|
+
print(f"Package: {args.package}")
|
|
192
|
+
print(f"Tipo: {args.trace_type}")
|
|
193
|
+
print(f"Duração: {args.duration}s\n")
|
|
194
|
+
|
|
195
|
+
ensure_app_running(adb, args.package)
|
|
196
|
+
|
|
197
|
+
raw_config = get_config_path(args.trace_type)
|
|
198
|
+
patched_config = inject_package(raw_config, args.package, args.duration * 1000)
|
|
199
|
+
|
|
200
|
+
collect_trace(device_id, patched_config, args.duration, args.output)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
if __name__ == "__main__":
|
|
204
|
+
main()
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
duration_ms: __DURATION_MS__
|
|
2
|
+
|
|
3
|
+
# Buffer grande para captura completa
|
|
4
|
+
buffers {
|
|
5
|
+
size_kb: 131072
|
|
6
|
+
fill_policy: RING_BUFFER
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
# --- MEMÓRIA ---
|
|
10
|
+
data_sources {
|
|
11
|
+
config {
|
|
12
|
+
name: "android.heapprofd"
|
|
13
|
+
heapprofd_config {
|
|
14
|
+
sampling_interval_bytes: 4096
|
|
15
|
+
process_cmdline: "__PACKAGE__"
|
|
16
|
+
shmem_size_bytes: 8388608
|
|
17
|
+
block_client: true
|
|
18
|
+
all_heaps: true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# --- CPU ---
|
|
24
|
+
data_sources {
|
|
25
|
+
config {
|
|
26
|
+
name: "linux.perf"
|
|
27
|
+
perf_event_config {
|
|
28
|
+
timebase {
|
|
29
|
+
frequency: 100
|
|
30
|
+
counter: SW_CPU_CLOCK
|
|
31
|
+
}
|
|
32
|
+
callstack_sampling {
|
|
33
|
+
scope {
|
|
34
|
+
target_cmdline: "__PACKAGE__"
|
|
35
|
+
}
|
|
36
|
+
kernel_frames: true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# --- FRAMES ---
|
|
43
|
+
data_sources {
|
|
44
|
+
config {
|
|
45
|
+
name: "android.surfaceflinger.frametimeline"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
# --- BATTERY ---
|
|
50
|
+
data_sources {
|
|
51
|
+
config {
|
|
52
|
+
name: "android.power"
|
|
53
|
+
android_power_config {
|
|
54
|
+
battery_poll_ms: 1000
|
|
55
|
+
battery_counters: BATTERY_COUNTER_CAPACITY_PERCENT
|
|
56
|
+
battery_counters: BATTERY_COUNTER_CHARGE
|
|
57
|
+
battery_counters: BATTERY_COUNTER_CURRENT
|
|
58
|
+
battery_counters: BATTERY_COUNTER_VOLTAGE
|
|
59
|
+
collect_power_rails: true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# --- ATRACE + FTRACE (formato compatível Perfetto v25+) ---
|
|
65
|
+
data_sources {
|
|
66
|
+
config {
|
|
67
|
+
name: "linux.ftrace"
|
|
68
|
+
ftrace_config {
|
|
69
|
+
ftrace_events: "sched/sched_switch"
|
|
70
|
+
ftrace_events: "sched/sched_wakeup"
|
|
71
|
+
ftrace_events: "sched/sched_waking"
|
|
72
|
+
ftrace_events: "power/cpu_frequency"
|
|
73
|
+
ftrace_events: "power/cpu_idle"
|
|
74
|
+
ftrace_events: "power/wakeup_source_activate"
|
|
75
|
+
ftrace_events: "power/wakeup_source_deactivate"
|
|
76
|
+
ftrace_events: "mm_event/mm_event_record"
|
|
77
|
+
atrace_categories: "gfx"
|
|
78
|
+
atrace_categories: "view"
|
|
79
|
+
atrace_categories: "wm"
|
|
80
|
+
atrace_categories: "am"
|
|
81
|
+
atrace_categories: "input"
|
|
82
|
+
atrace_categories: "dalvik"
|
|
83
|
+
atrace_apps: "__PACKAGE__"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
data_sources {
|
|
89
|
+
config {
|
|
90
|
+
name: "linux.sys_stats"
|
|
91
|
+
sys_stats_config {
|
|
92
|
+
meminfo_period_ms: 1000
|
|
93
|
+
meminfo_counters: MEMINFO_MEM_TOTAL
|
|
94
|
+
meminfo_counters: MEMINFO_MEM_FREE
|
|
95
|
+
meminfo_counters: MEMINFO_MEM_AVAILABLE
|
|
96
|
+
stat_period_ms: 1000
|
|
97
|
+
stat_counters: STAT_CPU_TIMES
|
|
98
|
+
cpufreq_period_ms: 500
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
data_sources {
|
|
104
|
+
config {
|
|
105
|
+
name: "linux.process_stats"
|
|
106
|
+
process_stats_config {
|
|
107
|
+
scan_all_processes_on_start: true
|
|
108
|
+
proc_stats_poll_ms: 1000
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
duration_ms: __DURATION_MS__
|
|
2
|
+
|
|
3
|
+
buffers {
|
|
4
|
+
size_kb: 32768
|
|
5
|
+
fill_policy: RING_BUFFER
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
# Contadores de bateria do Android
|
|
9
|
+
data_sources {
|
|
10
|
+
config {
|
|
11
|
+
name: "android.power"
|
|
12
|
+
android_power_config {
|
|
13
|
+
battery_poll_ms: 1000
|
|
14
|
+
battery_counters: BATTERY_COUNTER_CAPACITY_PERCENT
|
|
15
|
+
battery_counters: BATTERY_COUNTER_CHARGE
|
|
16
|
+
battery_counters: BATTERY_COUNTER_CURRENT
|
|
17
|
+
battery_counters: BATTERY_COUNTER_VOLTAGE
|
|
18
|
+
collect_power_rails: true
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# CPU callstack sampling a 60 Hz — identifica qual código do app drena a bateria
|
|
24
|
+
data_sources {
|
|
25
|
+
config {
|
|
26
|
+
name: "linux.perf"
|
|
27
|
+
perf_event_config {
|
|
28
|
+
timebase {
|
|
29
|
+
frequency: 60
|
|
30
|
+
counter: SW_CPU_CLOCK
|
|
31
|
+
}
|
|
32
|
+
callstack_sampling {
|
|
33
|
+
scope {
|
|
34
|
+
target_cmdline: "__PACKAGE__"
|
|
35
|
+
}
|
|
36
|
+
kernel_frames: true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
# Wakelock tracking
|
|
43
|
+
data_sources {
|
|
44
|
+
config {
|
|
45
|
+
name: "linux.ftrace"
|
|
46
|
+
ftrace_config {
|
|
47
|
+
ftrace_events: "power/wakeup_source_activate"
|
|
48
|
+
ftrace_events: "power/wakeup_source_deactivate"
|
|
49
|
+
ftrace_events: "power/suspend_resume"
|
|
50
|
+
ftrace_events: "power/cpu_frequency"
|
|
51
|
+
ftrace_events: "power/cpu_idle"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# System stats para correlação
|
|
57
|
+
data_sources {
|
|
58
|
+
config {
|
|
59
|
+
name: "linux.sys_stats"
|
|
60
|
+
sys_stats_config {
|
|
61
|
+
stat_period_ms: 1000
|
|
62
|
+
stat_counters: STAT_CPU_TIMES
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
duration_ms: __DURATION_MS__
|
|
2
|
+
|
|
3
|
+
buffers {
|
|
4
|
+
size_kb: 65536
|
|
5
|
+
fill_policy: RING_BUFFER
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
# CPU sampling (Linux perf events)
|
|
9
|
+
data_sources {
|
|
10
|
+
config {
|
|
11
|
+
name: "linux.perf"
|
|
12
|
+
perf_event_config {
|
|
13
|
+
timebase {
|
|
14
|
+
frequency: 100
|
|
15
|
+
counter: SW_CPU_CLOCK
|
|
16
|
+
}
|
|
17
|
+
callstack_sampling {
|
|
18
|
+
scope {
|
|
19
|
+
target_cmdline: "__PACKAGE__"
|
|
20
|
+
}
|
|
21
|
+
kernel_frames: true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
# Scheduling events via ftrace
|
|
28
|
+
data_sources {
|
|
29
|
+
config {
|
|
30
|
+
name: "linux.ftrace"
|
|
31
|
+
ftrace_config {
|
|
32
|
+
ftrace_events: "sched/sched_switch"
|
|
33
|
+
ftrace_events: "sched/sched_wakeup"
|
|
34
|
+
ftrace_events: "sched/sched_wakeup_new"
|
|
35
|
+
ftrace_events: "sched/sched_waking"
|
|
36
|
+
ftrace_events: "sched/sched_process_exit"
|
|
37
|
+
ftrace_events: "sched/sched_process_free"
|
|
38
|
+
ftrace_events: "task/task_newtask"
|
|
39
|
+
ftrace_events: "task/task_rename"
|
|
40
|
+
ftrace_events: "power/cpu_frequency"
|
|
41
|
+
ftrace_events: "power/cpu_idle"
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
# System stats (CPU usage)
|
|
47
|
+
data_sources {
|
|
48
|
+
config {
|
|
49
|
+
name: "linux.sys_stats"
|
|
50
|
+
sys_stats_config {
|
|
51
|
+
stat_period_ms: 1000
|
|
52
|
+
stat_counters: STAT_CPU_TIMES
|
|
53
|
+
stat_counters: STAT_FORK_COUNT
|
|
54
|
+
cpufreq_period_ms: 500
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Processos e threads
|
|
60
|
+
data_sources {
|
|
61
|
+
config {
|
|
62
|
+
name: "linux.process_stats"
|
|
63
|
+
process_stats_config {
|
|
64
|
+
scan_all_processes_on_start: true
|
|
65
|
+
proc_stats_poll_ms: 1000
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
duration_ms: __DURATION_MS__
|
|
2
|
+
|
|
3
|
+
buffers {
|
|
4
|
+
size_kb: 65536
|
|
5
|
+
fill_policy: RING_BUFFER
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
# Android Frame Timeline (Android 12+ / API 31+)
|
|
9
|
+
data_sources {
|
|
10
|
+
config {
|
|
11
|
+
name: "android.surfaceflinger.frametimeline"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
# Ftrace com ATrace categories (formato compatível com Perfetto v25+)
|
|
16
|
+
data_sources {
|
|
17
|
+
config {
|
|
18
|
+
name: "linux.ftrace"
|
|
19
|
+
ftrace_config {
|
|
20
|
+
ftrace_events: "sched/sched_switch"
|
|
21
|
+
ftrace_events: "sched/sched_wakeup"
|
|
22
|
+
ftrace_events: "drm/drm_vblank_event"
|
|
23
|
+
ftrace_events: "gpu_mem/gpu_mem_total"
|
|
24
|
+
atrace_categories: "gfx"
|
|
25
|
+
atrace_categories: "view"
|
|
26
|
+
atrace_categories: "wm"
|
|
27
|
+
atrace_categories: "am"
|
|
28
|
+
atrace_categories: "input"
|
|
29
|
+
atrace_categories: "res"
|
|
30
|
+
atrace_categories: "dalvik"
|
|
31
|
+
atrace_apps: "__PACKAGE__"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# CPU callstack sampling a 60 Hz — identifica qual função causou cada frame drop
|
|
37
|
+
data_sources {
|
|
38
|
+
config {
|
|
39
|
+
name: "linux.perf"
|
|
40
|
+
perf_event_config {
|
|
41
|
+
timebase {
|
|
42
|
+
frequency: 60
|
|
43
|
+
counter: SW_CPU_CLOCK
|
|
44
|
+
}
|
|
45
|
+
callstack_sampling {
|
|
46
|
+
scope {
|
|
47
|
+
target_cmdline: "__PACKAGE__"
|
|
48
|
+
}
|
|
49
|
+
kernel_frames: true
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
data_sources {
|
|
56
|
+
config {
|
|
57
|
+
name: "linux.process_stats"
|
|
58
|
+
process_stats_config {
|
|
59
|
+
scan_all_processes_on_start: true
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
duration_ms: __DURATION_MS__
|
|
2
|
+
|
|
3
|
+
# Heap profiling nativo (C/C++/Rust via heapprofd)
|
|
4
|
+
buffers {
|
|
5
|
+
size_kb: 65536
|
|
6
|
+
fill_policy: RING_BUFFER
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
data_sources {
|
|
10
|
+
config {
|
|
11
|
+
name: "android.heapprofd"
|
|
12
|
+
heapprofd_config {
|
|
13
|
+
sampling_interval_bytes: 4096
|
|
14
|
+
process_cmdline: "__PACKAGE__"
|
|
15
|
+
shmem_size_bytes: 8388608
|
|
16
|
+
block_client: true
|
|
17
|
+
all_heaps: true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Heap dumps Java/Kotlin (ART)
|
|
23
|
+
data_sources {
|
|
24
|
+
config {
|
|
25
|
+
name: "android.java_hprof"
|
|
26
|
+
java_hprof_config {
|
|
27
|
+
process_cmdline: "__PACKAGE__"
|
|
28
|
+
dump_smaps: true
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
# Contadores de memória do sistema
|
|
34
|
+
data_sources {
|
|
35
|
+
config {
|
|
36
|
+
name: "linux.sys_stats"
|
|
37
|
+
sys_stats_config {
|
|
38
|
+
meminfo_period_ms: 1000
|
|
39
|
+
meminfo_counters: MEMINFO_MEM_TOTAL
|
|
40
|
+
meminfo_counters: MEMINFO_MEM_FREE
|
|
41
|
+
meminfo_counters: MEMINFO_MEM_AVAILABLE
|
|
42
|
+
meminfo_counters: MEMINFO_CACHED
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Ftrace para rastrear eventos de memória
|
|
48
|
+
data_sources {
|
|
49
|
+
config {
|
|
50
|
+
name: "linux.ftrace"
|
|
51
|
+
ftrace_config {
|
|
52
|
+
ftrace_events: "mm_event/mm_event_record"
|
|
53
|
+
ftrace_events: "lowmemorykiller/lowmemory_kill"
|
|
54
|
+
ftrace_events: "oom/mark_victim"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|