85c2e843e4053c565890bbb865fd37e80d701096
[csit.git] / resources / libraries / python / CpuUtils.py
1 # Copyright (c) 2016 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 """CPU utilities library"""
15
16 from resources.libraries.python.ssh import SSH
17
18 __all__ = ["CpuUtils"]
19
20 class CpuUtils(object):
21     """CPU utilities"""
22
23     @staticmethod
24     def __str2int(string):
25         """Conversion from string to integer, 0 in case of empty string.
26
27         :param string: Input string.
28         :type string: str
29         :return: Integer converted from string, 0 in case of ValueError.
30         :rtype: int
31         """
32         try:
33             return int(string)
34         except ValueError:
35             return 0
36
37     @staticmethod
38     def get_cpu_layout_from_all_nodes(nodes):
39         """Retrieve cpu layout from all nodes, assuming all nodes
40            are Linux nodes.
41
42         :param nodes: DICT__nodes from Topology.DICT__nodes.
43         :type nodes: dict
44         """
45         ssh = SSH()
46         for node in nodes.values():
47             ssh.connect(node)
48             cmd = "lscpu -p"
49             ret, stdout, stderr = ssh.exec_command(cmd)
50 #           parsing of "lscpu -p" output:
51 #           # CPU,Core,Socket,Node,,L1d,L1i,L2,L3
52 #           0,0,0,0,,0,0,0,0
53 #           1,1,0,0,,1,1,1,0
54             if ret != 0:
55                 raise RuntimeError(
56                     "Failed to execute ssh command, ret: {} err: {}".format(
57                         ret, stderr))
58             node['cpuinfo'] = list()
59             for line in stdout.split("\n"):
60                 if len(line) > 0 and line[0] != "#":
61                     node['cpuinfo'].append([CpuUtils.__str2int(x) for x in
62                                             line.split(",")])
63
64     @staticmethod
65     def cpu_node_count(node):
66         """Return count of numa nodes.
67
68         :param node: Targeted node.
69         :type node: dict
70         :return: Count of numa nodes.
71         :rtype: int
72         """
73         cpuinfo = node.get("cpuinfo")
74         if cpuinfo is not None:
75             return node["cpuinfo"][-1][3] + 1
76         else:
77             raise RuntimeError("Node cpuinfo not available.")
78
79     @staticmethod
80     def cpu_list_per_node(node, cpu_node):
81         """Return node related list of CPU numbers.
82
83         :param node: Node dictionary with cpuinfo.
84         :param cpu_node: Numa node number.
85         :type node: int
86         :type cpu_node: int
87         :return: List of cpu numbers related to numa from argument.
88         :rtype: list of int
89         """
90         cpu_node = int(cpu_node)
91         cpuinfo = node.get("cpuinfo")
92         cpulist = []
93         if cpuinfo is not None:
94             for cpu in cpuinfo:
95                 if cpu[3] == cpu_node:
96                     cpulist.append(cpu[0])
97         else:
98             raise RuntimeError("Node cpuinfo not available.")
99
100         return cpulist
101
102     @staticmethod
103     def cpu_list_per_node_str(node, cpu_node, skip_cnt=0,
104                               cpu_cnt=0, sep=","):
105         """Return string of node related list of CPU numbers.
106
107         :param node: Node dictionary with cpuinfo.
108         :param cpu_node: Numa node number.
109         :param skip_cnt: Skip first "skip_cnt" CPUs.
110         :param cpu_cnt: Count of cpus to return, if 0 then return all.
111         :param sep: Separator, default: 1,2,3,4,....
112         :type node: dict
113         :type cpu_node: int
114         :type skip_cnt: int
115         :type cpu_cnt: int
116         :type sep: str
117         :return: Cpu numbers related to numa from argument.
118         :rtype: str
119         """
120
121         cpu_list = CpuUtils.cpu_list_per_node(node, cpu_node)
122         cpu_list_len = len(cpu_list)
123         cpu_flist = ""
124         if cpu_cnt == 0:
125             cpu_cnt = cpu_list_len - skip_cnt
126
127         if cpu_cnt + skip_cnt > cpu_list_len:
128             raise RuntimeError("cpu_cnt + skip_cnt > length(cpu list).")
129
130         cpu_flist = sep.join(str(a) for a in
131                              cpu_list[skip_cnt:skip_cnt+cpu_cnt])
132
133         return cpu_flist