summaryrefslogtreecommitdiffstats
path: root/vstf/vstf/agent/equalizer
diff options
context:
space:
mode:
Diffstat (limited to 'vstf/vstf/agent/equalizer')
-rwxr-xr-xvstf/vstf/agent/equalizer/README1
-rwxr-xr-xvstf/vstf/agent/equalizer/__init__.py14
-rwxr-xr-xvstf/vstf/agent/equalizer/equalizer.py67
-rwxr-xr-xvstf/vstf/agent/equalizer/get_info.py162
-rwxr-xr-xvstf/vstf/agent/equalizer/optimize.py54
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.")