038e86e7a0fdb6adb95d21b090e89a77c8a447be
[csit.git] / resources / tools / telemetry / bundle_perf_stat.py
1 # Copyright (c) 2022 Cisco and/or its affiliates.
2 # Licensed under the Apache License, Version 2.0 (the "License");
3 # you may not use this file except in compliance with the License.
4 # You may obtain a copy of the License at:
5 #
6 #     http://www.apache.org/licenses/LICENSE-2.0
7 #
8 # Unless required by applicable law or agreed to in writing, software
9 # distributed under the License is distributed on an "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 # See the License for the specific language governing permissions and
12 # limitations under the License.
13
14 """Perf Stat performance bundle."""
15
16 from logging import getLogger
17 import sys
18 import subprocess
19
20 from .constants import Constants
21
22
23 class BundlePerfStat:
24     """
25     Creates a Perf stat object. This is the main object for defining a Perf Stat
26     program and interacting with its output.
27
28     Syntax: perf stat [-e <EVENT> | --event=EVENT] [-a] — <command> [<options>]
29     """
30     def __init__(self, program, serializer, hook):
31         """Initialize Bundle Perf Stat event class.
32
33         :param program: events
34         :param serializer: Metric serializer.
35         :param hook: Process ID.
36         :type program: dict
37         :type serializer: Serializer
38         :type hook: int
39         """
40         self.metrics = program[u"metrics"]
41         self.events = program[u"events"]
42         self.api_replies_list = list()
43         self.serializer = serializer
44         self.hook = hook
45
46     def attach(self, duration=1):
47         """
48                Performs perf stat.
49
50                :param duration: Time how long perf stat is collecting data (in
51                seconds). Default value is 1 second.
52                :type duration: int
53                EventCode, UMask, EdgeDetect, AnyThread, Invert, CounterMask
54                """
55         try:
56             self.serializer.create(metrics=self.metrics)
57             for event in self.events:
58                 text = subprocess.getoutput(
59                     f"""sudo perf stat -x\; -e\
60                     '{{cpu/event={hex(event[u"EventCode"])},\
61                     umask={hex(event[u"UMask"])}/u}}'\
62                     -a --per-thread\
63                     sleep {duration}"""
64                 )
65
66                 if text == u"":
67                     getLogger("console_stdout").info(event[u"name"])
68                     continue
69                 if u";" not in text:
70                     getLogger("console_stdout").info(
71                         f"Could not get counters for event \"{event[u'name']}\""
72                         f". Is it supported by CPU?"
73                     )
74                     continue
75
76                 for line in text.splitlines():
77                     item = dict()
78                     labels = dict()
79                     item[u"name"] = event[u"name"]
80                     item[u"value"] = line.split(";")[1]
81                     labels["thread"] = u"-".join(
82                         line.split(";")[0].split("-")[0:-1]
83                     )
84                     labels["pid"] = line.split(";")[0].split("-")[-1]
85                     labels["name"] = item[u"name"]
86                     item[u"labels"] = labels
87
88                     getLogger("console_stdout").info(item)
89                     self.api_replies_list.append(item)
90
91         except AttributeError:
92             getLogger("console_stderr").error(f"Could not successfully run "
93                                               f"perf stat command.")
94             sys.exit(Constants.err_linux_perf_stat)
95
96     def detach(self):
97         pass
98
99     def fetch_data(self):
100        pass
101
102     def process_data(self):
103         """
104         Post process API replies.
105         """
106         for item in self.api_replies_list:
107             self.serializer.serialize(
108                 metric=item[u"name"], labels=item[u"labels"], item=item
109             )