aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiroslav Miklus <mmiklus@cisco.com>2016-08-05 16:16:45 +0200
committerJan Gelety <jgelety@cisco.com>2016-08-08 16:59:05 +0000
commite710b52146d8c5c9db250d29c01f4f8ebdaf3261 (patch)
tree87b67b944cb37d7b898be8921788c0dfcd564ed4
parent43717c90f05596f628cb7ef17cf35a8cf7289f86 (diff)
CSIT-338 PCI numa_node discovery
Allow to discover PCI - numa node relationship. Change-Id: I04a445e42b3cbbf450b990ebbc2c83ac313815f1 Signed-off-by: Miroslav Miklus <mmiklus@cisco.com>
-rw-r--r--resources/libraries/python/InterfaceUtil.py29
-rw-r--r--resources/libraries/python/topology.py81
-rw-r--r--tests/perf/__init__.robot2
3 files changed, 110 insertions, 2 deletions
diff --git a/resources/libraries/python/InterfaceUtil.py b/resources/libraries/python/InterfaceUtil.py
index 9537b2ba1d..9ecdb7503a 100644
--- a/resources/libraries/python/InterfaceUtil.py
+++ b/resources/libraries/python/InterfaceUtil.py
@@ -427,7 +427,26 @@ class InterfaceUtil(object):
InterfaceUtil.tg_set_interfaces_udev_rules(node)
@staticmethod
- def update_all_interface_data_on_all_nodes(nodes, skip_tg=False):
+ def iface_update_numa_node(node):
+ """For all interfaces from topology file update numa node based on
+ information from the node.
+
+ :param node: Node from topology.
+ :type node: dict
+ :return: nothing
+ """
+ ssh = SSH()
+ for if_key in Topology.get_node_interfaces(node):
+ if_pci = Topology.get_interface_pci_addr(node, if_key)
+ ssh.connect(node)
+ cmd = "cat /sys/bus/pci/devices/{}/numa_node".format(if_pci)
+ (ret, out, _) = ssh.exec_command(cmd)
+ if ret == 0:
+ Topology.set_interface_numa_node(node, if_key, int(out))
+
+ @staticmethod
+ def update_all_interface_data_on_all_nodes(nodes, skip_tg=False,
+ numa_node=False):
"""Update interface names on all nodes in DICT__nodes.
This method updates the topology dictionary by querying interface lists
@@ -435,8 +454,10 @@ class InterfaceUtil(object):
:param nodes: Nodes in the topology.
:param skip_tg: Skip TG node
+ :param numa_node: Retrieve numa_node location.
:type nodes: dict
:type skip_tg: bool
+ :type numa_node: bool
"""
for node_data in nodes.values():
if node_data['type'] == NodeType.DUT:
@@ -444,6 +465,12 @@ class InterfaceUtil(object):
elif node_data['type'] == NodeType.TG and not skip_tg:
InterfaceUtil.update_tg_interface_data_on_node(node_data)
+ if numa_node:
+ if node_data['type'] == NodeType.DUT:
+ InterfaceUtil.iface_update_numa_node(node_data)
+ elif node_data['type'] == NodeType.TG and not skip_tg:
+ InterfaceUtil.iface_update_numa_node(node_data)
+
@staticmethod
def create_vlan_subinterface(node, interface, vlan):
"""Create VLAN subinterface on node.
diff --git a/resources/libraries/python/topology.py b/resources/libraries/python/topology.py
index 80cbb1f4e1..a5c67d313c 100644
--- a/resources/libraries/python/topology.py
+++ b/resources/libraries/python/topology.py
@@ -13,6 +13,8 @@
"""Defines nodes and topology structure."""
+from collections import Counter
+
from yaml import load
from robot.api import logger
@@ -32,7 +34,7 @@ def load_topo_from_yaml():
with open(topo_path) as work_file:
return load(work_file.read())['nodes']
-
+# pylint: disable=invalid-name
class NodeType(object):
"""Defines node types used in topology dictionaries."""
# Device Under Test (this node has VPP running on it)
@@ -332,6 +334,56 @@ class Topology(object):
return None
@staticmethod
+ def get_interface_numa_node(node, iface_key):
+ """Get interface numa node.
+
+ Returns physical relation to numa node, numa_id.
+
+ :param node: Node to get numa id on.
+ :param iface_key: Interface key from topology file.
+ :type node: dict
+ :type iface_key: str
+ :return: numa node id, None if not available.
+ :rtype: int
+ """
+ try:
+ return node['interfaces'][iface_key].get('numa_node')
+ except KeyError:
+ return None
+
+ @staticmethod
+ def get_interfaces_numa_node(node, *iface_keys):
+ """Get numa node on which are located most of the interfaces.
+
+ Return numa node with highest count of interfaces provided as arguments.
+ Return 0 if the interface does not have numa_node information available.
+ If all interfaces have unknown location (-1), then return 0.
+ If most of interfaces have unknown location (-1), but there are
+ some interfaces with known location, then return the second most
+ location of the provided interfaces.
+
+ :param node: Node from DICT__nodes.
+ :param iface_keys: Interface keys for lookup.
+ :type node: dict
+ :type iface_keys: strings
+ """
+ numa_list = []
+ for if_key in iface_keys:
+ try:
+ numa_list.append(node['interfaces'][if_key].get('numa_node'))
+ except KeyError:
+ pass
+
+ numa_cnt_mc = Counter(numa_list).most_common()
+
+ if len(numa_cnt_mc) > 0 and numa_cnt_mc[0][0] != -1:
+ return numa_cnt_mc[0][0]
+ elif len(numa_cnt_mc) > 1 and numa_cnt_mc[0][0] == -1:
+ return numa_cnt_mc[1][0]
+ else:
+ return 0
+
+ @staticmethod
def get_interface_mac(node, iface_key):
"""Get MAC address for the interface.
@@ -416,6 +468,17 @@ class Topology(object):
return None
@staticmethod
+ def get_node_interfaces(node):
+ """Get all node interfaces.
+
+ :param node: Node to get list of interfaces from.
+ :type node: dict
+ :return: Return list of keys of all interfaces.
+ :rtype: list
+ """
+ return node['interfaces'].keys()
+
+ @staticmethod
def get_node_link_mac(node, link_name):
"""Return interface mac address by link name.
@@ -623,3 +686,19 @@ class Topology(object):
:rtype: str
"""
return node['host']
+
+ @staticmethod
+ def set_interface_numa_node(node, iface_key, numa_node_id):
+ """Set interface numa_node location.
+
+ :param node: Node to set numa_node on.
+ :param iface_key: Interface key from topology file.
+ :type node: dict
+ :type iface_key: str
+ :return: Return iface_key or None if not found.
+ """
+ try:
+ node['interfaces'][iface_key]['numa_node'] = numa_node_id
+ return iface_key
+ except KeyError:
+ return None
diff --git a/tests/perf/__init__.robot b/tests/perf/__init__.robot
index afdcc700e9..7efa763f57 100644
--- a/tests/perf/__init__.robot
+++ b/tests/perf/__init__.robot
@@ -19,3 +19,5 @@
| Suite Setup | Run Keywords | Setup Framework | ${nodes}
| ... | AND | Setup All DUTs | ${nodes}
| ... | AND | Get CPU Layout from all nodes | ${nodes}
+| ... | AND | Update All Interface Data On All Nodes
+| ... | ${nodes} | skip_tg=${True} | numa_node=${True}