bugfix: Graceful shutdown of VM - improvement
[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         found = False
227         with open(app_version_file['dpdk']) as file_:
228             for line in file_:
229                 if not line.strip():
230                     continue
231                 if line.startswith('#define RTE_VER_MAJOR'):
232                     found = True
233                     tmp_ver[0] = line.rstrip('\n').split(' ')[2]
234                 if line.startswith('#define RTE_VER_MINOR'):
235                     found = True
236                     tmp_ver[1] = line.rstrip('\n').split(' ')[2]
237                 if line.startswith('#define RTE_VER_PATCH_LEVEL'):
238                     found = True
239                     tmp_ver[2] = line.rstrip('\n').split(' ')[2]
240
241         if found:
242             app_version = '.'.join(tmp_ver)
243         app_git_tag = get_git_tag(S.getValue('RTE_SDK'))
244     elif app_name.lower().startswith('qemu'):
245         app_version = match_line(app_version_file['qemu'], '')
246         app_git_tag = get_git_tag(S.getValue('QEMU_DIR'))
247     elif app_name.lower() == 'ixnet':
248         app_version = match_line(app_version_file['ixnet'], 'package provide IxTclNetwork')
249         if app_version:
250             app_version = app_version.split(' ')[3]
251     elif app_name.lower() == 'xena':
252         try:
253             app_version = S.getValue('XENA_VERSION')
254         except AttributeError:
255             # setting was not available after execution
256             app_version = 'N/A'
257     elif app_name.lower() == 'dummy':
258         # get git tag of file with Dummy implementation
259         app_git_tag = get_git_tag(os.path.join(S.getValue('ROOT_DIR'), 'tools/pkt_gen/dummy/dummy.py'))
260     elif app_name.lower() == 'vswitchperf':
261         app_git_tag = get_git_tag(S.getValue('ROOT_DIR'))
262     elif app_name.lower() == 'l2fwd':
263         app_version = match_line(app_version_file[app_name], 'MODULE_VERSION')
264         if app_version:
265             app_version = app_version.split('"')[1]
266         app_git_tag = get_git_tag(app_version_file[app_name])
267     elif app_name.lower() in ['linux_bridge', 'buildin']:
268         # without login into running VM, it is not possible to check bridge_utils version
269         app_version = 'NA'
270         app_git_tag = 'NA'
271
272     return {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag}