Merge commit '91b067cca0913d0cc9f8b5dab68e3302e278efdc' into sync-20260716

# Conflicts:
#	.github/labeler.yaml
#	.github/workflows/auto_pr_review.yaml
#	.github/workflows/docs.yaml
#	.github/workflows/release.yaml
#	.github/workflows/repo-maintenance.yaml
#	.github/workflows/tests.yaml
#	.github/workflows/ui_preview.yaml
#	README.md
#	SConstruct
#	conftest.py
#	docs/CARS.md
#	msgq_repo
#	opendbc_repo
#	openpilot/cereal/messaging/tests/validate_sp_cereal_upstream.py
#	openpilot/common/api.py
#	openpilot/common/hardware/hw.py
#	openpilot/common/version.py
#	openpilot/selfdrive/assets/fonts/Audiowide-Regular.ttf
#	openpilot/selfdrive/assets/sounds/prompt_single_high.wav
#	openpilot/selfdrive/assets/sounds/prompt_single_low.wav
#	openpilot/selfdrive/car/card.py
#	openpilot/selfdrive/car/helpers.py
#	openpilot/selfdrive/car/tests/test_car_interfaces.py
#	openpilot/selfdrive/car/tests/test_cruise_speed.py
#	openpilot/selfdrive/controls/lib/desire_helper.py
#	openpilot/selfdrive/controls/lib/longcontrol.py
#	openpilot/selfdrive/controls/plannerd.py
#	openpilot/selfdrive/controls/radard.py
#	openpilot/selfdrive/controls/tests/test_longcontrol.py
#	openpilot/selfdrive/modeld/compile_warp.py
#	openpilot/selfdrive/modeld/modeld.py
#	openpilot/selfdrive/monitoring/policy.py
#	openpilot/selfdrive/monitoring/test_monitoring.py
#	openpilot/selfdrive/selfdrived/events.py
#	openpilot/selfdrive/selfdrived/selfdrived.py
#	openpilot/selfdrive/ui/layouts/onboarding.py
#	openpilot/selfdrive/ui/mici/layouts/onboarding.py
#	openpilot/selfdrive/ui/soundd.py
#	openpilot/selfdrive/ui/tests/diff/replay.py
#	openpilot/selfdrive/ui/translations/app.pot
#	openpilot/system/athena/athenad.py
#	openpilot/system/athena/manage_athenad.py
#	openpilot/system/hardware/hardwared.py
#	openpilot/system/loggerd/config.py
#	openpilot/system/manager/github_runner.sh
#	openpilot/system/manager/manager.py
#	openpilot/system/updated/updated.py
#	panda
#	pyproject.toml
#	scripts/lint/lint.sh
#	system/manager/process_config.py
#	system/statsd.py
#	tinygrad_repo
#	tools/release/build_release.sh
#	tools/release/build_stripped.sh
#	uv.lock
This commit is contained in:
Jason Wen
2026-07-16 00:58:01 -04:00
1107 changed files with 3558 additions and 2874 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ set -euo pipefail
while IFS=' ' read -r name port; do
adb forward "tcp:${port}" "tcp:${port}" > /dev/null
done < <(python3 - <<'PY'
from cereal.services import SERVICE_LIST
from openpilot.cereal.services import SERVICE_LIST
FNV_PRIME = 0x100000001b3
FNV_OFFSET_BASIS = 0xcbf29ce484222325
+2 -2
View File
@@ -4,8 +4,8 @@ import binascii
import time
from collections import defaultdict
import cereal.messaging as messaging
from openpilot.tools.scripts.can_table import can_table
import openpilot.cereal.messaging as messaging
from tools.scripts.car.can_table import can_table
from openpilot.tools.lib.logreader import LogIterable, LogReader
RED = '\033[91m'
+1 -1
View File
@@ -4,7 +4,7 @@ import binascii
import time
from collections import defaultdict
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
def can_printer(bus, max_msg, addr, ascii_decode):
+1 -1
View File
@@ -2,7 +2,7 @@
import argparse
import pandas as pd
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
def can_table(dat):
+1 -1
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
import time
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
from opendbc.car.disable_ecu import disable_ecu
from openpilot.selfdrive.car.card import can_comm_callbacks
+3 -3
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import argparse
import time
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
from opendbc.car.carlog import carlog
from opendbc.car.ecu_addrs import get_all_ecu_addrs
from openpilot.common.params import Params
@@ -26,9 +26,9 @@ if __name__ == "__main__":
# Set up params for pandad
params = Params()
params.remove("FirmwareQueryDone")
params.put_bool("IsOnroad", False, block=True)
params.put_bool("IsOffroad", True, block=True)
time.sleep(0.2) # thread is 10 Hz
params.put_bool("IsOnroad", True, block=True)
params.put_bool("IsOffroad", False, block=True)
obd_callback(params)(not args.no_obd)
+4 -4
View File
@@ -1,8 +1,8 @@
#!/usr/bin/env python3
import time
import argparse
import cereal.messaging as messaging
from cereal import car
import openpilot.cereal.messaging as messaging
from opendbc.car.structs import car
from opendbc.car.carlog import carlog
from opendbc.car.fw_versions import get_fw_versions, match_fw_to_car
from opendbc.car.vin import get_vin
@@ -30,9 +30,9 @@ if __name__ == "__main__":
# Set up params for pandad
params = Params()
params.remove("FirmwareQueryDone")
params.put_bool("IsOnroad", False, block=True)
params.put_bool("IsOffroad", True, block=True)
time.sleep(0.2) # thread is 10 Hz
params.put_bool("IsOnroad", True, block=True)
params.put_bool("IsOffroad", False, block=True)
set_obd_multiplexing = obd_callback(params)
extra: Any = None
@@ -15,7 +15,6 @@ import sys
import argparse
from typing import NamedTuple
from subprocess import check_output, CalledProcessError
from opendbc.car.carlog import carlog
from opendbc.car.uds import UdsClient, SESSION_TYPE, DATA_IDENTIFIER_TYPE
from opendbc.car.structs import CarParams
@@ -6,8 +6,8 @@ import struct
from collections import deque
from statistics import mean
from cereal import log
import cereal.messaging as messaging
from openpilot.cereal import log
import openpilot.cereal.messaging as messaging
if __name__ == "__main__":
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import argparse
import time
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
from opendbc.car.carlog import carlog
from opendbc.car.vin import get_vin
from openpilot.selfdrive.car.card import can_comm_callbacks
+1 -1
View File
@@ -6,7 +6,7 @@ from collections import Counter
from pprint import pprint
from typing import cast
from cereal.services import SERVICE_LIST
from openpilot.cereal.services import SERVICE_LIST
from openpilot.tools.lib.logreader import LogReader, ReadMode
from openpilot.selfdrive.test.process_replay.migration import migrate_all
-120
View File
@@ -1,120 +0,0 @@
#!/usr/bin/env python3
'''
System tools like top/htop can only show current cpu usage values, so I write this script to do statistics jobs.
Features:
Use psutil library to sample cpu usage(avergage for all cores) of openpilot processes, at a rate of 5 samples/sec.
Do cpu usage statistics periodically, 5 seconds as a cycle.
Calculate the average cpu usage within this cycle.
Calculate minumium/maximum/accumulated_average cpu usage as long term inspections.
Monitor multiple processes simuteneously.
Sample usage:
root@localhost:/data/openpilot$ python tools/scripts/cpu_usage_stat.py pandad,ubloxd
('Add monitored proc:', './pandad')
('Add monitored proc:', 'python locationd/ubloxd.py')
pandad: 1.96%, min: 1.96%, max: 1.96%, acc: 1.96%
ubloxd.py: 0.39%, min: 0.39%, max: 0.39%, acc: 0.39%
'''
import psutil
import time
import os
import sys
import numpy as np
import argparse
import re
from collections import defaultdict
from openpilot.system.manager.process_config import managed_processes
# Do statistics every 5 seconds
PRINT_INTERVAL = 5
SLEEP_INTERVAL = 0.2
monitored_proc_names = [
# android procs
'SurfaceFlinger', 'sensors.qcom'
] + list(managed_processes.keys())
cpu_time_names = ['user', 'system', 'children_user', 'children_system']
def get_arg_parser():
parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("proc_names", nargs="?", default='',
help="Process names to be monitored, comma separated")
parser.add_argument("--list_all", action='store_true',
help="Show all running processes' cmdline")
parser.add_argument("--detailed_times", action='store_true',
help="show cpu time details (split by user, system, child user, child system)")
return parser
if __name__ == "__main__":
args = get_arg_parser().parse_args(sys.argv[1:])
if args.list_all:
for p in psutil.process_iter():
print('cmdline', p.cmdline(), 'name', p.name())
sys.exit(0)
if len(args.proc_names) > 0:
monitored_proc_names = args.proc_names.split(',')
monitored_procs = []
stats = {}
for p in psutil.process_iter():
if p == psutil.Process():
continue
matched = any(l for l in p.cmdline() if any(pn for pn in monitored_proc_names if re.match(fr'.*{pn}.*', l, re.M | re.I)))
if matched:
k = ' '.join(p.cmdline())
print('Add monitored proc:', k)
stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None),
'avg': defaultdict(float), 'last_cpu_times': None, 'last_sys_time': None}
stats[k]['last_sys_time'] = time.monotonic()
stats[k]['last_cpu_times'] = p.cpu_times()
monitored_procs.append(p)
i = 0
interval_int = int(PRINT_INTERVAL / SLEEP_INTERVAL)
while True:
for p in monitored_procs:
k = ' '.join(p.cmdline())
cur_sys_time = time.monotonic()
cur_cpu_times = p.cpu_times()
cpu_times = np.subtract(cur_cpu_times, stats[k]['last_cpu_times']) / (cur_sys_time - stats[k]['last_sys_time'])
stats[k]['last_sys_time'] = cur_sys_time
stats[k]['last_cpu_times'] = cur_cpu_times
cpu_percent = 0
for num, name in enumerate(cpu_time_names):
stats[k]['cpu_samples'][name].append(cpu_times[num])
cpu_percent += cpu_times[num]
stats[k]['cpu_samples']['total'].append(cpu_percent)
time.sleep(SLEEP_INTERVAL)
i += 1
if i % interval_int == 0:
l = []
for k, stat in stats.items():
if len(stat['cpu_samples']) <= 0:
continue
for name, samples in stat['cpu_samples'].items():
samples = np.array(samples)
avg = samples.mean()
c = samples.size
min_cpu = np.amin(samples)
max_cpu = np.amax(samples)
if stat['min'][name] is None or min_cpu < stat['min'][name]:
stat['min'][name] = min_cpu
if stat['max'][name] is None or max_cpu > stat['max'][name]:
stat['max'][name] = max_cpu
stat['avg'][name] = (stat['avg'][name] * (i - c) + avg * c) / (i)
stat['cpu_samples'][name] = []
msg = f"avg: {stat['avg']['total']:.2%}, min: {stat['min']['total']:.2%}, max: {stat['max']['total']:.2%} {os.path.basename(k)}"
if args.detailed_times:
for stat_type in ['avg', 'min', 'max']:
msg += f"\n {stat_type}: {[(name + ':' + str(round(stat[stat_type][name] * 100, 2))) for name in cpu_time_names]}"
l.append((os.path.basename(k), stat['avg']['total'], msg))
l.sort(key=lambda x: -x[1])
for x in l:
print(x[2])
print('avg sum: {:.2%} over {} samples {} seconds\n'.format(
sum(stat['avg']['total'] for k, stat in stats.items()), i, i * SLEEP_INTERVAL
))
+3 -2
View File
@@ -2,8 +2,9 @@
import time
import random
from cereal import car, log
import cereal.messaging as messaging
from openpilot.cereal import log
from opendbc.car.structs import car
import openpilot.cereal.messaging as messaging
from opendbc.car.honda.interface import CarInterface
from openpilot.common.realtime import DT_CTRL
from openpilot.selfdrive.selfdrived.events import ET, Events
@@ -1,6 +1,5 @@
#!/usr/bin/env python3
import argparse
from opendbc.car import uds
from openpilot.tools.lib.live_logreader import live_logreader
from openpilot.tools.lib.logreader import LogReader, ReadMode
+3 -3
View File
@@ -4,8 +4,8 @@ import argparse
import json
import codecs
from cereal import log
from cereal.services import SERVICE_LIST
from openpilot.cereal import log
from openpilot.cereal.services import SERVICE_LIST
from openpilot.tools.lib.live_logreader import raw_live_logreader
@@ -25,7 +25,7 @@ def hexdump(msg):
if __name__ == "__main__":
parser = argparse.ArgumentParser(description='Dump communication sockets. See cereal/services.py for a complete list of available sockets.')
parser = argparse.ArgumentParser(description='Dump communication sockets. See openpilot/cereal/services.py for a complete list of available sockets.')
parser.add_argument('--pipe', action='store_true')
parser.add_argument('--raw', action='store_true')
parser.add_argument('--json', action='store_true')
+9 -9
View File
@@ -2,7 +2,7 @@
import argparse
import json
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
from openpilot.tools.lib.logreader import LogReader
LEVELS = {
@@ -13,7 +13,7 @@ LEVELS = {
"CRITICAL": 50,
}
ANDROID_LOG_SOURCE = {
OPERATING_SYSTEM_LOG_SOURCE = {
0: "MAIN",
1: "RADIO",
2: "EVENTS",
@@ -34,8 +34,8 @@ def print_logmessage(t, msg, min_level):
print(f"[{t / 1e9:.6f}] decode error: {msg}")
def print_androidlog(t, msg):
source = ANDROID_LOG_SOURCE[msg.id]
def print_operating_system_log(t, msg):
source = msg.tag or OPERATING_SYSTEM_LOG_SOURCE.get(msg.id, "SYSTEM")
try:
m = json.loads(msg.message)['MESSAGE']
except Exception:
@@ -65,15 +65,15 @@ if __name__ == "__main__":
print_logmessage(m.logMonoTime-st, m.logMessage, min_level)
elif m.which() == 'errorLogMessage':
print_logmessage(m.logMonoTime-st, m.errorLogMessage, min_level)
elif m.which() == 'androidLog':
print_androidlog(m.logMonoTime-st, m.androidLog)
elif m.which() == 'operatingSystemLog':
print_operating_system_log(m.logMonoTime-st, m.operatingSystemLog)
else:
sm = messaging.SubMaster(['logMessage', 'androidLog'], addr=args.addr)
sm = messaging.SubMaster(['logMessage', 'operatingSystemLog'], addr=args.addr)
while True:
sm.update()
if sm.updated['logMessage']:
print_logmessage(sm.logMonoTime['logMessage'], sm['logMessage'], min_level)
if sm.updated['androidLog']:
print_androidlog(sm.logMonoTime['androidLog'], sm['androidLog'])
if sm.updated['operatingSystemLog']:
print_operating_system_log(sm.logMonoTime['operatingSystemLog'], sm['operatingSystemLog'])
-1
View File
@@ -3,7 +3,6 @@ import random
from collections import defaultdict
from tqdm import tqdm
from opendbc.car.fw_versions import match_fw_to_car_fuzzy
from opendbc.car.toyota.values import FW_VERSIONS as TOYOTA_FW_VERSIONS
from opendbc.car.honda.values import FW_VERSIONS as HONDA_FW_VERSIONS
+2 -2
View File
@@ -4,13 +4,13 @@
# Instructions:
# - connect to a Panda
# - run selfdrive/pandad/pandad
# - run openpilot/selfdrive/pandad/pandad
# - launching this script
# Note: it's very important that the car is in stock mode, in order to collect a complete fingerprint
# - since some messages are published at low frequency, keep this script running for at least 30s,
# until all messages are received at least once
import cereal.messaging as messaging
import openpilot.cereal.messaging as messaging
logcan = messaging.sub_sock('can')
msgs = {}
+1 -1
View File
@@ -4,7 +4,7 @@ import numpy as np
import capnp
from collections import defaultdict
from cereal.messaging import SubMaster
from openpilot.cereal.messaging import SubMaster
def cputime_total(ct):
return ct.user + ct.nice + ct.system + ct.idle + ct.iowait + ct.irq + ct.softirq
+3 -206
View File
@@ -1,216 +1,13 @@
#!/usr/bin/env python3
import argparse
import os
from collections import defaultdict
import sys
import numpy as np
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
from openpilot.common.utils import tabulate
from openpilot.selfdrive.test.mem_usage import DEMO_ROUTE, print_report
from openpilot.tools.lib.logreader import LogReader
DEMO_ROUTE = "5beb9b58bd12b691/0000010a--a51155e496"
MB = 1024 * 1024
TABULATE_OPTS = dict(tablefmt="simple_grid", stralign="center", numalign="center")
def _get_procs():
from openpilot.selfdrive.test.test_onroad import PROCS
return PROCS
def is_openpilot_proc(name):
if any(p in name for p in _get_procs()):
return True
# catch openpilot processes not in PROCS (athenad, manager, etc.)
return 'openpilot' in name or name.startswith(('selfdrive.', 'system.'))
def get_proc_name(proc):
if len(proc.cmdline) > 0:
return list(proc.cmdline)[0]
return proc.name
def pct(val_mb, total_mb):
return val_mb / total_mb * 100 if total_mb else 0
def has_pss(proc_logs):
"""Check if logs contain PSS data (new field, not in old logs)."""
try:
for proc in proc_logs[-1].procLog.procs:
if proc.memPss > 0:
return True
except AttributeError:
pass
return False
def print_summary(proc_logs, device_states):
mem = proc_logs[-1].procLog.mem
total = mem.total / MB
used = (mem.total - mem.available) / MB
cached = mem.cached / MB
shared = mem.shared / MB
buffers = mem.buffers / MB
lines = [
f" Total: {total:.0f} MB",
f" Used (total-avail): {used:.0f} MB ({pct(used, total):.0f}%)",
f" Cached: {cached:.0f} MB ({pct(cached, total):.0f}%) Buffers: {buffers:.0f} MB ({pct(buffers, total):.0f}%)",
f" Shared/MSGQ: {shared:.0f} MB ({pct(shared, total):.0f}%)",
]
if device_states:
mem_pcts = [m.deviceState.memoryUsagePercent for m in device_states]
lines.append(f" deviceState memory: {np.min(mem_pcts)}-{np.max(mem_pcts)}% (avg {np.mean(mem_pcts):.0f}%)")
print("\n-- Memory Summary --")
print("\n".join(lines))
return total
def collect_per_process_mem(proc_logs, use_pss):
"""Collect per-process memory samples. Returns {name: {metric: [values_per_sample_in_MB]}}."""
by_proc = defaultdict(lambda: defaultdict(list))
for msg in proc_logs:
sample = defaultdict(lambda: defaultdict(float))
for proc in msg.procLog.procs:
name = get_proc_name(proc)
sample[name]['rss'] += proc.memRss / MB
if use_pss:
sample[name]['pss'] += proc.memPss / MB
sample[name]['pss_anon'] += proc.memPssAnon / MB
sample[name]['pss_shmem'] += proc.memPssShmem / MB
for name, metrics in sample.items():
for metric, val in metrics.items():
by_proc[name][metric].append(val)
return by_proc
def _has_pss_detail(by_proc) -> bool:
"""Check if any process has non-zero pss_anon/pss_shmem (unavailable on some kernels)."""
return any(sum(v.get('pss_anon', [])) > 0 or sum(v.get('pss_shmem', [])) > 0 for v in by_proc.values())
def process_table_rows(by_proc, total_mb, use_pss, show_detail):
"""Build table rows. Returns (rows, total_row)."""
mem_key = 'pss' if use_pss else 'rss'
rows = []
for name in sorted(by_proc, key=lambda n: np.mean(by_proc[n][mem_key]), reverse=True):
m = by_proc[name]
vals = m[mem_key]
avg = round(np.mean(vals))
row = [name, f"{avg} MB", f"{round(np.max(vals))} MB", f"{round(pct(avg, total_mb), 1)}%"]
if show_detail:
row.append(f"{round(np.mean(m['pss_anon']))} MB")
row.append(f"{round(np.mean(m['pss_shmem']))} MB")
rows.append(row)
# Total row
total_row = None
if by_proc:
max_samples = max(len(v[mem_key]) for v in by_proc.values())
totals = []
for i in range(max_samples):
s = sum(v[mem_key][i] for v in by_proc.values() if i < len(v[mem_key]))
totals.append(s)
avg_total = round(np.mean(totals))
total_row = ["TOTAL", f"{avg_total} MB", f"{round(np.max(totals))} MB", f"{round(pct(avg_total, total_mb), 1)}%"]
if show_detail:
total_row.append(f"{round(sum(np.mean(v['pss_anon']) for v in by_proc.values()))} MB")
total_row.append(f"{round(sum(np.mean(v['pss_shmem']) for v in by_proc.values()))} MB")
return rows, total_row
def print_process_tables(op_procs, other_procs, total_mb, use_pss):
all_procs = {**op_procs, **other_procs}
show_detail = use_pss and _has_pss_detail(all_procs)
header = ["process", "avg", "max", "%"]
if show_detail:
header += ["anon", "shmem"]
op_rows, op_total = process_table_rows(op_procs, total_mb, use_pss, show_detail)
# filter other: >5MB avg and not bare interpreter paths (test infra noise)
other_filtered = {n: v for n, v in other_procs.items()
if np.mean(v['pss' if use_pss else 'rss']) > 5.0
and os.path.basename(n.split()[0]) not in ('python', 'python3')}
other_rows, other_total = process_table_rows(other_filtered, total_mb, use_pss, show_detail)
rows = op_rows
if op_total:
rows.append(op_total)
if other_rows:
sep_width = len(header)
rows.append([""] * sep_width)
rows.extend(other_rows)
if other_total:
other_total[0] = "TOTAL (other)"
rows.append(other_total)
metric = "PSS (no shared double-count)" if use_pss else "RSS (includes shared, overcounts)"
print(f"\n-- Per-Process Memory: {metric} --")
print(tabulate(rows, header, **TABULATE_OPTS))
def print_memory_accounting(proc_logs, op_procs, other_procs, total_mb, use_pss):
last = proc_logs[-1].procLog.mem
used = (last.total - last.available) / MB
shared = last.shared / MB
cached_buf = (last.buffers + last.cached) / MB - shared # shared (MSGQ) is in Cached; separate it
msgq = shared
mem_key = 'pss' if use_pss else 'rss'
op_total = sum(v[mem_key][-1] for v in op_procs.values()) if op_procs else 0
other_total = sum(v[mem_key][-1] for v in other_procs.values()) if other_procs else 0
proc_sum = op_total + other_total
remainder = used - (cached_buf + msgq) - proc_sum
if not use_pss:
# RSS double-counts shared; add back once to partially correct
remainder += shared
header = ["", "MB", "%", ""]
label = "PSS" if use_pss else "RSS*"
rows = [
["Used (total - avail)", f"{used:.0f}", f"{pct(used, total_mb):.1f}", "memory in use by the system"],
[" Cached + Buffers", f"{cached_buf:.0f}", f"{pct(cached_buf, total_mb):.1f}", "pagecache + fs metadata, reclaimable"],
[" MSGQ (shared)", f"{msgq:.0f}", f"{pct(msgq, total_mb):.1f}", "/dev/shm tmpfs, also in process PSS"],
[f" openpilot {label}", f"{op_total:.0f}", f"{pct(op_total, total_mb):.1f}", "sum of openpilot process memory"],
[f" other {label}", f"{other_total:.0f}", f"{pct(other_total, total_mb):.1f}", "sum of non-openpilot process memory"],
[" kernel/ION/GPU", f"{remainder:.0f}", f"{pct(remainder, total_mb):.1f}", "slab, ION/DMA-BUF, GPU, page tables"],
]
note = "" if use_pss else " (*RSS overcounts shared mem)"
print(f"\n-- Memory Accounting (last sample){note} --")
print(tabulate(rows, header, tablefmt="simple_grid", stralign="right"))
def print_report(proc_logs, device_states=None):
"""Print full memory analysis report. Can be called from tests or CLI."""
if not proc_logs:
print("No procLog messages found")
return
print(f"{len(proc_logs)} procLog samples, {len(device_states or [])} deviceState samples")
use_pss = has_pss(proc_logs)
if not use_pss:
print(" (no PSS data — re-record with updated proclogd for accurate numbers)")
total_mb = print_summary(proc_logs, device_states or [])
by_proc = collect_per_process_mem(proc_logs, use_pss)
op_procs = {n: v for n, v in by_proc.items() if is_openpilot_proc(n)}
other_procs = {n: v for n, v in by_proc.items() if not is_openpilot_proc(n)}
print_process_tables(op_procs, other_procs, total_mb, use_pss)
print_memory_accounting(proc_logs, op_procs, other_procs, total_mb, use_pss)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Analyze memory usage from route logs")
+2 -2
View File
@@ -4,10 +4,10 @@ snapdragon profiler
* download from https://developer.qualcomm.com/software/snapdragon-profiler/tools-archive (need a qc developer account)
* choose v2021.5 (verified working with 24.04 dev environment)
* unzip to selfdrive/debug/profiling/snapdragon/SnapdragonProfiler
* unzip to openpilot/selfdrive/debug/profiling/snapdragon/SnapdragonProfiler
* run ```./setup-profiler.sh```
* run ```./setup-agnos.sh```
* run ```selfdrive/debug/adb.sh``` on device
* run ```openpilot/selfdrive/debug/adb.sh``` on device
* run the ```adb connect xxx``` command that was given to you on local pc
* cd to SnapdragonProfiler and run ```./run_sdp.sh```
* connect to device -> choose device you just setup
+1 -1
View File
@@ -5,7 +5,7 @@ from collections import defaultdict
import matplotlib.pyplot as plt
from cereal.services import SERVICE_LIST
from openpilot.cereal.services import SERVICE_LIST
from openpilot.common.utils import LOG_COMPRESSION_LEVEL
from openpilot.tools.lib.logreader import LogReader
from tqdm import tqdm
+1 -1
View File
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
import sys
from cereal import car
from opendbc.car.structs import car
from openpilot.common.params import Params
from openpilot.tools.lib.route import Route
from openpilot.tools.lib.logreader import LogReader
+1 -1
View File
@@ -14,7 +14,7 @@ if __name__ == "__main__":
parser.add_argument("device", help="device name or dongle id")
parser.add_argument("--host", help="ssh jump server host", default="ssh.comma.ai")
parser.add_argument("--port", help="ssh jump server port", default=22, type=int)
parser.add_argument("--key", help="ssh key", default=os.path.join(BASEDIR, "common/hardware/tici/id_rsa"))
parser.add_argument("--key", help="ssh key", default=os.path.join(BASEDIR, "openpilot/common/hardware/tici/id_rsa"))
parser.add_argument("--debug", help="enable debug output", action="store_true")
args = parser.parse_args()
+2 -1
View File
@@ -1,7 +1,8 @@
#!/usr/bin/env python3
import time
from cereal import car, log, messaging
from openpilot.cereal import log, messaging
from opendbc.car.structs import car
from openpilot.common.params import Params
from openpilot.system.manager.process_config import managed_processes, is_tinygrad_model, is_stock_model
from openpilot.common.hardware import HARDWARE
+2 -2
View File
@@ -7,8 +7,8 @@ from dataclasses import dataclass, field
import numpy as np
import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
import openpilot.cereal.messaging as messaging
from openpilot.cereal.services import SERVICE_LIST
@dataclass