report: add rst template for results reporting
[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_pciid in S.getValue('WHITELIST_NICS'):
75             if line.startswith(nic_pciid):
76                 nics.append(''.join(line.split(':')[2:]).strip())
77     return nics
78
79 def get_platform():
80     """Get platform information.
81
82     Currently this is the motherboard vendor, name and socket
83     count.
84
85     :returns: Return platform information as a string
86     """
87     output = []
88
89     with open('/sys/class/dmi/id/board_vendor', 'r') as file_:
90         output.append(file_.readline().rstrip())
91
92     with open('/sys/class/dmi/id/board_name', 'r') as file_:
93         output.append(file_.readline().rstrip())
94
95     num_nodes = len([name for name in os.listdir(
96         '/sys/devices/system/node/') if name.startswith('node')])
97     output.append(''.join(['[', str(num_nodes), ' sockets]']))
98
99     return ' '.join(output).strip()
100
101 def get_cpu_cores():
102     """Get number of CPU cores.
103
104     :returns: Return number of CPU cores
105     """
106     cores = 0
107     with open('/proc/cpuinfo') as file_:
108         for line in file_:
109             if line.rstrip('\n').startswith('processor'):
110                 cores += 1
111             continue
112
113     # this code must be executed by at leat one core...
114     if cores < 1:
115         cores = 1
116     return cores
117
118 def get_memory():
119     """Get memory information.
120
121     :returns: amount of system memory as string together with unit
122     """
123     memory = match_line('/proc/meminfo', 'MemTotal')
124     return memory.split(':')[1].strip() if memory else memory
125
126 def get_memory_bytes():
127     """Get memory information in bytes
128
129     :returns: amount of system memory
130     """
131     mem_list = get_memory().split(' ')
132     mem = float(mem_list[0].strip())
133     if mem_list.__len__() > 1:
134         unit = mem_list[1].strip().lower()
135         if unit == 'kb':
136             mem *= 1024
137         elif unit == 'mb':
138             mem *= 1024 ** 2
139         elif unit == 'gb':
140             mem *= 1024 ** 3
141         elif unit == 'tb':
142             mem *= 1024 ** 4
143
144     return int(mem)
145
146 def get_pids(proc_names_list):
147     """ Get pid(s) of process(es) with given name(s)
148
149     :returns: list with pid(s) of given processes or None if processes
150         with given names are not running
151     """
152
153     try:
154         pids = subprocess.check_output(['sudo', 'LC_ALL=' + S.getValue('DEFAULT_CMD_LOCALE'), 'pidof']
155                                        + proc_names_list)
156     except subprocess.CalledProcessError:
157         # such process isn't running
158         return None
159
160     return list(map(str, map(int, pids.split())))
161
162 def get_pid(proc_name_str):
163     """ Get pid(s) of process with given name
164
165     :returns: list with pid(s) of given process or None if process
166         with given name is not running
167     """
168     return get_pids([proc_name_str])
169
170 # This function uses long switch per purpose, so let us suppress pylint warning too-many-branches
171 # pylint: disable=R0912
172 def get_version(app_name):
173     """ Get version of given application and its git tag
174
175     :returns: dictionary {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag) in case that
176         version or git tag are not known or not applicaple, than None is returned for any unknown value
177
178     """
179     app_version_file = {
180         'ovs' : os.path.join(S.getValue('OVS_DIR'), 'include/openvswitch/version.h'),
181         'dpdk' : os.path.join(S.getValue('RTE_SDK'), 'lib/librte_eal/common/include/rte_version.h'),
182         'qemu' : os.path.join(S.getValue('QEMU_DIR'), 'VERSION'),
183         'l2fwd' : os.path.join(S.getValue('ROOT_DIR'), 'src/l2fwd/l2fwd.c'),
184         'ixnet' : os.path.join(S.getValue('TRAFFICGEN_IXNET_LIB_PATH'), 'pkgIndex.tcl')
185     }
186
187
188     def get_git_tag(path):
189         """ get tag of recent commit from repository located at 'path'
190
191         :returns: git tag in form of string with commit hash or None if there
192             isn't any git repository at given path
193         """
194         try:
195             if os.path.isdir(path):
196                 return subprocess.check_output('cd {}; git rev-parse HEAD'.format(path), shell=True,
197                                                stderr=subprocess.DEVNULL).decode().rstrip('\n')
198             elif os.path.isfile(path):
199                 return subprocess.check_output('cd $(dirname {}); git log -1 --pretty="%H" {}'.format(path, path),
200                                                shell=True, stderr=subprocess.DEVNULL).decode().rstrip('\n')
201             else:
202                 return None
203         except subprocess.CalledProcessError:
204             return None
205
206
207     app_version = None
208     app_git_tag = None
209
210     if app_name.lower().startswith('ovs'):
211         app_version = match_line(app_version_file['ovs'], '#define OVS_PACKAGE_VERSION')
212         if app_version:
213             app_version = app_version.split('"')[1]
214         app_git_tag = get_git_tag(S.getValue('OVS_DIR'))
215     elif app_name.lower() in ['dpdk', 'testpmd']:
216         tmp_ver = ['', '', '']
217         found = False
218         with open(app_version_file['dpdk']) as file_:
219             for line in file_:
220                 if not line.strip():
221                     continue
222                 if line.startswith('#define RTE_VER_MAJOR'):
223                     found = True
224                     tmp_ver[0] = line.rstrip('\n').split(' ')[2]
225                 if line.startswith('#define RTE_VER_MINOR'):
226                     found = True
227                     tmp_ver[1] = line.rstrip('\n').split(' ')[2]
228                 if line.startswith('#define RTE_VER_PATCH_LEVEL'):
229                     found = True
230                     tmp_ver[2] = line.rstrip('\n').split(' ')[2]
231
232         if found:
233             app_version = '.'.join(tmp_ver)
234         app_git_tag = get_git_tag(S.getValue('RTE_SDK'))
235     elif app_name.lower().startswith('qemu'):
236         app_version = match_line(app_version_file['qemu'], '')
237         app_git_tag = get_git_tag(S.getValue('QEMU_DIR'))
238     elif app_name.lower() == 'ixnet':
239         app_version = match_line(app_version_file['ixnet'], 'package provide IxTclNetwork')
240         if app_version:
241             app_version = app_version.split(' ')[3]
242     elif app_name.lower() == 'dummy':
243         # get git tag of file with Dummy implementation
244         app_git_tag = get_git_tag(os.path.join(S.getValue('ROOT_DIR'), 'tools/pkt_gen/dummy/dummy.py'))
245     elif app_name.lower() == 'vswitchperf':
246         app_git_tag = get_git_tag(S.getValue('ROOT_DIR'))
247     elif app_name.lower() == 'l2fwd':
248         app_version = match_line(app_version_file[app_name], 'MODULE_VERSION')
249         if app_version:
250             app_version = app_version.split('"')[1]
251         app_git_tag = get_git_tag(app_version_file[app_name])
252     elif app_name.lower() in ['linux_bridge', 'buildin']:
253         # without login into running VM, it is not possible to check bridge_utils version
254         app_version = 'NA'
255         app_git_tag = 'NA'
256
257     return {'name' : app_name, 'version' : app_version, 'git_tag' : app_git_tag}