Merge branch '19-update-after-tracepoint-to-fix-new-intra-process-communication' into 'master'
Resolve "Update after tracepoint to fix new intra-process communication" Closes #19 See merge request micro-ROS/ros_tracing/tracetools_analysis!28
This commit is contained in:
commit
f16fa313a5
4 changed files with 152 additions and 63 deletions
Binary file not shown.
|
@ -56,6 +56,10 @@ class RosDataModel(DataModel):
|
|||
'topic_name',
|
||||
'depth'])
|
||||
self.subscriptions.set_index(['subscription_handle'], inplace=True, drop=True)
|
||||
self.subscription_objects = pd.DataFrame(columns=['subscription',
|
||||
'timestamp',
|
||||
'subscription_handle'])
|
||||
self.subscription_objects.set_index(['subscription'], inplace=True, drop=True)
|
||||
self.services = pd.DataFrame(columns=['service_handle',
|
||||
'timestamp',
|
||||
'node_handle',
|
||||
|
@ -74,10 +78,10 @@ class RosDataModel(DataModel):
|
|||
'tid'])
|
||||
self.timers.set_index(['timer_handle'], inplace=True, drop=True)
|
||||
|
||||
self.callback_objects = pd.DataFrame(columns=['handle',
|
||||
self.callback_objects = pd.DataFrame(columns=['reference',
|
||||
'timestamp',
|
||||
'callback_object'])
|
||||
self.callback_objects.set_index(['handle'], inplace=True, drop=True)
|
||||
self.callback_objects.set_index(['reference'], inplace=True, drop=True)
|
||||
self.callback_symbols = pd.DataFrame(columns=['callback_object',
|
||||
'timestamp',
|
||||
'symbol'])
|
||||
|
@ -104,11 +108,16 @@ class RosDataModel(DataModel):
|
|||
) -> None:
|
||||
self.publishers.loc[handle] = [timestamp, node_handle, rmw_handle, topic_name, depth]
|
||||
|
||||
def add_subscription(
|
||||
def add_rcl_subscription(
|
||||
self, handle, timestamp, node_handle, rmw_handle, topic_name, depth
|
||||
) -> None:
|
||||
self.subscriptions.loc[handle] = [timestamp, node_handle, rmw_handle, topic_name, depth]
|
||||
|
||||
def add_rclcpp_subscription(
|
||||
self, subscription_pointer, timestamp, subscription_handle
|
||||
) -> None:
|
||||
self.subscription_objects.loc[subscription_pointer] = [timestamp, subscription_handle]
|
||||
|
||||
def add_service(
|
||||
self, handle, timestamp, node_handle, rmw_handle, service_name
|
||||
) -> None:
|
||||
|
@ -125,9 +134,9 @@ class RosDataModel(DataModel):
|
|||
self.timers.loc[handle] = [timestamp, period, tid]
|
||||
|
||||
def add_callback_object(
|
||||
self, handle, timestamp, callback_object
|
||||
self, reference, timestamp, callback_object
|
||||
) -> None:
|
||||
self.callback_objects.loc[handle] = [timestamp, callback_object]
|
||||
self.callback_objects.loc[reference] = [timestamp, callback_object]
|
||||
|
||||
def add_callback_symbol(
|
||||
self, callback_object, timestamp, symbol
|
||||
|
@ -156,6 +165,8 @@ class RosDataModel(DataModel):
|
|||
print()
|
||||
print(f'Subscriptions:\n{self.subscriptions.to_string()}')
|
||||
print()
|
||||
print(f'Subscription objects:\n{self.subscription_objects.to_string()}')
|
||||
print()
|
||||
print(f'Services:\n{self.services.to_string()}')
|
||||
print()
|
||||
print(f'Clients:\n{self.clients.to_string()}')
|
||||
|
|
|
@ -43,7 +43,9 @@ class Ros2Handler(EventHandler):
|
|||
'ros2:rcl_publisher_init':
|
||||
self._handle_rcl_publisher_init,
|
||||
'ros2:rcl_subscription_init':
|
||||
self._handle_subscription_init,
|
||||
self._handle_rcl_subscription_init,
|
||||
'ros2:rclcpp_subscription_init':
|
||||
self._handle_rclcpp_subscription_init,
|
||||
'ros2:rclcpp_subscription_callback_added':
|
||||
self._handle_rclcpp_subscription_callback_added,
|
||||
'ros2:rcl_service_init':
|
||||
|
@ -78,7 +80,7 @@ class Ros2Handler(EventHandler):
|
|||
return self._data_model
|
||||
|
||||
def _handle_rcl_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
context_handle = get_field(event, 'context_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -87,7 +89,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_context(context_handle, timestamp, pid, version)
|
||||
|
||||
def _handle_rcl_node_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'node_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -98,7 +100,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_node(handle, timestamp, tid, rmw_handle, name, namespace)
|
||||
|
||||
def _handle_rcl_publisher_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'publisher_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -108,8 +110,8 @@ class Ros2Handler(EventHandler):
|
|||
depth = get_field(event, 'queue_depth')
|
||||
self.data.add_publisher(handle, timestamp, node_handle, rmw_handle, topic_name, depth)
|
||||
|
||||
def _handle_subscription_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
def _handle_rcl_subscription_init(
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'subscription_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -117,18 +119,28 @@ class Ros2Handler(EventHandler):
|
|||
rmw_handle = get_field(event, 'rmw_subscription_handle')
|
||||
topic_name = get_field(event, 'topic_name')
|
||||
depth = get_field(event, 'queue_depth')
|
||||
self.data.add_subscription(handle, timestamp, node_handle, rmw_handle, topic_name, depth)
|
||||
self.data.add_rcl_subscription(
|
||||
handle, timestamp, node_handle, rmw_handle, topic_name, depth,
|
||||
)
|
||||
|
||||
def _handle_rclcpp_subscription_init(
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
subscription_pointer = get_field(event, 'subscription')
|
||||
timestamp = metadata.timestamp
|
||||
handle = get_field(event, 'subscription_handle')
|
||||
self.data.add_rclcpp_subscription(subscription_pointer, timestamp, handle)
|
||||
|
||||
def _handle_rclcpp_subscription_callback_added(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'subscription_handle')
|
||||
subscription_pointer = get_field(event, 'subscription')
|
||||
timestamp = metadata.timestamp
|
||||
callback_object = get_field(event, 'callback')
|
||||
self.data.add_callback_object(handle, timestamp, callback_object)
|
||||
self.data.add_callback_object(subscription_pointer, timestamp, callback_object)
|
||||
|
||||
def _handle_rcl_service_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'service_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -138,7 +150,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_service(handle, timestamp, node_handle, rmw_handle, service_name)
|
||||
|
||||
def _handle_rclcpp_service_callback_added(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'service_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -146,7 +158,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_callback_object(handle, timestamp, callback_object)
|
||||
|
||||
def _handle_rcl_client_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'client_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -156,7 +168,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_client(handle, timestamp, node_handle, rmw_handle, service_name)
|
||||
|
||||
def _handle_rcl_timer_init(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'timer_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -165,7 +177,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_timer(handle, timestamp, period, tid)
|
||||
|
||||
def _handle_rclcpp_timer_callback_added(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
handle = get_field(event, 'timer_handle')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -173,7 +185,7 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_callback_object(handle, timestamp, callback_object)
|
||||
|
||||
def _handle_rclcpp_callback_register(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
callback_object = get_field(event, 'callback')
|
||||
timestamp = metadata.timestamp
|
||||
|
@ -181,14 +193,14 @@ class Ros2Handler(EventHandler):
|
|||
self.data.add_callback_symbol(callback_object, timestamp, symbol)
|
||||
|
||||
def _handle_callback_start(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
# Add to dict
|
||||
callback_addr = get_field(event, 'callback')
|
||||
self._callback_instances[callback_addr] = (event, metadata)
|
||||
|
||||
def _handle_callback_end(
|
||||
self, event: Dict, metadata: EventMetadata
|
||||
self, event: Dict, metadata: EventMetadata,
|
||||
) -> None:
|
||||
# Fetch from dict
|
||||
callback_object = get_field(event, 'callback')
|
||||
|
|
|
@ -38,7 +38,10 @@ class DataModelUtil():
|
|||
This class provides basic util functions.
|
||||
"""
|
||||
|
||||
def __init__(self, data_model: DataModel) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
data_model: DataModel,
|
||||
) -> None:
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
|
@ -105,7 +108,10 @@ class DataModelUtil():
|
|||
class ProfileDataModelUtil(DataModelUtil):
|
||||
"""Profiling data model utility class."""
|
||||
|
||||
def __init__(self, data_model: ProfileDataModel) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
data_model: ProfileDataModel,
|
||||
) -> None:
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
|
@ -113,14 +119,20 @@ class ProfileDataModelUtil(DataModelUtil):
|
|||
"""
|
||||
super().__init__(data_model)
|
||||
|
||||
def with_tid(self, tid: int) -> DataFrame:
|
||||
def with_tid(
|
||||
self,
|
||||
tid: int,
|
||||
) -> DataFrame:
|
||||
return self.data.times.loc[self.data.times['tid'] == tid]
|
||||
|
||||
def get_tids(self) -> Set[int]:
|
||||
"""Get the TIDs in the data model."""
|
||||
return set(self.data.times['tid'])
|
||||
|
||||
def get_call_tree(self, tid: int) -> Dict[str, List[str]]:
|
||||
def get_call_tree(
|
||||
self,
|
||||
tid: int,
|
||||
) -> Dict[str, List[str]]:
|
||||
depth_names = self.with_tid(tid)[
|
||||
['depth', 'function_name', 'parent_name']
|
||||
].drop_duplicates()
|
||||
|
@ -136,7 +148,10 @@ class ProfileDataModelUtil(DataModelUtil):
|
|||
tree[parent].add(name)
|
||||
return dict(tree)
|
||||
|
||||
def get_function_duration_data(self, tid: int) -> List[Dict[str, Union[int, str, DataFrame]]]:
|
||||
def get_function_duration_data(
|
||||
self,
|
||||
tid: int,
|
||||
) -> List[Dict[str, Union[int, str, DataFrame]]]:
|
||||
"""Get duration data for each function."""
|
||||
tid_df = self.with_tid(tid)
|
||||
depth_names = tid_df[['depth', 'function_name', 'parent_name']].drop_duplicates()
|
||||
|
@ -167,7 +182,10 @@ class ProfileDataModelUtil(DataModelUtil):
|
|||
class CpuTimeDataModelUtil(DataModelUtil):
|
||||
"""CPU time data model utility class."""
|
||||
|
||||
def __init__(self, data_model: CpuTimeDataModel) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
data_model: CpuTimeDataModel,
|
||||
) -> None:
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
|
@ -183,7 +201,10 @@ class CpuTimeDataModelUtil(DataModelUtil):
|
|||
class RosDataModelUtil(DataModelUtil):
|
||||
"""ROS data model utility class."""
|
||||
|
||||
def __init__(self, data_model: RosDataModel) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
data_model: RosDataModel,
|
||||
) -> None:
|
||||
"""
|
||||
Constructor.
|
||||
|
||||
|
@ -191,7 +212,10 @@ class RosDataModelUtil(DataModelUtil):
|
|||
"""
|
||||
super().__init__(data_model)
|
||||
|
||||
def _prettify(self, original: str) -> str:
|
||||
def _prettify(
|
||||
self,
|
||||
original: str,
|
||||
) -> str:
|
||||
"""
|
||||
Process symbol to make it more readable.
|
||||
|
||||
|
@ -263,7 +287,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
}
|
||||
|
||||
def get_callback_durations(
|
||||
self, callback_obj: int
|
||||
self,
|
||||
callback_obj: int,
|
||||
) -> DataFrame:
|
||||
"""
|
||||
Get durations of callback instances for a given callback object.
|
||||
|
@ -280,7 +305,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
return self.convert_time_columns(data, ['duration'], ['timestamp'])
|
||||
|
||||
def get_node_tid_from_name(
|
||||
self, node_name: str
|
||||
self,
|
||||
node_name: str,
|
||||
) -> Union[int, None]:
|
||||
"""
|
||||
Get the tid corresponding to a node.
|
||||
|
@ -296,7 +322,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
return node_row.iloc[0]['tid'] if not node_row.empty else None
|
||||
|
||||
def get_node_names_from_tid(
|
||||
self, tid: str
|
||||
self,
|
||||
tid: str,
|
||||
) -> Union[List[str], None]:
|
||||
"""
|
||||
Get the list of node names corresponding to a tid.
|
||||
|
@ -309,7 +336,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
]['name'].tolist()
|
||||
|
||||
def get_callback_owner_info(
|
||||
self, callback_obj: int
|
||||
self,
|
||||
callback_obj: int,
|
||||
) -> Union[str, None]:
|
||||
"""
|
||||
Get information about the owner of a callback.
|
||||
|
@ -322,36 +350,37 @@ class RosDataModelUtil(DataModelUtil):
|
|||
:param callback_obj: the callback object value
|
||||
:return: information about the owner of the callback, or `None` if it fails
|
||||
"""
|
||||
# Get handle corresponding to callback object
|
||||
handle = self.data.callback_objects.loc[
|
||||
# Get reference corresponding to callback object
|
||||
reference = self.data.callback_objects.loc[
|
||||
self.data.callback_objects['callback_object'] == callback_obj
|
||||
].index.values.astype(int)[0]
|
||||
|
||||
type_name = None
|
||||
info = None
|
||||
# Check if it's a timer first (since it's slightly different than the others)
|
||||
if handle in self.data.timers.index:
|
||||
if reference in self.data.timers.index:
|
||||
type_name = 'Timer'
|
||||
info = self.get_timer_handle_info(handle)
|
||||
elif handle in self.data.publishers.index:
|
||||
info = self.get_timer_handle_info(reference)
|
||||
elif reference in self.data.publishers.index:
|
||||
type_name = 'Publisher'
|
||||
info = self.get_publisher_handle_info(handle)
|
||||
elif handle in self.data.subscriptions.index:
|
||||
info = self.get_publisher_handle_info(reference)
|
||||
elif reference in self.data.subscription_objects.index:
|
||||
type_name = 'Subscription'
|
||||
info = self.get_subscription_handle_info(handle)
|
||||
elif handle in self.data.services.index:
|
||||
info = self.get_subscription_reference_info(reference)
|
||||
elif reference in self.data.services.index:
|
||||
type_name = 'Service'
|
||||
info = self.get_subscription_handle_info(handle)
|
||||
elif handle in self.data.clients.index:
|
||||
info = self.get_service_handle_info(reference)
|
||||
elif reference in self.data.clients.index:
|
||||
type_name = 'Client'
|
||||
info = self.get_client_handle_info(handle)
|
||||
info = self.get_client_handle_info(reference)
|
||||
|
||||
if info is not None:
|
||||
info = f'{type_name} -- {self.format_info_dict(info)}'
|
||||
return info
|
||||
|
||||
def get_timer_handle_info(
|
||||
self, timer_handle: int
|
||||
self,
|
||||
timer_handle: int,
|
||||
) -> Union[Mapping[str, Any], None]:
|
||||
"""
|
||||
Get information about the owner of a timer.
|
||||
|
@ -369,7 +398,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
return {'tid': tid, 'period': f'{period_ms:.0f} ms'}
|
||||
|
||||
def get_publisher_handle_info(
|
||||
self, publisher_handle: int
|
||||
self,
|
||||
publisher_handle: int,
|
||||
) -> Union[Mapping[str, Any], None]:
|
||||
"""
|
||||
Get information about a publisher handle.
|
||||
|
@ -386,30 +416,61 @@ class RosDataModelUtil(DataModelUtil):
|
|||
publisher_info = {'topic': topic_name}
|
||||
return {**node_handle_info, **publisher_info}
|
||||
|
||||
def get_subscription_handle_info(
|
||||
self, subscription_handle: int
|
||||
def get_subscription_reference_info(
|
||||
self,
|
||||
subscription_reference: int,
|
||||
) -> Union[Mapping[str, Any], None]:
|
||||
"""
|
||||
Get information about a subscription handle.
|
||||
|
||||
:param subscription_handle: the subscription handle value
|
||||
:param subscription_reference: the subscription reference value
|
||||
:return: a dictionary with name:value info, or `None` if it fails
|
||||
"""
|
||||
subscriptions_info = self.data.subscriptions.merge(
|
||||
self.data.nodes,
|
||||
left_on='node_handle',
|
||||
right_index=True)
|
||||
if subscription_handle not in self.data.subscriptions.index:
|
||||
# First check that the subscription reference exists
|
||||
if subscription_reference not in self.data.subscription_objects.index:
|
||||
return None
|
||||
|
||||
node_handle = subscriptions_info.loc[subscription_handle, 'node_handle']
|
||||
# To get information about a subscription reference, we need 3 dataframes
|
||||
# * subscription_objects
|
||||
# * subscription (reference) <--> subscription_handle
|
||||
# * subscriptions
|
||||
# * subscription_handle <--> topic_name
|
||||
# * subscription_handle <--> node_handle
|
||||
# * nodes
|
||||
# * node_handle <--> (node info)
|
||||
# First, drop unnecessary common columns for debugging simplicity
|
||||
subscription_objects_simple = self.data.subscription_objects.drop(
|
||||
columns=['timestamp'],
|
||||
axis=1,
|
||||
)
|
||||
subscriptions_simple = self.data.subscriptions.drop(
|
||||
columns=['timestamp', 'rmw_handle'],
|
||||
inplace=False,
|
||||
)
|
||||
nodes_simple = self.data.nodes.drop(
|
||||
columns=['timestamp', 'rmw_handle'],
|
||||
inplace=False,
|
||||
)
|
||||
# Then merge the 3 dataframes
|
||||
subscriptions_info = subscription_objects_simple.merge(
|
||||
subscriptions_simple,
|
||||
left_on='subscription_handle',
|
||||
right_index=True,
|
||||
).merge(
|
||||
nodes_simple,
|
||||
left_on='node_handle',
|
||||
right_index=True,
|
||||
)
|
||||
|
||||
node_handle = subscriptions_info.loc[subscription_reference, 'node_handle']
|
||||
node_handle_info = self.get_node_handle_info(node_handle)
|
||||
topic_name = subscriptions_info.loc[subscription_handle, 'topic_name']
|
||||
topic_name = subscriptions_info.loc[subscription_reference, 'topic_name']
|
||||
subscription_info = {'topic': topic_name}
|
||||
return {**node_handle_info, **subscription_info}
|
||||
|
||||
def get_service_handle_info(
|
||||
self, service_handle: int
|
||||
self,
|
||||
service_handle: int,
|
||||
) -> Union[Mapping[str, Any], None]:
|
||||
"""
|
||||
Get information about a service handle.
|
||||
|
@ -427,7 +488,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
return {**node_handle_info, **service_info}
|
||||
|
||||
def get_client_handle_info(
|
||||
self, client_handle: int
|
||||
self,
|
||||
client_handle: int,
|
||||
) -> Union[Mapping[str, Any], None]:
|
||||
"""
|
||||
Get information about a client handle.
|
||||
|
@ -445,7 +507,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
return {**node_handle_info, **service_info}
|
||||
|
||||
def get_node_handle_info(
|
||||
self, node_handle: int
|
||||
self,
|
||||
node_handle: int,
|
||||
) -> Union[Mapping[str, Any], None]:
|
||||
"""
|
||||
Get information about a node handle.
|
||||
|
@ -460,5 +523,8 @@ class RosDataModelUtil(DataModelUtil):
|
|||
tid = self.data.nodes.loc[node_handle, 'tid']
|
||||
return {'node': node_name, 'tid': tid}
|
||||
|
||||
def format_info_dict(self, info_dict: Mapping[str, Any]) -> str:
|
||||
def format_info_dict(
|
||||
self,
|
||||
info_dict: Mapping[str, Any],
|
||||
) -> str:
|
||||
return ', '.join([f'{key}: {val}' for key, val in info_dict.items()])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue