aboutsummaryrefslogtreecommitdiff
path: root/trappy/dynamic.py
blob: 5b094ce5cd6a3457782e55c5dae175ea84911bec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#    Copyright 2015-2017 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#


"""The idea is to create a wrapper class that
returns a Type of a Class dynamically created based
on the input parameters. Similar to a factory design
pattern
"""
from trappy.base import Base
import re
from trappy.ftrace import GenericFTrace


def default_init(self):
    """Default Constructor for the
    Dynamic MetaClass. This is used for
    the dynamic object creation in
    :mod:`trappy.dynamic.DynamicTypeFactory`
    """

    kwords = {}

    try:
        kwords["parse_raw"] = self.parse_raw
    except AttributeError:
        pass

    super(type(self), self).__init__(**kwords)


class DynamicTypeFactory(type):

    """Override the type class to create
    a dynamic type on the fly. This Factory
    class is used internally by
    :mod:`trappy.dynamic.register_dynamic_ftrace`
    """

    def __new__(mcs, name, bases, dct):
        """Override the new method"""
        return type.__new__(mcs, name, bases, dct)

    def __init__(cls, name, bases, dct):
        """Override the constructor"""
        super(DynamicTypeFactory, cls).__init__(name, bases, dct)


def _get_name(name):
    """Internal Method to Change camelcase to
    underscores. CamelCase -> camel_case
    """
    return re.sub('(?!^)([A-Z]+)', r'_\1', name).lower()


def register_dynamic_ftrace(class_name, unique_word, scope="all",
                            parse_raw=False, pivot=None):
    """Create a Dynamic FTrace parser and register it with any FTrace parsing classes

    :param class_name: The name of the class to be registered
        (Should be in CamelCase)
    :type class_name: str

    :param unique_word: The unique_word to be matched in the
        trace
    :type unique_word: str

    :param scope: Registry Scope (Can be used to constrain
        the parsing of events and group them together)
    :type scope: str

    :param parse_raw: If, true, raw trace output (-r flag)
        will be used
    :type parse_raw: bool

    :param pivot: The data column about which the data can be grouped
    :type pivot: str

    For example if a new unique word :code:`my_unique_word` has
    to be registered with TRAPpy:
    ::

        import trappy
        custom_class = trappy.register_dynamic_ftrace("MyEvent", "my_unique_word")
        trace = trappy.FTrace("/path/to/trace_file")

        # New data member created in the ftrace object
        trace.my_event

    .. note:: The name of the member is :code:`my_event` from **MyEvent**


    :return: A class object of type :mod:`trappy.base.Base`
    """

    kwords = {
            "__init__": default_init,
            "unique_word": unique_word,
            "name": _get_name(class_name),
            "parse_raw" : parse_raw,
        }

    if pivot:
        kwords["pivot"] = pivot

    dyn_class = DynamicTypeFactory(class_name, (Base,), kwords)
    GenericFTrace.register_parser(dyn_class, scope)
    return dyn_class


def register_ftrace_parser(cls, scope="all"):
    """Register a new FTrace parser class implementation

    Should be used when the class has complex helper methods and does
    not expect to use the default constructor.

    :param cls: The class to be registered for
        enabling the parsing of an event in trace
    :type cls: :mod:`trappy.base.Base`

    :param scope: scope of this parser class.  The scope can be used
        to restrict the parsing done on an individual file.  Currently
        the only scopes available are "sched", "thermal" or "all"
    :type scope: string

    """

    # Check the argspec of the class
    GenericFTrace.register_parser(cls, scope)

def unregister_ftrace_parser(ftrace_parser):
    """Unregister an ftrace parser

    :param ftrace_parser: An ftrace parser class that was registered
        with register_ftrace_parser() or register_dynamic_ftrace().
        If done with the latter, the cls parameter is the return value
        of register_dynamic_ftrace()
    :type ftrace_parser: class derived from :mod:`trappy.base.Base`

    """
    GenericFTrace.unregister_parser(ftrace_parser)