@ -25,6 +25,7 @@ from selfdrive.manager.process_config import managed_processes
from selfdrive . test . process_replay . helpers import OpenpilotPrefix , DummySocket
from selfdrive . test . process_replay . helpers import OpenpilotPrefix , DummySocket
from selfdrive . test . process_replay . vision_meta import meta_from_camera_state , available_streams
from selfdrive . test . process_replay . vision_meta import meta_from_camera_state , available_streams
from selfdrive . test . process_replay . migration import migrate_all
from selfdrive . test . process_replay . migration import migrate_all
from selfdrive . test . process_replay . capture import ProcessOutputCapture
from tools . lib . logreader import LogReader
from tools . lib . logreader import LogReader
# Numpy gives different results based on CPU features after version 19
# Numpy gives different results based on CPU features after version 19
@ -33,6 +34,16 @@ PROC_REPLAY_DIR = os.path.dirname(os.path.abspath(__file__))
FAKEDATA = os . path . join ( PROC_REPLAY_DIR , " fakedata/ " )
FAKEDATA = os . path . join ( PROC_REPLAY_DIR , " fakedata/ " )
class LauncherWithCapture :
def __init__ ( self , capture : ProcessOutputCapture , launcher : Callable ) :
self . capture = capture
self . launcher = launcher
def __call__ ( self , * args , * * kwargs ) :
self . capture . link_with_current_proc ( )
self . launcher ( * args , * * kwargs )
class ReplayContext :
class ReplayContext :
def __init__ ( self , cfg ) :
def __init__ ( self , cfg ) :
self . proc_name = cfg . proc_name
self . proc_name = cfg . proc_name
@ -126,13 +137,14 @@ class ProcessContainer:
def __init__ ( self , cfg : ProcessConfig ) :
def __init__ ( self , cfg : ProcessConfig ) :
self . prefix = OpenpilotPrefix ( clean_dirs_on_exit = False )
self . prefix = OpenpilotPrefix ( clean_dirs_on_exit = False )
self . cfg = copy . deepcopy ( cfg )
self . cfg = copy . deepcopy ( cfg )
self . process = managed_processes [ cfg . proc_name ]
self . process = copy . deepcopy ( managed_processes [ cfg . proc_name ] )
self . msg_queue : List [ capnp . _DynamicStructReader ] = [ ]
self . msg_queue : List [ capnp . _DynamicStructReader ] = [ ]
self . cnt = 0
self . cnt = 0
self . pm : Optional [ messaging . PubMaster ] = None
self . pm : Optional [ messaging . PubMaster ] = None
self . sockets : Optional [ List [ messaging . SubSocket ] ] = None
self . sockets : Optional [ List [ messaging . SubSocket ] ] = None
self . rc : Optional [ ReplayContext ] = None
self . rc : Optional [ ReplayContext ] = None
self . vipc_server : Optional [ VisionIpcServer ] = None
self . vipc_server : Optional [ VisionIpcServer ] = None
self . capture : Optional [ ProcessOutputCapture ] = None
@property
@property
def has_empty_queue ( self ) - > bool :
def has_empty_queue ( self ) - > bool :
@ -180,11 +192,18 @@ class ProcessContainer:
self . vipc_server = vipc_server
self . vipc_server = vipc_server
def _start_process ( self ) :
if self . capture is not None :
self . process . launcher = LauncherWithCapture ( self . capture , self . process . launcher )
self . process . prepare ( )
self . process . start ( )
def start (
def start (
self , params_config : Dict [ str , Any ] , environ_config : Dict [ str , Any ] ,
self , params_config : Dict [ str , Any ] , environ_config : Dict [ str , Any ] ,
all_msgs : Union [ LogReader , List [ capnp . _DynamicStructReader ] ] , fingerprint : Optional [ str ]
all_msgs : Union [ LogReader , List [ capnp . _DynamicStructReader ] ] ,
fingerprint : Optional [ str ] , capture_output : bool
) :
) :
with self . prefix :
with self . prefix as p :
self . _setup_env ( params_config , environ_config )
self . _setup_env ( params_config , environ_config )
if self . cfg . config_callback is not None :
if self . cfg . config_callback is not None :
@ -201,8 +220,10 @@ class ProcessContainer:
self . _setup_vision_ipc ( all_msgs )
self . _setup_vision_ipc ( all_msgs )
assert self . vipc_server is not None
assert self . vipc_server is not None
self . process . prepare ( )
if capture_output :
self . process . start ( )
self . capture = ProcessOutputCapture ( self . cfg . proc_name , p . prefix )
self . _start_process ( )
if self . cfg . init_callback is not None :
if self . cfg . init_callback is not None :
self . cfg . init_callback ( self . rc , self . pm , all_msgs , fingerprint )
self . cfg . init_callback ( self . rc , self . pm , all_msgs , fingerprint )
@ -598,7 +619,8 @@ def replay_process_with_name(name: Union[str, Iterable[str]], lr: Union[LogReade
def replay_process (
def replay_process (
cfg : Union [ ProcessConfig , Iterable [ ProcessConfig ] ] , lr : Union [ LogReader , List [ capnp . _DynamicStructReader ] ] , frs : Optional [ Dict [ str , Any ] ] = None ,
cfg : Union [ ProcessConfig , Iterable [ ProcessConfig ] ] , lr : Union [ LogReader , List [ capnp . _DynamicStructReader ] ] , frs : Optional [ Dict [ str , Any ] ] = None ,
fingerprint : Optional [ str ] = None , return_all_logs : bool = False , custom_params : Optional [ Dict [ str , Any ] ] = None , disable_progress : bool = False
fingerprint : Optional [ str ] = None , return_all_logs : bool = False , custom_params : Optional [ Dict [ str , Any ] ] = None ,
captured_output_store : Optional [ Dict [ str , Dict [ str , str ] ] ] = None , disable_progress : bool = False
) - > List [ capnp . _DynamicStructReader ] :
) - > List [ capnp . _DynamicStructReader ] :
if isinstance ( cfg , Iterable ) :
if isinstance ( cfg , Iterable ) :
cfgs = list ( cfg )
cfgs = list ( cfg )
@ -606,7 +628,7 @@ def replay_process(
cfgs = [ cfg ]
cfgs = [ cfg ]
all_msgs = migrate_all ( lr , old_logtime = True , camera_states = any ( len ( cfg . vision_pubs ) != 0 for cfg in cfgs ) )
all_msgs = migrate_all ( lr , old_logtime = True , camera_states = any ( len ( cfg . vision_pubs ) != 0 for cfg in cfgs ) )
process_logs = _replay_multi_process ( cfgs , all_msgs , frs , fingerprint , custom_params , disable_progress )
process_logs = _replay_multi_process ( cfgs , all_msgs , frs , fingerprint , custom_params , captured_output_store , disable_progress )
if return_all_logs :
if return_all_logs :
keys = { m . which ( ) for m in process_logs }
keys = { m . which ( ) for m in process_logs }
@ -621,8 +643,8 @@ def replay_process(
def _replay_multi_process (
def _replay_multi_process (
cfgs : List [ ProcessConfig ] , lr : Union [ LogReader , List [ capnp . _DynamicStructReader ] ] , frs : Optional [ Dict [ str , Any ] ] ,
cfgs : List [ ProcessConfig ] , lr : Union [ LogReader , List [ capnp . _DynamicStructReader ] ] , frs : Optional [ Dict [ str , Any ] ] , fingerprint : Optional [ str ] ,
fingerprint : Optional [ str ] , custom_params : Optional [ Dict [ str , Any ] ] , disable_progress : bool
custom_params : Optional [ Dict [ str , Any ] ] , captured_output_store : Optional [ Dict [ str , Dict [ str , str ] ] ] , disable_progress : bool
) - > List [ capnp . _DynamicStructReader ] :
) - > List [ capnp . _DynamicStructReader ] :
if fingerprint is not None :
if fingerprint is not None :
params_config = generate_params_config ( lr = lr , fingerprint = fingerprint , custom_params = custom_params )
params_config = generate_params_config ( lr = lr , fingerprint = fingerprint , custom_params = custom_params )
@ -647,7 +669,7 @@ def _replay_multi_process(
containers = [ ]
containers = [ ]
for cfg in cfgs :
for cfg in cfgs :
container = ProcessContainer ( cfg )
container = ProcessContainer ( cfg )
container . start ( params_config , env_config , all_msgs , fingerprint )
container . start ( params_config , env_config , all_msgs , fingerprint , captured_output_store is not None )
containers . append ( container )
containers . append ( container )
all_pubs = set ( [ pub for container in containers for pub in container . pubs ] )
all_pubs = set ( [ pub for container in containers for pub in container . pubs ] )
@ -682,6 +704,10 @@ def _replay_multi_process(
finally :
finally :
for container in containers :
for container in containers :
container . stop ( )
container . stop ( )
if captured_output_store is not None :
assert container . capture is not None
out , err = container . capture . read_outerr ( )
captured_output_store [ container . cfg . proc_name ] = { " out " : out , " err " : err }
return log_msgs
return log_msgs