c978441d72ed79b7dfbacfa53c67b5baffce88ac
[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     @staticmethod
125     def run_telemetry_on_all_duts(nodes, profile):
126         """Get telemetry stat read on all DUTs.
127
128         :param nodes: Nodes in the topology.
129         :param profile: Telemetry configuration profile.
130         :param hooks: Dict of Process IDs or socket paths (optional).
131         :type nodes: dict
132         :type profile: str
133         :type hooks: dict
134         """
135         for node in nodes.values():
136             if node[u"type"] == NodeType.DUT:
137                 try:
138                     for socket in node[u"sockets"][u"CLI"].values():
139                         TelemetryUtil.run_telemetry(
140                             node, profile=profile, hook=socket
141                         )
142                 except IndexError:
143                     pass