-
Notifications
You must be signed in to change notification settings - Fork 39
trappy: Add support for 'print:' ftrace fallback event [v2] #280
trappy: Add support for 'print:' ftrace fallback event [v2] #280
Conversation
[1] Event parser objects are stored in the per-scope (i.e. sched/thermal/dynamic) dicts at import time via register_parser. These dicts are keyed using the 'name' attribute of the event parsers. [2] During trace construction the class_definitions attribute is initially created from the per-scope objects created in [1]. [3] Then, for each event requested by the 'events' parameter, the event class is added to class_definitions (they may already be present, having been added in [2], in which case this _should_ be a nop). Some event classes may have a `name` that is different from the actual event name that is printed in the trace (i.e. `unique_word`), for example the 'print' event is parsed by a parser class (to be added) whose 'name' is 'print_' in order to avoid keyword collisions. Since step [1] currently uses `name` to index class_definitions but step [3] uses the actual printed event name (i.e. `unique_word`), the expected no-op I mentioned above actually results in two instances of the same event parser being present in class_definitions. This leads to missing data, where one instance of the event parser has a populated DataFrame and the other does not, and causes great angst, woe and distress in developers. So instead always use `name` to index class_definitions. This bug was being taken advantage of by the systrace/sched tests - the sched_contrib_scale_f event is currently parsed by the SchedContribScaleFactor dynamic ftrace class, whose 'name' attribute (set via trappy.dynamic._get_name) is currently sched_contrib_scale_factor but whose uniqe_word is sched_contrib_scale_f. Therefore ftrace objects haave an attribute with both names. With this commit, the 'sched_contrib_scale_f' attribute is removed, so the test is updated to use 'sched_contrib_scale_factor'
If we have a bug like this we should give up and fix the bug before trying to do anything else, otherwise things will break in desperately confusing ways.
@@ -465,6 +472,33 @@ def __parse_trace_file(self, trace_file): | |||
raise ValueError('Failed to parse ftrace file {}:\n{}'.format( | |||
trace_file, str(e))) | |||
|
|||
def __getattr__(self, attr): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC this is something that's not made explicit in the commit message - this raises an exception when trying to get a dataframe for an event by specifying its unique_word
instead of its name
. #276 instead raised an exception at parse time, which is different, unless I missed something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may need to update the commit message, but the behavior is largely the same. #276 did not raise exception at parse time, it was only when an attribute was accessed on the thing retrieved on the trace. Now, it fails straight away when you try to get "the thing":
# Used to work
trace.my_unique_word
# Used to raise
trace.my_unique_word.data_frame
# Now raises
trace.my_unique_word
trace.my_unique_word.data_frame
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh ok, I missed the set_attr
at the end of __add_warnings
in #276. LGTM then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Three minor nits.
trappy/ftrace.py
Outdated
attr=attr, | ||
name=name | ||
)) | ||
raise AttributeError('{} object has no attribute {}'.format( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't try to imitate the exception that was raised, just let the parent handle it was happening we added this:
return super(GenericFTrace, self).__getattribute__(attr)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, object.getattr does not exist but getattribute does
tests/test_fallback.py
Outdated
@@ -0,0 +1,62 @@ | |||
|
|||
# Copyright 2017 ARM Limited, Google and contributors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2018
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
trappy/fallback.py
Outdated
class FallbackEvent(Base): | ||
""" | ||
Parse free-form events that couldn't be matched with more specific unique | ||
words This class is always used as a fallback if nothing more specific could |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'.' between "words" and "This"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
We used to have a bug where when you had a known event whose 'name' attribute != its 'unique_word', and you specified it explicitly in the 'events' param, we had two attributes - one for the 'name' and one for the 'unique_word', and it was undefined which would be populated. Now we just have the attribute from the 'name'. If there is any code out there that was relying on this bug (i.e. accessing the 'unique_word' atribute), this will tell them what they need to do to fix their code. Co-author: Douglas Raillard <douglas.raillard@arm.com>
Currently if you specify an event in the `events` by the `name` attribute of its parser class, __add_events will add that name to the class_definitions dict. For events in the 'thermal' and 'sched' scopes, that is then overwritten, but for events in the dynamic_classes dict (where scope='all'), this is not the case. That means that a specialised event parser class will be replaced with a basic dynamic parser. Fix that by checking the 'name' field in known_events.
This is just like tracing_mark_write but with a different name. It poses a minor difficulty as its name is a Python 2 keyword (so 'ftrace.print.data_frame' is a syntax error) - this is solved by appending an underscore to the name, as suggested by PEP8. A base class is added which encapsulates the fallback behaviour for both tracing_mark_write and print.
417e4cb
to
2d8e485
Compare
Respin of:
#276
Changelog:
GenericFTrace.__getattr__
instead of introducing an new class. That also allows catching issues earlier.