diff options
Diffstat (limited to 'vstf/vstf/agent/equalizer')
-rwxr-xr-x | vstf/vstf/agent/equalizer/README | 1 | ||||
-rwxr-xr-x | vstf/vstf/agent/equalizer/__init__.py | 14 | ||||
-rwxr-xr-x | vstf/vstf/agent/equalizer/equalizer.py | 67 | ||||
-rwxr-xr-x | vstf/vstf/agent/equalizer/get_info.py | 162 | ||||
-rwxr-xr-x | vstf/vstf/agent/equalizer/optimize.py | 54 |
5 files changed, 298 insertions, 0 deletions
diff --git a/vstf/vstf/agent/equalizer/README b/vstf/vstf/agent/equalizer/README new file mode 100755 index 00000000..6c688a1f --- /dev/null +++ b/vstf/vstf/agent/equalizer/README @@ -0,0 +1 @@ +equalizer of the performance of network diff --git a/vstf/vstf/agent/equalizer/__init__.py b/vstf/vstf/agent/equalizer/__init__.py new file mode 100755 index 00000000..89dcd4e2 --- /dev/null +++ b/vstf/vstf/agent/equalizer/__init__.py @@ -0,0 +1,14 @@ +# Copyright Huawei Technologies Co., Ltd. 1998-2015. +# All Rights Reserved. +# +# 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. diff --git a/vstf/vstf/agent/equalizer/equalizer.py b/vstf/vstf/agent/equalizer/equalizer.py new file mode 100755 index 00000000..8db35df9 --- /dev/null +++ b/vstf/vstf/agent/equalizer/equalizer.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# coding=utf-8 +import os +import re +import subprocess +import logging + +log = logging.getLogger(__name__) + + +def run_cmd(cmd, shell=True): + try: + ret = subprocess.check_output(cmd, shell=shell) + except subprocess.CalledProcessError as e: + raise e + return ret + + +class Resource(object): + def __init__(self): + super(Resource, self).__init__() + self.sysfs = "/sys/devices/system/node" + self.mapping = {} + for node in self._init_numa(): + self.mapping[node] = {} + + process_mapping = self._get_process_mapping(node) + for process_index in xrange(0, len(bin(process_mapping)) - 2): + if process_mapping & 1 << process_index != 0: + core = self._get_core_id(node, process_index) + if not self.mapping[node].has_key(core): + self.mapping[node][core] = [] + self.mapping[node][core].append(process_index) + + def _get_process_mapping(self, numa_node): + ret = run_cmd("cat " + self.sysfs + '/' + numa_node + '/cpumap').replace(',', '').lstrip('0') + return int(ret, 16) + + def _get_core_id(self, numa_node, process_index): + cmd = "cat " + self.sysfs + '/' + numa_node + '/cpu' + str(process_index) + '/topology/core_id' + return run_cmd(cmd).strip('\n') + + def _init_numa(self): + """the node name is node0, node1......""" + try: + node_list = os.listdir(self.sysfs) + except Exception as e: + raise e + ret = [] + partten = re.compile("^node[0-9]{,}$") + for node in node_list: + if partten.match(node) is None: + continue + ret.append(node) + return ret + + +class Equalizer(Resource): + def __init__(self): + super(Equalizer, self).__init__() + + def topology(self): + print self.mapping + + +e = Equalizer() +e.topology() diff --git a/vstf/vstf/agent/equalizer/get_info.py b/vstf/vstf/agent/equalizer/get_info.py new file mode 100755 index 00000000..873f0caf --- /dev/null +++ b/vstf/vstf/agent/equalizer/get_info.py @@ -0,0 +1,162 @@ +#!/usr/bin/python +import commands + +try: + import xml.etree.cElementTree as ET +except ImportError: + import xml.etree.ElementTree as ET + + +class GetPhyInfo(object): + def __init__(self): + pass + + def _get_range(self, temp): + topo = {} + phy_core_flag = True + for sub in temp.split(','): + r_list = [] + _start = sub.split('-')[0] + _end = sub.split('-')[1] + r_list.extend(range(int(_start), int(_end) + 1)) + if phy_core_flag: + topo['phy_cores'] = r_list + else: + topo['virt_cores'] = r_list + phy_core_flag = False + return topo + + def _get_numa_num(self): + flag, num = commands.getstatusoutput('lscpu | grep "NUMA node(s):"') + try: + num = num.split(':')[1] + except: + print('get numa %s value failed.' % (num)) + return num + + def get_numa_core(self): + numa = {} + num = self._get_numa_num() + for numa_id in range(0, int(num)): + flag, temp = commands.getstatusoutput('lscpu | grep "NUMA node%s"' % (str(numa_id))) + try: + temp = temp.split(':')[1].split()[0] + except: + print('get numa %s range %s failed.' % (str(numa_id), range)) + topo = self._get_range(temp) + numa['node' + str(numa_id)] = topo + return str(numa) + + def get_nic_numa(self, nic): + result = {} + try: + flag, id = commands.getstatusoutput('cat /sys/class/net/%s/device/numa_node' % (nic)) + except: + print('get nic numa id failed.') + return id + + def _get_main_pid(self, xml_file): + try: + tree = ET.ElementTree(file=xml_file) + root = tree.getroot() + _main_pid = root.attrib['pid'] + except: + print('[ERROR]Parse xml file failed, could not get qemu main pid') + return _main_pid + + def _get_qemu_threads(self, xml_file): + # import pdb + # pdb.set_trace() + _qemu_threads = [] + try: + tree = ET.ElementTree(file=xml_file) + root = tree.getroot() + for element in tree.iterfind('vcpus/vcpu'): + _qemu_threads.append(element.attrib['pid']) + except: + print('[ERROR]Parse xml file failed, could not get qemu threads.') + + return _qemu_threads + + def _get_mem_numa(self, xml_file): + try: + _mem_numa = None + tree = ET.ElementTree(file=xml_file) + root = tree.getroot() + for element in tree.iterfind('domain/numatune/memory'): + _mem_numa = element.attrib['nodeset'] + finally: + return _mem_numa + + def _get_vhost_threads(self, xml_file): + _vhost = [] + _main_pid = self._get_main_pid(xml_file) + + # get vhost info + proc_name = 'vhost-' + _main_pid + flag, temp = commands.getstatusoutput('ps -ef | grep %s | grep -v grep' % (proc_name)) + for line in temp.split('\n'): + try: + vhost = line.split()[1] + _vhost.append(vhost) + except: + print('get vhost %s proc id failed' % (line)) + + return _vhost + + def get_vm_info(self, vm_name): + vm = {} + src_path = '/var/run/libvirt/qemu/' + xml_file = src_path + vm_name + '.xml' + + # get vm main pid from file + _main_pid = self._get_main_pid(xml_file) + # get vm vcpu thread from the libvirt file + _qemu_threads = self._get_qemu_threads(xml_file) + # get vm bind mem numa id + _mem_numa = self._get_mem_numa(xml_file) + # get vhost thread + _vhosts = self._get_vhost_threads(xml_file) + + vm['main_pid'] = _main_pid + vm['qemu_thread'] = _qemu_threads + vm['mem_numa'] = _mem_numa + vm['vhost_thread'] = _vhosts + return vm + + def _get_proc_by_irq(self, irq): + try: + flag, info = commands.getstatusoutput('ps -ef | grep irq/%s | grep -v grep ' % (irq)) + proc_id = info.split('\n')[0].split()[1] + except: + print("[ERROR]grep process id failed.") + return proc_id + + def get_nic_interrupt_proc(self, nic): + _phy_nic_thread = [] + flag, info = commands.getstatusoutput('cat /proc/interrupts | grep %s' % (nic)) + for line in info.split('\n'): + try: + irq_num = line.split(':')[0].split()[0] + proc_id = self._get_proc_by_irq(irq_num) + _phy_nic_thread.append([irq_num, proc_id]) + except: + print("[ERROR]get irq num failed.") + return _phy_nic_thread + + def get_libvirt_vms(self): + vm_list = [] + flag, info = commands.getstatusoutput('virsh list') + list = info.split('\n') + if list[-1] == '': + list.pop() + del list[0] + del list[0] + + for line in list: + try: + vm_temp = line.split()[1] + vm_list.append(vm_temp) + except: + print("Get vm name failed from %s" % (line)) + return vm_list diff --git a/vstf/vstf/agent/equalizer/optimize.py b/vstf/vstf/agent/equalizer/optimize.py new file mode 100755 index 00000000..941769a3 --- /dev/null +++ b/vstf/vstf/agent/equalizer/optimize.py @@ -0,0 +1,54 @@ +#!/usr/bin/python +import commands +import re + + +# import pdb +# pdb.set_trace() + +class Optimize(object): + def __init__(self): + pass + + def bind_cpu(self, cpu_range, thread): + flag, num = commands.getstatusoutput('taskset -pc %s %s' % (cpu_range, thread)) + return flag + + def catch_thread_info(self): + thread_info = {'fwd_vhost': None, 'src_recv_irq': None, 'dst_send_irq': None} + # top -H get the usage info + flag, threads_usages = commands.getstatusoutput('top -bH -n1 -c -w 2000') + line_array = threads_usages.split('\n') + # get highest vhost line + for line in line_array: + if re.search('vhost-', line) and self._check_thread_usage(line): + thread_info['fwd_vhost'] = line.split()[0] + break + # get highest irq thread as src_recv_irq thread + for line in line_array: + if re.search('irq/', line) and self._check_thread_usage(line): + thread_info['src_recv_irq'] = line.split()[0] + line_array.remove(line) + break + # get the second highest irq thread as dst_send_irq + for line in line_array: + if re.search('irq/', line) and self._check_thread_usage(line): + thread_info['dst_send_irq'] = line.split()[0] + break + # check the data valid + + for key in thread_info.keys(): + if thread_info[key] is None: + return False, str(thread_info) + return True, str(thread_info) + + def _check_thread_usage(self, line): + try: + usage = line.split()[8] + if float(usage) >= 3.0: + return True + else: + print("[ERROR]The highest thread %s is less than 0.05" % usage) + return False + except: + print("[ERROR]The thread usage get failed.") |