aboutsummaryrefslogtreecommitdiff
path: root/trappy/bare_trace.py
blob: c2f4b04e2a0664a04bc8cfbf4c6b07216bf12f59 (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
#    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.
#

import re

class BareTrace(object):
    """A wrapper class that holds dataframes for all the events in a trace.

    BareTrace doesn't parse any file so it's a class that should
    either be (a) subclassed to parse a particular trace (like FTrace)
    or (b) be instantiated and the events added with add_parsed_event()

    :param name: is a string describing the trace.
    :type name: str

    """

    def __init__(self, name=""):
        self.name = name
        self.normalized_time = False
        self.class_definitions = {}
        self.trace_classes = []
        self.basetime = 0

    def get_duration(self):
        """Returns the largest time value of all classes,
        returns 0 if the data frames of all classes are empty"""
        max_durations = []
        min_durations = []

        for trace_class in self.trace_classes:
            try:
                max_durations.append(trace_class.data_frame.index[-1])
                min_durations.append(trace_class.data_frame.index[0])
            except IndexError:
                pass

        if len(min_durations) == 0 or len(max_durations) == 0:
            return 0

        return max(max_durations) - min(min_durations)

    def get_filters(self, key=""):
        """Returns an array with the available filters.

        :param key: If specified, returns a subset of the available filters
            that contain 'key' in their name (e.g., :code:`key="sched"` returns
            only the :code:`"sched"` related filters)."""
        filters = []

        for cls in self.class_definitions:
            if re.search(key, cls):
                filters.append(cls)

        return filters

    def _normalize_time(self, basetime=None):
        """Normalize the time of all the trace classes

        :param basetime: The offset which needs to be subtracted from
            the time index
        :type basetime: float
        """

        if basetime is not None:
            self.basetime = basetime

        for trace_class in self.trace_classes:
            trace_class.normalize_time(self.basetime)

        self.normalized_time = True

    def add_parsed_event(self, name, dfr, pivot=None):
        """Add a dataframe to the events in this trace

        This function lets you add other events that have been parsed
        by other tools to the collection of events in this instance.  For
        example, assuming you have some events in a csv, you could add
        them to a trace instance like this:

        >>> trace = trappy.BareTrace()
        >>> counters_dfr = pd.DataFrame.from_csv("counters.csv")
        >>> trace.add_parsed_event("pmu_counters", counters_dfr)

        Now you can access :code:`trace.pmu_counters` as you would with any
        other trace event and other trappy classes can interact with
        them.

        :param name: The attribute name in this trace instance.  As in the example above, if :code:`name` is "pmu_counters", the parsed event will be accessible using :code:`trace.pmu_counters`.
        :type name: str

        :param dfr: :mod:`pandas.DataFrame` containing the events.  Its index should be time in seconds.  Its columns are the events.
        :type dfr: :mod:`pandas.DataFrame`

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

        """
        from trappy.base import Base
        from trappy.dynamic import DynamicTypeFactory, default_init

        if hasattr(self, name):
            raise ValueError("event {} already present".format(name))

        kwords = {
            "__init__": default_init,
            "unique_word": name + ":",
            "name": name,
        }

        trace_class = DynamicTypeFactory(name, (Base,), kwords)
        self.class_definitions[name] = trace_class

        event = trace_class()
        self.trace_classes.append(event)
        event.data_frame = dfr
        if pivot:
            event.pivot = pivot

        setattr(self, name, event)

    def finalize_objects(self):
        for trace_class in self.trace_classes:
            # If cached, don't need to do any other DF operation
            if trace_class.cached:
                continue
            trace_class.tracer = self
            trace_class.create_dataframe()
            trace_class.finalize_object()

    def generate_data_dict(self, data_str):
        return None