Merge "dpdk: Support of DPDK16.07-rc5 and newer"
[vswitchperf.git] / tools / systeminfo.py
1 # Copyright 2015-2016 Intel Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #   http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14
15 """Tools for access to OS details
16 """
17
18 import os
19 import platform
20 import subprocess
21 import locale
22
23 from conf import settings as S
24
25 def match_line(file_name, pattern):
26     """ loops through given file and returns first line matching given pattern
27
28     :returns: string with the matching line without end of line or None
29     """
30     try:
31         with open(file_name, encoding="latin-1") as file_:
32             for line in file_:
33                 if not line.strip():
34                     continue
35                 if not line.strip().startswith(pattern):
36                     continue
37
38                 return line.strip().rstrip('\n')
39         return None
40     except OSError:
41         return None
42
43 def get_os():
44     """Get distro name.
45
46     :returns: Return distro name as a string
47     """
48     return ' '.join(platform.dist())
49
50 def get_kernel():
51     """Get kernel version.
52
53     :returns: Return kernel version as a string
54     """
55     return platform.release()
56
57 def get_cpu():
58     """Get CPU information.
59
60     :returns: Return CPU information as a string
61     """
62     cpu = match_line('/proc/cpuinfo', 'model name')
63     return cpu.split(':')[1] if cpu else cpu
64
65 def get_nic():
66     """Get NIC(s) information.
67
68     :returns: Return NIC(s) information as a list
69     """
70     nics = []
71     output = subprocess.check_output('lspci', shell=True)
72     output = output.decode(locale.getdefaultlocale()[1])
73     for line in output.split('\n'):
74         for nic in S.getValue('NICS'):
75             # lspci shows PCI addresses without domain part, i.e. last 7 chars
76             if line.startswith(nic['pci'][-7:]):
77                 nics.append(''.join(line.split(':')[2:]).strip())
78     return nics
79
80 def get_platform():
81     """Get platform information.
82
83     Currently this is the motherboard vendor, name and socket
84     count.
85
86     :returns: Return platform information as a string
87     """
88     output = []
89
90     with open('/sys/class/dmi/id/board_vendor', 'r') as file_:
91         output.append(file_.readline().rstrip())
92
93     with open('/sys/class/dmi/id/board_name', 'r') as file_:
94         output.append(file_.readline().rstrip())
95
96     num_nodes = len([name for name in os.listdir(
97         '/sys/devices/system/node/') if name.startswith('node')])
98     output.append(''.join(['[', str(num_nodes), ' sockets]']))
99
100     return ' '.join(output).strip()
101
102 def get_cpu_cores():
103     """Get number of CPU cores.
104
105     :returns: Return number of CPU cores
106     """
107     cores = 0
108     with open('/proc/cpuinfo') as file_:
109         for line in file_:
110             if line.rstrip('\n').startswith('processor'):
111                 cores += 1
112             continue
113
114     # this code must be executed by at leat one core...
115     if cores < 1:
116         cores = 1
117     return cores
118
119 def get_memory():
120     """Get memory information.
121
122     :returns: amount of system memory as string together with unit
123     """
124     memory = match_line('/proc/meminfo', 'MemTotal')
125     return memory.split(':')[1].strip() if memory else memory
126
127 def get_memory_bytes():
128     """Get memory information in bytes
129
130     :returns: amount of system memory
131     """
132     mem_list = get_memory().split(' ')
133     mem = float(mem_list[0].strip())
134     if mem_list.__len__() > 1:
135         unit = mem_list[1].strip().lower()
136         if unit == 'kb':
137             mem *= 1024
138         elif unit == 'mb':
139             mem *= 1024 ** 2
140         elif unit == 'gb':
141             mem *= 1024 ** 3
142         elif unit == 'tb':
143             mem *= 1024 ** 4
144
145     return int(mem)
146
147 def get_pids(proc_names_list):
148     """ Get pid(s) of process(es) with given name(s)
149
150     :returns: list with pid(s) of given processes or None if processes
151         with given names are not running
152     """
153
154     try:
155         pids = subprocess.check_output(['sudo', 'LC_ALL=' + S.getValue('DEFAULT_CMD_LOCALE'), 'pidof']
156                                        + proc_names_list)
157     except subprocess.CalledProcessError:
158         # such process isn't running
159         return None
160
161     return list(map(str, map(int, pids.split())))
162
163 def get_pid(proc_name_str):
164     """ Get pid(s) of process with given name
165
166     :returns: list with pid(s) of given process or None if process
167         with given name is not running
168     """
169     return get_pids([proc_name_str])
170
171 def pid_isalive(pid):
172     """ Checks if given PID is alive
173
174     :param pid: PID of the process
175     :returns: True if given process is running, False otherwise
176     """
177     return os.path.isdir('/proc/' + str(pid))
178
179 # This function uses long switch per purpose, so let us suppress pylint warning too-many-branches
180 # pylint: disable=R0912
181 def get_version(app_name):
182     """ Get version of given application and its git tag
183
184     :returns: dictionary {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag) in case that
185         version or git tag are not known or not applicaple, than None is returned for any unknown value
186
187     """
188     app_version_file = {
189         'ovs' : os.path.join(S.getValue('OVS_DIR'), 'include/openvswitch/version.h'),
190         'dpdk' : os.path.join(S.getValue('RTE_SDK'), 'lib/librte_eal/common/include/rte_version.h'),
191         'qemu' : os.path.join(S.getValue('QEMU_DIR'), 'VERSION'),
192         'l2fwd' : os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/l2fwd.c'),
193         'ixnet' : os.path.join(S.getValue('TRAFFICGEN_IXNET_LIB_PATH'), 'pkgIndex.tcl'),
194     }
195
196
197     def get_git_tag(path):
198         """ get tag of recent commit from repository located at 'path'
199
200         :returns: git tag in form of string with commit hash or None if there
201             isn't any git repository at given path
202         """
203         try:
204             if os.path.isdir(path):
205                 return subprocess.check_output('cd {}; git rev-parse HEAD'.format(path), shell=True,
206                                                stderr=subprocess.DEVNULL).decode().rstrip('\n')
207             elif os.path.isfile(path):
208                 return subprocess.check_output('cd $(dirname {}); git log -1 --pretty="%H" {}'.format(path, path),
209                                                shell=True, stderr=subprocess.DEVNULL).decode().rstrip('\n')
210             else:
211                 return None
212         except subprocess.CalledProcessError:
213             return None
214
215
216     app_version = None
217     app_git_tag = None
218
219     if app_name.lower().startswith('ovs'):
220         app_version = match_line(app_version_file['ovs'], '#define OVS_PACKAGE_VERSION')
221         if app_version:
222             app_version = app_version.split('"')[1]
223         app_git_tag = get_git_tag(S.getValue('OVS_DIR'))
224     elif app_name.lower() in ['dpdk', 'testpmd']:
225         tmp_ver = ['', '', '']
226         dpdk_16 = False
227         with open(app_version_file['dpdk']) as file_:
228             for line in file_:
229                 if not line.strip():
230                     continue
231                 # DPDK version < 16
232                 if line.startswith('#define RTE_VER_MAJOR'):
233                     tmp_ver[0] = line.rstrip('\n').split(' ')[2]
234                 # DPDK version < 16
235                 elif line.startswith('#define RTE_VER_PATCH_LEVEL'):
236                     tmp_ver[2] = line.rstrip('\n').split(' ')[2]
237                 # DPDK version < 16
238                 elif line.startswith('#define RTE_VER_PATCH_RELEASE'):
239                     release = line.rstrip('\n').split(' ')[2]
240                     if not '16' in release:
241                         tmp_ver[2] += line.rstrip('\n').split(' ')[2]
242                 # DPDK all versions
243                 elif line.startswith('#define RTE_VER_MINOR'):
244                     if dpdk_16:
245                         tmp_ver[2] = line.rstrip('\n').split(' ')[2]
246                     else:
247                         tmp_ver[1] = line.rstrip('\n').split(' ')[2]
248                 # DPDK all versions
249                 elif line.startswith('#define RTE_VER_SUFFIX'):
250                     tmp_ver[2] += line.rstrip('\n').split('"')[1]
251                 # DPDK version >= 16
252                 elif line.startswith('#define RTE_VER_YEAR'):
253                     dpdk_16 = True
254                     tmp_ver[0] = line.rstrip('\n').split(' ')[2]
255                 # DPDK version >= 16
256                 elif line.startswith('#define RTE_VER_MONTH'):
257                     tmp_ver[1] = '{:0>2}'.format(line.rstrip('\n').split(' ')[2])
258                 # DPDK version >= 16
259                 elif line.startswith('#define RTE_VER_RELEASE'):
260                     release = line.rstrip('\n').split(' ')[2]
261                     if not '16' in release:
262                         tmp_ver[2] += line.rstrip('\n').split(' ')[2]
263
264         if len(tmp_ver[0]):
265             app_version = '.'.join(tmp_ver)
266         app_git_tag = get_git_tag(S.getValue('RTE_SDK'))
267     elif app_name.lower().startswith('qemu'):
268         app_version = match_line(app_version_file['qemu'], '')
269         app_git_tag = get_git_tag(S.getValue('QEMU_DIR'))
270     elif app_name.lower() == 'ixnet':
271         app_version = match_line(app_version_file['ixnet'], 'package provide IxTclNetwork')
272         if app_version:
273             app_version = app_version.split(' ')[3]
274     elif app_name.lower() == 'xena':
275         try:
276             app_version = S.getValue('XENA_VERSION')
277         except AttributeError:
278             # setting was not available after execution
279             app_version = 'N/A'
280     elif app_name.lower() == 'dummy':
281         # get git tag of file with Dummy implementation
282         app_git_tag = get_git_tag(os.path.join(S.getValue('ROOT_DIR'), 'tools/pkt_gen/dummy/dummy.py'))
283     elif app_name.lower() == 'vswitchperf':
284         app_git_tag = get_git_tag(S.getValue('ROOT_DIR'))
285     elif app_name.lower() == 'l2fwd':
286         app_version = match_line(app_version_file[app_name], 'MODULE_VERSION')
287         if app_version:
288             app_version = app_version.split('"')[1]
289         app_git_tag = get_git_tag(app_version_file[app_name])
290     elif app_name.lower() in ['linux_bridge', 'buildin']:
291         # without login into running VM, it is not possible to check bridge_utils version
292         app_version = 'NA'
293         app_git_tag = 'NA'
294
295     return {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag}