1e81fdcb135d0325e3bc22fae0583555d20aae280Brendan Jackman#    Copyright 2015-2017 ARM Limited
208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino#
308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# Licensed under the Apache License, Version 2.0 (the "License");
408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# you may not use this file except in compliance with the License.
508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# You may obtain a copy of the License at
608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino#
708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino#     http://www.apache.org/licenses/LICENSE-2.0
808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino#
908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# Unless required by applicable law or agreed to in writing, software
1008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# distributed under the License is distributed on an "AS IS" BASIS,
1108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# See the License for the specific language governing permissions and
1308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino# limitations under the License.
1408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino#
1508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
1608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merinoimport re
1708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
1808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merinoclass BareTrace(object):
1908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    """A wrapper class that holds dataframes for all the events in a trace.
2008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
2108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    BareTrace doesn't parse any file so it's a class that should
2208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    either be (a) subclassed to parse a particular trace (like FTrace)
2308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    or (b) be instantiated and the events added with add_parsed_event()
2408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
2508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    :param name: is a string describing the trace.
2608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    :type name: str
2708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
2808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    """
2908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
3008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    def __init__(self, name=""):
3108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.name = name
3208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.normalized_time = False
3308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.class_definitions = {}
3408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.trace_classes = []
3508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.basetime = 0
3608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
3708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    def get_duration(self):
3808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        """Returns the largest time value of all classes,
3908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        returns 0 if the data frames of all classes are empty"""
4008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        durations = []
4108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
4208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        for trace_class in self.trace_classes:
4308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            try:
4408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino                durations.append(trace_class.data_frame.index[-1])
4508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            except IndexError:
4608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino                pass
4708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
4808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        if len(durations) == 0:
4908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            return 0
5008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
5108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        if self.normalized_time:
5208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            return max(durations)
5308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        else:
5408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            return max(durations) - self.basetime
5508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
5608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    def get_filters(self, key=""):
5708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        """Returns an array with the available filters.
5808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
5908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :param key: If specified, returns a subset of the available filters
6008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            that contain 'key' in their name (e.g., :code:`key="sched"` returns
6108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            only the :code:`"sched"` related filters)."""
6208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        filters = []
6308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
6408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        for cls in self.class_definitions:
6508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            if re.search(key, cls):
6608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino                filters.append(cls)
6708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
6808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        return filters
6908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
70b01c848f3928dfcdf2f3d7dae1343bbe677847efChris Redpath    def _normalize_time(self, basetime=None):
7108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        """Normalize the time of all the trace classes
7208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
7308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :param basetime: The offset which needs to be subtracted from
7408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            the time index
7508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :type basetime: float
7608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        """
7708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
7808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        if basetime is not None:
7908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            self.basetime = basetime
8008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
8108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        for trace_class in self.trace_classes:
8208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            trace_class.normalize_time(self.basetime)
8308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
8408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.normalized_time = True
8508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
8608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    def add_parsed_event(self, name, dfr, pivot=None):
8708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        """Add a dataframe to the events in this trace
8808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
8908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        This function lets you add other events that have been parsed
9008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        by other tools to the collection of events in this instance.  For
9108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        example, assuming you have some events in a csv, you could add
9208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        them to a trace instance like this:
9308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
9408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        >>> trace = trappy.BareTrace()
9508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        >>> counters_dfr = pd.DataFrame.from_csv("counters.csv")
9608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        >>> trace.add_parsed_event("pmu_counters", counters_dfr)
9708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
9808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        Now you can access :code:`trace.pmu_counters` as you would with any
9908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        other trace event and other trappy classes can interact with
10008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        them.
10108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
10208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :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`.
10308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :type name: str
10408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
10508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :param dfr: :mod:`pandas.DataFrame` containing the events.  Its index should be time in seconds.  Its columns are the events.
10608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :type dfr: :mod:`pandas.DataFrame`
10708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
10808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :param pivot: The data column about which the data can be grouped
10908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        :type pivot: str
11008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
11108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        """
11208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        from trappy.base import Base
11308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        from trappy.dynamic import DynamicTypeFactory, default_init
11408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
11508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        if hasattr(self, name):
11608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            raise ValueError("event {} already present".format(name))
11708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
11808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        kwords = {
11908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            "__init__": default_init,
12008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            "unique_word": name + ":",
12108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            "name": name,
12208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        }
12308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
12408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        trace_class = DynamicTypeFactory(name, (Base,), kwords)
12508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.class_definitions[name] = trace_class
12608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
12708f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        event = trace_class()
12808f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        self.trace_classes.append(event)
12908f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        event.data_frame = dfr
13008f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        if pivot:
13108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            event.pivot = pivot
13208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
13308f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        setattr(self, name, event)
13408f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino
13508f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino    def finalize_objects(self):
13608f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino        for trace_class in self.trace_classes:
137a951463b87e0a17229d5fcd426b0b05a4ffb0764Joel Fernandes            # If cached, don't need to do any other DF operation
138a951463b87e0a17229d5fcd426b0b05a4ffb0764Joel Fernandes            if trace_class.cached:
139a951463b87e0a17229d5fcd426b0b05a4ffb0764Joel Fernandes                continue
14002c452ef5bcfafe49450059f7927664a393e0235Joel Fernandes            trace_class.tracer = self
14108f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            trace_class.create_dataframe()
14208f3c34d0a24e7ffeff543e302efc911306e7beaJavi Merino            trace_class.finalize_object()
14302c452ef5bcfafe49450059f7927664a393e0235Joel Fernandes
14402c452ef5bcfafe49450059f7927664a393e0235Joel Fernandes    def generate_data_dict(self):
14502c452ef5bcfafe49450059f7927664a393e0235Joel Fernandes        return None
146