Skip to content

Commit

Permalink
Deprecate 'context_names' param and replace with 'context_fields'
Browse files Browse the repository at this point in the history
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
  • Loading branch information
christophebedard committed Oct 23, 2021
1 parent 637ac1b commit d196944
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 58 deletions.
2 changes: 1 addition & 1 deletion ros2trace/ros2trace/command/trace.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def main(self, *, parser, args):
args.path,
args.events_ust,
args.events_kernel,
args.context_names,
args.context_fields,
args.list,
)
fini(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ def test_action_context_per_domain(self) -> None:
'ros2:*',
'*',
],
context_names={
context_fields={
'kernel': [],
'userspace': ['vpid', 'vtid'],
},
Expand All @@ -151,7 +151,7 @@ def test_action_context_per_domain(self) -> None:
self._check_trace_action(action, tmpdir)

self.assertDictEqual(
action.context_names,
action.context_fields,
{
'kernel': [],
'userspace': ['vpid', 'vtid'],
Expand Down Expand Up @@ -182,7 +182,7 @@ def test_action_substitutions(self) -> None:
EnvironmentVariable(name='TestTraceAction__event_ust'),
TextSubstitution(text='*'),
],
context_names={
context_fields={
'kernel': [],
'userspace': [
EnvironmentVariable(name='TestTraceAction__context_field'),
Expand All @@ -194,7 +194,7 @@ def test_action_substitutions(self) -> None:
self._check_trace_action(action, tmpdir)

self.assertDictEqual(
action.context_names,
action.context_fields,
{
'kernel': [],
'userspace': ['vpid', 'vtid'],
Expand Down
56 changes: 38 additions & 18 deletions tracetools_launch/tracetools_launch/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,17 +81,22 @@ def __init__(
base_path: Optional[SomeSubstitutionsType] = None,
events_ust: Iterable[SomeSubstitutionsType] = names.DEFAULT_EVENTS_ROS,
events_kernel: Iterable[SomeSubstitutionsType] = names.DEFAULT_EVENTS_KERNEL,
context_names:
context_fields:
Union[Iterable[SomeSubstitutionsType], Dict[str, Iterable[SomeSubstitutionsType]]]
= names.DEFAULT_CONTEXT,
context_names:
Optional[
Union[Iterable[SomeSubstitutionsType], Dict[str, Iterable[SomeSubstitutionsType]]]
]
= None,
profile_fast: bool = True,
**kwargs,
) -> None:
"""
Create a Trace.
Substitutions are supported for the session name,
base path, and the lists of events and context names.
base path, and the lists of events and context fields.
For the lists of events, wildcards can be used, e.g., 'ros2:*' for
all events from the 'ros2' tracepoint provider or '*' for all events.
Expand All @@ -106,29 +111,35 @@ def __init__(
or `None` for default
:param events_ust: the list of ROS UST events to enable
:param events_kernel: the list of kernel events to enable
:param context_names: the names of context fields to enable
:param context_fields: the names of context fields to enable
if it's a list or a set, the context fields are enabled for both kernel and userspace;
if it's a dictionary: { domain type string -> context fields list }
with the domain type string being either 'kernel' or 'userspace'
:param context_names: DEPRECATED, use context_fields instead
:param profile_fast: `True` to use fast profiling, `False` for normal (only if necessary)
"""
super().__init__(**kwargs)
self.__logger = logging.get_logger(__name__)
self.__append_timestamp = append_timestamp
self.__session_name = normalize_to_list_of_substitutions(session_name)
self.__base_path = base_path \
if base_path is None else normalize_to_list_of_substitutions(base_path)
self.__trace_directory = None
self.__events_ust = [normalize_to_list_of_substitutions(x) for x in events_ust]
self.__events_kernel = [normalize_to_list_of_substitutions(x) for x in events_kernel]
self.__context_names = \
# Use value from deprecated param if it is provided
# TODO(christophebedard) remove context_names param in Rolling after Humble release
if context_names is not None:
context_fields = context_names
self.__logger.warning('context_names parameter is deprecated, use context_fields')
self.__context_fields = \
{
d: [normalize_to_list_of_substitutions(n) for n in names]
for d, names in context_names.items()
domain: [normalize_to_list_of_substitutions(field) for field in fields]
for domain, fields in context_fields.items()
} \
if isinstance(context_names, dict) \
else [normalize_to_list_of_substitutions(x) for x in context_names]
if isinstance(context_fields, dict) \
else [normalize_to_list_of_substitutions(field) for field in context_fields]
self.__profile_fast = profile_fast
self.__logger = logging.get_logger(__name__)
self.__ld_preload_actions: List[LdPreload] = []

@property
Expand All @@ -151,9 +162,14 @@ def events_ust(self):
def events_kernel(self):
return self.__events_kernel

@property
def context_fields(self):
return self.__context_fields

@property
def context_names(self):
return self.__context_names
self.__logger.warning('context_names parameter is deprecated, use context_fields')
return self.__context_fields

@property
def profile_fast(self):
Expand Down Expand Up @@ -243,6 +259,10 @@ def parse(cls, entity: Entity, parser: Parser):
if events_kernel is not None:
kwargs['events_kernel'] = cls._parse_cmdline(events_kernel, parser) \
if events_kernel else []
context_fields = entity.get_attr('context-fields', optional=True)
if context_fields is not None:
kwargs['context_fields'] = cls._parse_cmdline(context_fields, parser) \
if context_fields else []
context_names = entity.get_attr('context-names', optional=True)
if context_names is not None:
kwargs['context_names'] = cls._parse_cmdline(context_names, parser) \
Expand Down Expand Up @@ -297,13 +317,13 @@ def __perform_substitutions(self, context: LaunchContext) -> None:
if self.__base_path else path.get_tracing_directory()
self.__events_ust = [perform_substitutions(context, x) for x in self.__events_ust]
self.__events_kernel = [perform_substitutions(context, x) for x in self.__events_kernel]
self.__context_names = \
self.__context_fields = \
{
d: [perform_substitutions(context, n) for n in names]
for d, names in self.__context_names.items()
domain: [perform_substitutions(context, field) for field in fields]
for domain, fields in self.__context_fields.items()
} \
if isinstance(self.__context_names, dict) \
else [perform_substitutions(context, x) for x in self.__context_names]
if isinstance(self.__context_fields, dict) \
else [perform_substitutions(context, field) for field in self.__context_fields]

# Add LD_PRELOAD actions if corresponding events are enabled
if self.has_profiling_events(self.__events_ust):
Expand All @@ -330,12 +350,12 @@ def _setup(self) -> None:
base_path=self.__base_path,
ros_events=self.__events_ust,
kernel_events=self.__events_kernel,
context_names=self.__context_names,
context_fields=self.__context_fields,
)
self.__logger.info(f'Writing tracing session to: {self.__trace_directory}')
self.__logger.debug(f'UST events: {self.__events_ust}')
self.__logger.debug(f'Kernel events: {self.__events_kernel}')
self.__logger.debug(f'Context names: {self.__context_names}')
self.__logger.debug(f'Context fields: {self.__context_fields}')
self.__logger.debug(f'LD_PRELOAD: {self.__ld_preload_actions}')

def _destroy(self, event: Event, context: LaunchContext) -> None:
Expand All @@ -350,7 +370,7 @@ def __repr__(self):
f'trace_directory={self.__trace_directory}, '
f'events_ust={self.__events_ust}, '
f'events_kernel={self.__events_kernel}, '
f'context_names={self.__context_names}, '
f'context_fields={self.__context_fields}, '
f'profile_fast={self.__profile_fast}, '
f'ld_preload_actions={self.__ld_preload_actions})'
)
8 changes: 4 additions & 4 deletions tracetools_trace/tracetools_trace/tools/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ def add_arguments(parser: argparse.ArgumentParser) -> None:
'provide this flag without any event name]')
events_kernel_arg.completer = DefaultArgValueCompleter(events_kernel_arg) # type: ignore
context_arg = parser.add_argument( # type: ignore
'-c', '--context', nargs='*', dest='context_names', metavar='CONTEXT',
'-c', '--context', nargs='*', dest='context_fields', metavar='CONTEXT',
default=names.DEFAULT_CONTEXT,
help='the context names to enable (default: see tracetools_trace.tools.names) '
'[to disable all context names, '
'provide this flag without any name]')
help='the context fields to enable (default: see tracetools_trace.tools.names) '
'[to disable all context fields, '
'provide this flag without any field names]')
context_arg.completer = DefaultArgValueCompleter(context_arg) # type: ignore
parser.add_argument(
'-l', '--list', dest='list', action='store_true',
Expand Down
59 changes: 35 additions & 24 deletions tracetools_trace/tracetools_trace/tools/lttng_impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from typing import Optional
from typing import Set
from typing import Union
import warnings

import lttng

Expand Down Expand Up @@ -59,7 +60,8 @@ def setup(
base_path: str,
ros_events: Union[List[str], Set[str]] = DEFAULT_EVENTS_ROS,
kernel_events: Union[List[str], Set[str]] = DEFAULT_EVENTS_KERNEL,
context_names: Union[List[str], Set[str], Dict[str, List[str]]] = DEFAULT_CONTEXT,
context_fields: Union[List[str], Set[str], Dict[str, List[str]]] = DEFAULT_CONTEXT,
context_names: Optional[Union[List[str], Set[str], Dict[str, List[str]]]] = None,
channel_name_ust: str = 'ros2',
channel_name_kernel: str = 'kchan',
) -> Optional[str]:
Expand All @@ -72,13 +74,20 @@ def setup(
:param base_path: the path to the directory in which to create the tracing session directory
:param ros_events: list of ROS events to enable
:param kernel_events: list of kernel events to enable
:param context_names: the names of context fields to enable
:param context_fields: the names of context fields to enable
if it's a list or a set, the context fields are enabled for both kernel and userspace;
if it's a dictionary: { domain type string -> context fields list }
:param context_names: DEPRECATED, use context_fields instead
:param channel_name_ust: the UST channel name
:param channel_name_kernel: the kernel channel name
:return: the full path to the trace directory
"""
# Use value from deprecated param if it is provided
# TODO(christophebedard) remove context_names param in Rolling after Humble release
if context_names is not None:
context_fields = context_names
warnings.warn('context_names parameter is deprecated, use context_fields', stacklevel=4)

# Check if there is a session daemon running
if lttng.session_daemon_alive() == 0:
# Otherwise spawn one without doing any error checks
Expand All @@ -91,8 +100,8 @@ def setup(
ros_events = set(ros_events)
if not isinstance(kernel_events, set):
kernel_events = set(kernel_events)
if isinstance(context_names, list):
context_names = set(context_names)
if isinstance(context_fields, list):
context_fields = set(context_fields)

# Resolve full tracing directory path
full_path = os.path.join(base_path, session_name)
Expand Down Expand Up @@ -156,7 +165,7 @@ def setup(

# Context
contexts_dict = _normalize_contexts_dict(
{'kernel': handle_kernel, 'userspace': handle_ust}, context_names)
{'kernel': handle_kernel, 'userspace': handle_ust}, context_fields)
_add_context(contexts_dict)

return full_path
Expand Down Expand Up @@ -304,57 +313,58 @@ def _enable_events(
}


def _context_name_to_type(
context_name: str,
def _context_field_name_to_type(
context_field_name: str,
) -> Optional[int]:
"""
Convert from context name to LTTng enum/constant type.
:param context_name: the generic name for the context
:param context_field_name: the generic name for the context field
:return: the associated type, or `None` if it cannot be found
"""
return context_map.get(context_name, None)
return context_map.get(context_field_name, None)


def _create_context_list(
context_names: Set[str],
context_fields: Set[str],
) -> List[lttng.EventContext]:
"""
Create context list from names, and check for errors.
Create context list from field names, and check for errors.
:param context_names: the set of context names
:param context_fields: the set of context fields
:return: the event context list
"""
context_list = []
for context_name in context_names:
for context_field_name in context_fields:
ec = lttng.EventContext()
context_type = _context_name_to_type(context_name)
context_type = _context_field_name_to_type(context_field_name)
if context_type is not None:
ec.ctx = context_type
context_list.append(ec)
else:
raise RuntimeError(f'failed to find context type: {context_name}')
raise RuntimeError(f'failed to find context type: {context_field_name}')
return context_list


def _normalize_contexts_dict(
handles: Dict[str, Optional[lttng.Handle]],
contexts: Union[Set[str], Dict[str, List[str]]],
context_fields: Union[Set[str], Dict[str, List[str]]],
) -> Dict[lttng.Handle, List[lttng.EventContext]]:
"""
Normalize context list/set/dict to dict.
:param handles: the mapping from domain type name to handle
:param contexts: the set of context field names,
:param context_fields: the set of context field names,
or mapping from domain type name to list of context field names
:return: a dictionary of handle to list of event contexts
"""
handles = {domain: handle for domain, handle in handles.items() if handle is not None}
contexts_dict = {}
if isinstance(contexts, set):
contexts_dict = {h: _create_context_list(contexts) for _, h in handles.items()}
elif isinstance(contexts, dict):
contexts_dict = {h: _create_context_list(set(contexts[d])) for d, h in handles.items()}
if isinstance(context_fields, set):
contexts_dict = {h: _create_context_list(context_fields) for _, h in handles.items()}
elif isinstance(context_fields, dict):
contexts_dict = \
{h: _create_context_list(set(context_fields[d])) for d, h in handles.items()}
else:
assert False
return contexts_dict
Expand All @@ -369,7 +379,8 @@ def _add_context(
:param contexts: the dictionay of context handles -> event contexts
"""
for handle, contexts_list in contexts.items():
for contex in contexts_list:
result = lttng.add_context(handle, contex, None, None)
for context in contexts_list:
result = lttng.add_context(handle, context, None, None)
if result < 0:
raise RuntimeError(f'failed to add context: {lttng.strerror(result)}')
raise RuntimeError(
f'failed to add context field {str(context)}: {lttng.strerror(result)}')
Loading

0 comments on commit d196944

Please sign in to comment.