aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/network_services/helpers/cpu.py
blob: 279af204ad4919bcc6a3327cf0fbd268d902ce15 (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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# Copyright (c) 2016-2017 Intel Corporation
#
# 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.


import io

# Number of threads per core.
NR_OF_THREADS = 2


class CpuSysCores(object):

    def __init__(self, connection=""):
        self.core_map = {}
        self.cpuinfo = {}
        self.connection = connection

    def _open_cpuinfo(self):
        cpuinfo = io.BytesIO()
        self.connection.get_file_obj("/proc/cpuinfo", cpuinfo)
        lines = cpuinfo.getvalue().decode('utf-8').splitlines()
        return lines

    def _get_core_details(self, lines):
        core_details = []
        core_lines = {}
        for line in lines:
            if line.strip():
                name, value = line.split(":", 1)
                core_lines[name.strip()] = value.strip()
            else:
                core_details.append(core_lines)
                core_lines = {}

        return core_details

    def get_core_socket(self):
        lines = self.connection.execute("lscpu")[1].split(u'\n')
        num_cores = self._get_core_details(lines)
        for num in num_cores:
            self.core_map["cores_per_socket"] = num["Core(s) per socket"]
            self.core_map["thread_per_core"] = num["Thread(s) per core"]

        lines = self._open_cpuinfo()
        core_details = self._get_core_details(lines)
        for core in core_details:
            for k, _ in core.items():
                if k == "physical id":
                    if core["physical id"] not in self.core_map:
                        self.core_map[core['physical id']] = []
                    self.core_map[core['physical id']].append(
                        core["processor"])

        return self.core_map

    def get_cpu_layout(self):
        _, stdout, _ = self.connection.execute("lscpu -p")
        self.cpuinfo = {}
        self.cpuinfo['cpuinfo'] = list()
        for line in stdout.split("\n"):
            if line and line[0] != "#":
                self.cpuinfo['cpuinfo'].append(
                    [CpuSysCores._str2int(x) for x in
                     line.split(",")])
        return self.cpuinfo

    def validate_cpu_cfg(self, vnf_cfg=None):
        if vnf_cfg is None:
            vnf_cfg = {
                'lb_config': 'SW',
                'lb_count': 1,
                'worker_config': '1C/1T',
                'worker_threads': 1
            }
        if self.core_map["thread_per_core"] == 1 and \
                vnf_cfg["worker_config"] == "1C/2T":
            return -1

        if vnf_cfg['lb_config'] == 'SW':
            num_cpu = int(vnf_cfg["worker_threads"]) + 5
            if int(self.core_map["cores_per_socket"]) < num_cpu:
                return -1

        return 0

    def is_smt_enabled(self):
        return CpuSysCores.smt_enabled(self.cpuinfo)

    def cpu_list_per_node(self, cpu_node, smt_used=False):
        cpu_node = int(cpu_node)
        cpu_info = self.cpuinfo.get("cpuinfo")
        if cpu_info is None:
            raise RuntimeError("Node cpuinfo not available.")

        smt_enabled = self.is_smt_enabled()
        if not smt_enabled and smt_used:
            raise RuntimeError("SMT is not enabled.")

        cpu_list = []
        for cpu in cpu_info:
            if cpu[3] == cpu_node:
                cpu_list.append(cpu[0])

        if not smt_enabled or smt_enabled and smt_used:
            pass

        if smt_enabled and not smt_used:
            cpu_list_len = len(cpu_list)
            cpu_list = cpu_list[:int(cpu_list_len / NR_OF_THREADS)]

        return cpu_list

    def cpu_slice_of_list_per_node(self, cpu_node, skip_cnt=0, cpu_cnt=0,
                                   smt_used=False):
        cpu_list = self.cpu_list_per_node(cpu_node, smt_used)

        cpu_list_len = len(cpu_list)
        if cpu_cnt + skip_cnt > cpu_list_len:
            raise RuntimeError("cpu_cnt + skip_cnt > length(cpu list).")

        if cpu_cnt == 0:
            cpu_cnt = cpu_list_len - skip_cnt

        if smt_used:
            cpu_list_0 = cpu_list[:int(cpu_list_len / NR_OF_THREADS)]
            cpu_list_1 = cpu_list[int(cpu_list_len / NR_OF_THREADS):]
            cpu_list = [cpu for cpu in cpu_list_0[skip_cnt:skip_cnt + cpu_cnt]]
            cpu_list_ex = [cpu for cpu in
                           cpu_list_1[skip_cnt:skip_cnt + cpu_cnt]]
            cpu_list.extend(cpu_list_ex)
        else:
            cpu_list = [cpu for cpu in cpu_list[skip_cnt:skip_cnt + cpu_cnt]]

        return cpu_list

    def cpu_list_per_node_str(self, cpu_node, skip_cnt=0, cpu_cnt=0, sep=",",
                              smt_used=False):
        cpu_list = self.cpu_slice_of_list_per_node(cpu_node,
                                                   skip_cnt=skip_cnt,
                                                   cpu_cnt=cpu_cnt,
                                                   smt_used=smt_used)
        return sep.join(str(cpu) for cpu in cpu_list)

    @staticmethod
    def _str2int(string):
        try:
            return int(string)
        except ValueError:
            return 0

    @staticmethod
    def smt_enabled(cpuinfo):
        cpu_info = cpuinfo.get("cpuinfo")
        if cpu_info is None:
            raise RuntimeError("Node cpuinfo not available.")
        cpu_mems = [item[-4:] for item in cpu_info]
        cpu_mems_len = int(len(cpu_mems) / NR_OF_THREADS)
        count = 0
        for cpu_mem in cpu_mems[:cpu_mems_len]:
            if cpu_mem in cpu_mems[cpu_mems_len:]:
                count += 1
        return count == cpu_mems_len