aboutsummaryrefslogtreecommitdiffstats
path: root/resources/tools/telemetry/bundle_perf_stat.py
blob: 038e86e7a0fdb6adb95d21b090e89a77c8a447be (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
# Copyright (c) 2022 Cisco and/or its affiliates.
# 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.

"""Perf Stat performance bundle."""

from logging import getLogger
import sys
import subprocess

from .constants import Constants


class BundlePerfStat:
    """
    Creates a Perf stat object. This is the main object for defining a Perf Stat
    program and interacting with its output.

    Syntax: perf stat [-e <EVENT> | --event=EVENT] [-a] — <command> [<options>]
    """
    def __init__(self, program, serializer, hook):
        """Initialize Bundle Perf Stat event class.

        :param program: events
        :param serializer: Metric serializer.
        :param hook: Process ID.
        :type program: dict
        :type serializer: Serializer
        :type hook: int
        """
        self.metrics = program[u"metrics"]
        self.events = program[u"events"]
        self.api_replies_list = list()
        self.serializer = serializer
        self.hook = hook

    def attach(self, duration=1):
        """
               Performs perf stat.

               :param duration: Time how long perf stat is collecting data (in
               seconds). Default value is 1 second.
               :type duration: int
               EventCode, UMask, EdgeDetect, AnyThread, Invert, CounterMask
               """
        try:
            self.serializer.create(metrics=self.metrics)
            for event in self.events:
                text = subprocess.getoutput(
                    f"""sudo perf stat -x\; -e\
                    '{{cpu/event={hex(event[u"EventCode"])},\
                    umask={hex(event[u"UMask"])}/u}}'\
                    -a --per-thread\
                    sleep {duration}"""
                )

                if text == u"":
                    getLogger("console_stdout").info(event[u"name"])
                    continue
                if u";" not in text:
                    getLogger("console_stdout").info(
                        f"Could not get counters for event \"{event[u'name']}\""
                        f". Is it supported by CPU?"
                    )
                    continue

                for line in text.splitlines():
                    item = dict()
                    labels = dict()
                    item[u"name"] = event[u"name"]
                    item[u"value"] = line.split(";")[1]
                    labels["thread"] = u"-".join(
                        line.split(";")[0].split("-")[0:-1]
                    )
                    labels["pid"] = line.split(";")[0].split("-")[-1]
                    labels["name"] = item[u"name"]
                    item[u"labels"] = labels

                    getLogger("console_stdout").info(item)
                    self.api_replies_list.append(item)

        except AttributeError:
            getLogger("console_stderr").error(f"Could not successfully run "
                                              f"perf stat command.")
            sys.exit(Constants.err_linux_perf_stat)

    def detach(self):
        pass

    def fetch_data(self):
       pass

    def process_data(self):
        """
        Post process API replies.
        """
        for item in self.api_replies_list:
            self.serializer.serialize(
                metric=item[u"name"], labels=item[u"labels"], item=item
            )