FIX: CPU util for NF
[csit.git] / resources / libraries / python / CpuUtils.py
index f4d52f8..57bf7fd 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2018 Cisco and/or its affiliates.
+# Copyright (c) 2019 Cisco and/or its affiliates.
 # 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:
@@ -49,7 +49,6 @@ class CpuUtils(object):
         :returns: True if SMT is enabled, False if SMT is disabled.
         :rtype: bool
         """
-
         cpu_mems = [item[-4:] for item in cpu_info]
         cpu_mems_len = len(cpu_mems) / CpuUtils.NR_OF_THREADS
         count = 0
@@ -117,7 +116,6 @@ class CpuUtils(object):
         :raises RuntimeError: If node cpuinfo is not available
             or if SMT is not enabled.
         """
-
         cpu_node = int(cpu_node)
         cpu_info = node.get("cpuinfo")
         if cpu_info is None:
@@ -160,7 +158,6 @@ class CpuUtils(object):
         :rtype: list
         :raises RuntimeError: If we require more cpus than available.
         """
-
         cpu_list = CpuUtils.cpu_list_per_node(node, cpu_node, smt_used)
 
         cpu_list_len = len(cpu_list)
@@ -202,7 +199,6 @@ class CpuUtils(object):
         :returns: Cpu numbers related to numa from argument.
         :rtype: str
         """
-
         cpu_list = CpuUtils.cpu_slice_of_list_per_node(node, cpu_node,
                                                        skip_cnt=skip_cnt,
                                                        cpu_cnt=cpu_cnt,
@@ -229,7 +225,6 @@ class CpuUtils(object):
         :returns: String of node related range of CPU numbers.
         :rtype: str
         """
-
         cpu_list = CpuUtils.cpu_slice_of_list_per_node(node, cpu_node,
                                                        skip_cnt=skip_cnt,
                                                        cpu_cnt=cpu_cnt,
@@ -246,3 +241,60 @@ class CpuUtils(object):
             cpu_range = "{}{}{}".format(cpu_list[0], sep, cpu_list[-1])
 
         return cpu_range
+
+    @staticmethod
+    def cpu_slice_of_list_for_nf(**kwargs):
+        """Return list of node related list of CPU numbers.
+
+        :param kwargs: Key-value pairs used to compute placement.
+        :type kwargs: dict
+        :returns: Cpu numbers related to numa from argument.
+        :rtype: list
+        :raises RuntimeError: If we require more cpus than available or if
+        placement is not possible due to wrong parameters.
+        """
+        if kwargs['chain_id'] - 1 >= kwargs['chains']:
+            raise RuntimeError("ChainID is higher than total number of chains!")
+        if kwargs['node_id'] - 1 >= kwargs['nodeness']:
+            raise RuntimeError("NodeID is higher than chain nodeness!")
+
+        smt_used = CpuUtils.is_smt_enabled(kwargs['node']['cpuinfo'])
+        cpu_list = CpuUtils.cpu_list_per_node(kwargs['node'],
+                                              kwargs['cpu_node'], smt_used)
+        cpu_list_len = len(cpu_list)
+
+        mt_req = ((kwargs['chains'] * kwargs['nodeness']) + kwargs['mtcr'] - 1)\
+            / kwargs['mtcr']
+        dt_req = ((kwargs['chains'] * kwargs['nodeness']) + kwargs['dtcr'] - 1)\
+            / kwargs['dtcr']
+
+        cpu_req = kwargs['skip_cnt'] + mt_req + dt_req
+        if smt_used and cpu_req > cpu_list_len / CpuUtils.NR_OF_THREADS:
+            raise RuntimeError("Not enough CPU cores available for placement!")
+        elif not smt_used and cpu_req > cpu_list_len:
+            raise RuntimeError("Not enough CPU cores available for placement!")
+
+        offset = (kwargs['node_id'] - 1) + (kwargs['chain_id'] - 1)\
+            * kwargs['nodeness']
+        dtc = kwargs['dtc']
+        try:
+            mt_odd = (offset / mt_req) & 1
+            mt_skip = kwargs['skip_cnt'] + (offset % mt_req)
+            dt_skip = kwargs['skip_cnt'] + mt_req + (offset % dt_req) * dtc
+        except ZeroDivisionError:
+            raise RuntimeError("Invalid placement combination!")
+
+        if smt_used:
+            cpu_list_0 = cpu_list[:cpu_list_len / CpuUtils.NR_OF_THREADS]
+            cpu_list_1 = cpu_list[cpu_list_len / CpuUtils.NR_OF_THREADS:]
+
+            mt_cpu_list = [cpu for cpu in cpu_list_1[mt_skip:mt_skip + 1]] \
+                if mt_odd else [cpu for cpu in cpu_list_0[mt_skip:mt_skip + 1]]
+
+            dt_cpu_list = [cpu for cpu in cpu_list_0[dt_skip:dt_skip + dtc]]
+            dt_cpu_list += [cpu for cpu in cpu_list_1[dt_skip:dt_skip + dtc]]
+        else:
+            mt_cpu_list = [cpu for cpu in cpu_list[mt_skip:mt_skip + 1]]
+            dt_cpu_list = [cpu for cpu in cpu_list[dt_skip:dt_skip + dtc]]
+
+        return mt_cpu_list + dt_cpu_list