Add initial support for LD_PRELOAD in Trace action

This commit is contained in:
Christophe Bedard 2019-08-07 10:00:59 +02:00
parent 6ded4f3845
commit 11d6f5c9c1

View file

@ -14,10 +14,14 @@
"""Module for the Trace action."""
import re
import subprocess
from typing import List
from typing import Optional
from typing import Union
from launch.action import Action
from launch.actions import SetEnvironmentVariable
from launch.event import Event
from launch.event_handlers import OnShutdown
from launch.launch_context import LaunchContext
@ -33,6 +37,10 @@ class Trace(Action):
Sets up and enables tracing through a launch file description.
"""
PROFILE_LIB_NORMAL = 'liblttng-ust-cyg-profile.so'
PROFILE_LIB_FAST = 'liblttng-ust-cyg-profile-fast.so'
PROFILE_PATTERN = '^lttng_ust_cyg_profile.*:func_.*'
def __init__(
self,
*,
@ -41,6 +49,7 @@ class Trace(Action):
base_path: str = path.DEFAULT_BASE_PATH,
events_ust: List[str] = names.DEFAULT_EVENTS_ROS,
events_kernel: List[str] = names.DEFAULT_EVENTS_KERNEL,
profile_fast: bool = True,
**kwargs,
) -> None:
"""
@ -51,6 +60,7 @@ class Trace(Action):
:param base_path: the path to the base directory in which to create the session directory
:param events_ust: the list of ROS UST events to enable
:param events_kernel: the list of kernel events to enable
:param profile_fast: `True` to use fast profiling, `False` for normal (only if necessary)
"""
super().__init__(**kwargs)
if append_timestamp:
@ -59,8 +69,41 @@ class Trace(Action):
self.__base_path = base_path
self.__events_ust = events_ust
self.__events_kernel = events_kernel
self.__ld_preload_action = None
if self.has_profiling_events(events_ust):
profile_lib_name = self.PROFILE_LIB_FAST if profile_fast else self.PROFILE_LIB_NORMAL
self.__ld_preload_action = SetEnvironmentVariable(
'LD_PRELOAD',
self.get_shared_lib_path(profile_lib_name),
)
@classmethod
def has_profiling_events(cls, events_ust: List[str]) -> bool:
matches = [re.match(cls.PROFILE_PATTERN, event_name) for event_name in events_ust]
return any(matches)
@staticmethod
def get_shared_lib_path(lib_name: str) -> Union[str, None]:
"""
Get the full path to a given shared lib, if possible.
:param lib_name: the name of the shared library
:return: the full path if found, `None` otherwise
"""
(exit_code, output) = subprocess.getstatusoutput(f'whereis -b {lib_name}')
if exit_code != 0:
return None
# Output of whereis is
# <input_lib_name>: <full path, if found>
# Filter out empty strings, in case lib is not found
output_split = [split_part for split_part in output.split(':') if len(split_part) > 0]
if len(output_split) != 2:
return None
return output_split[1].strip()
def execute(self, context: LaunchContext) -> Optional[List[Action]]:
if self.__ld_preload_action is not None:
context.add_action(self.__ld_preload_action)
# TODO make sure this is done as late as possible
context.register_event_handler(OnShutdown(on_shutdown=self._destroy))
# TODO make sure this is done as early as possible