telemetry: linux telemetry with perf-stat
[csit.git] / resources / libraries / python / TelemetryUtil.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 """Telemetry utility."""
15
16 from robot.api import logger
17 from time import sleep
18
19 from resources.libraries.python.Constants import Constants
20 from resources.libraries.python.VppCounters import VppCounters
21 from resources.libraries.python.OptionString import OptionString
22 from resources.libraries.python.ssh import exec_cmd, exec_cmd_no_error
23 from resources.libraries.python.topology import NodeType
24
25 __all__ = [u"TelemetryUtil"]
26
27
28 class TelemetryUtil:
29     """Class contains methods for telemetry utility."""
30
31     @staticmethod
32     def perf_stat(node, cpu_list=None, duration=1):
33         """Get perf stat read for duration.
34
35         :param node: Node in the topology.
36         :param cpu_list: CPU List as a string separated by comma.
37         :param duration: Measure time in seconds.
38         :type node: dict
39         :type cpu_list: str
40         :type duration: int
41         """
42         if cpu_list:
43             cpu_list = list(dict.fromkeys(cpu_list.split(u",")))
44             cpu_list = ",".join(str(cpu) for cpu in cpu_list)
45
46         cmd_opts = OptionString(prefix=u"--")
47         cmd_opts.add(u"no-aggr")
48         cmd_opts.add_with_value_if(
49             u"cpu", cpu_list, cpu_list
50         )
51         cmd_opts.add_if(
52             u"all-cpus", not(cpu_list)
53         )
54         cmd_opts.add_with_value_if(
55             u"event", f"'{{{Constants.PERF_STAT_EVENTS}}}'",
56             Constants.PERF_STAT_EVENTS
57         )
58         cmd_opts.add_with_value(
59             u"interval-print", 1000
60         )
61         cmd_opts.add_with_value(
62             u"field-separator", u"';'"
63         )
64
65         cmd_base = OptionString()
66         cmd_base.add(f"perf stat")
67         cmd_base.extend(cmd_opts)
68         cmd_base.add(u"--")
69         cmd_base.add_with_value(u"sleep", int(duration))
70
71         exec_cmd(node, cmd_base, sudo=True)
72
73     @staticmethod
74     def perf_stat_on_all_duts(nodes, cpu_list=None, duration=1):
75         """Get perf stat read for duration on all DUTs.
76
77         :param nodes: Nodes in the topology.
78         :param cpu_list: CPU List.
79         :param duration: Measure time in seconds.
80         :type nodes: dict
81         :type cpu_list: str
82         :type duration: int
83         """
84         for node in nodes.values():
85             if node[u"type"] == NodeType.DUT:
86                 TelemetryUtil.perf_stat(
87                     node, cpu_list=cpu_list, duration=duration
88                 )
89
90     @staticmethod
91     def run_telemetry(node, profile, hook=None):
92         """Get telemetry stat read for duration.
93
94         :param node: Node in the topology.
95         :param profile: Telemetry configuration profile.
96         :param hook: Process ID or socket path (optional).
97         :type node: dict
98         :type profile: str
99         :type hook: str
100         """
101         config = u""
102         config += f"{Constants.REMOTE_FW_DIR}/"
103         config += f"{Constants.RESOURCES_TPL_TELEMETRY}/"
104         config += f"{profile}"
105
106         cd_cmd = u""
107         cd_cmd += f"sh -c \"cd {Constants.REMOTE_FW_DIR}/"
108         cd_cmd += f"{Constants.RESOURCES_TOOLS}"
109
110         bin_cmd = f"python3 -m telemetry --config {config} --hook {hook}\""
111         hostname = node[u"host"]
112
113         exec_cmd_no_error(node, f"{cd_cmd} && {bin_cmd}", sudo=True)
114         stdout, _ = exec_cmd_no_error(
115             node, u"cat /tmp/metric.prom", sudo=True, log_stdout_err=False
116         )
117         logger.info(
118             u"# TYPE target info\n"
119             u"# HELP target Target metadata\n"
120             f"target_info{{hostname=\"{hostname}\",hook=\"{hook}\"}} 1\n"
121             f"{stdout}"
122         )
123
124         VppCounters.vpp_clear_runtime(node)
125         sleep(1)
126         VppCounters.vpp_show_runtime(node)
127
128     @staticmethod
129     def run_telemetry_on_all_duts(nodes, profile):
130         """Get telemetry stat read on all DUTs.
131
132         :param nodes: Nodes in the topology.
133         :param profile: Telemetry configuration profile.
134         :param hooks: Dict of Process IDs or socket paths (optional).
135         :type nodes: dict
136         :type profile: str
137         :type hooks: dict
138         """
139         for node in nodes.values():
140             if node[u"type"] == NodeType.DUT:
141                 try:
142                     for socket in node[u"sockets"][u"CLI"].values():
143                         TelemetryUtil.run_telemetry(
144                             node, profile=profile, hook=socket
145                         )
146                 except IndexError:
147                     pass