[PATCH v3 1/2] misc: refine CLOS module for expansibility


chenli.wei
 

This patch refine CLOS module by the following aspects:

1 Unified CACHE_ID type to Hex Format
2 Rewrite policy merge with RDT Class
3 Modify the logic of generate CPU mask

v2-->v3:
1. Add some new class to abstract CLOS Policy
2. Add new interface for RdtPolicy
3. Code format and variable rename

v1-->v2:
1. code format
2. add comment for RdtPolicy

Signed-off-by: Chenli Wei <chenli.wei@...>
---
misc/config_tools/board_config/board_c.py | 8 +-
misc/config_tools/schema/types.xsd | 2 +-
misc/config_tools/static_allocators/clos.py | 275 ++++++++++++--------
3 files changed, 174 insertions(+), 111 deletions(-)

diff --git a/misc/config_tools/board_config/board_c.py b/misc/config_tools/board_config/board_c.py
index 8082c4387..4be3ea4ec 100644
--- a/misc/config_tools/board_config/board_c.py
+++ b/misc/config_tools/board_config/board_c.py
@@ -173,7 +173,7 @@ def gen_rdt_str(cache, config):
return err_dic

cdp_enable = get_cdp_enabled()
- cat_mask_list = get_mask_list(cache_level, int(cache_id, 16))
+ cat_mask_list = get_mask_list(cache_level, cache_id)
if len(cat_mask_list) > int(clos_number):
err_dic['board config: Failed to generate board.c'] = "CLOS Mask Number too bigger then the supported of L2/L3 cache"
return err_dic;
@@ -207,7 +207,7 @@ def gen_rdt_str(cache, config):

cpu_mask = 0
for processor in processor_list:
- core_id = common.get_node(f"//core[@id = '{processor}']/thread/cpu_id/text()", board_etree)
+ core_id = common.get_node(f"//thread[apic_id = '{processor}']/cpu_id/text()", board_etree)
if core_id is None:
continue
else:
@@ -240,7 +240,7 @@ def gen_clos_array(cache_list, config):
clos_number = common.get_node(f"./capability/clos_number/text()", cache)
if cache_level == "2":

- cat_mask_list = get_mask_list(cache_level, int(cache_id, 16))
+ cat_mask_list = get_mask_list(cache_level, cache_id)
array_size = len(cat_mask_list)

print("union clos_config platform_l2_clos_array_{0}[{1}] = {{".format(int(cache_id, 16), clos_number), file=config)
@@ -250,7 +250,7 @@ def gen_clos_array(cache_list, config):
print("};\n", file=config)
res_present[RDT.L2.value] += 1
elif cache_level == "3":
- cat_mask_list = get_mask_list(cache_level, int(cache_id, 16))
+ cat_mask_list = get_mask_list(cache_level, cache_id)

print("union clos_config platform_l3_clos_array_{0}[{1}] = {{".format(int(cache_id, 16), clos_number), file=config)

diff --git a/misc/config_tools/schema/types.xsd b/misc/config_tools/schema/types.xsd
index 36a4aae09..cec4b84a5 100644
--- a/misc/config_tools/schema/types.xsd
+++ b/misc/config_tools/schema/types.xsd
@@ -355,7 +355,7 @@ RDT, setting this option to ``y`` is ignored.</xs:documentation>

<xs:complexType name="CacheAllocationType">
<xs:sequence>
- <xs:element name="CACHE_ID" type="xs:integer"/>
+ <xs:element name="CACHE_ID" type="HexFormat"/>
<xs:element name="CACHE_LEVEL" type="xs:integer"/>
<xs:element name="POLICY" type="CachePolicyType" minOccurs="1" maxOccurs="unbounded"/>
</xs:sequence>
diff --git a/misc/config_tools/static_allocators/clos.py b/misc/config_tools/static_allocators/clos.py
index 1f0476422..f018dcd4a 100644
--- a/misc/config_tools/static_allocators/clos.py
+++ b/misc/config_tools/static_allocators/clos.py
@@ -11,140 +11,203 @@ import common
import re
from collections import defaultdict
from itertools import combinations
+from collections import namedtuple

-def create_clos_node(etree, vm_id, index_list):
- allocation_vm_node = common.get_node(f"/acrn-config/vm[@id = '{vm_id}']", etree)
+
+policy_owner = namedtuple("policy_owner", ["vm_name", "vcpu", "cache_type"])
+
+class Policy:
+ def __init__(self, cache_id, clos_mask):
+ self.cache_id = cache_id
+ self.clos_mask = clos_mask
+
+ def get_cache_id(self):
+ return self.cache_id
+
+ def get_clos_mask(self):
+ return self.clos_mask
+
+ def match_policy(self, src):
+ return (self.clos_mask == None) or (src.clos_mask == None) or (self.clos_mask == src.clos_mask)
+
+class L3Policy(Policy):
+ def __init__(self, policy):
+ self.cache_id = policy.get_cache_id()
+ self.clos_mask = policy.get_clos_mask()
+
+ def merge_policy(self, src):
+ return self.match_policy(src)
+
+class L2Policy:
+ policy_list = []
+ cache2_id_list = []
+
+ def __init__(self, policy):
+ for index,cache2_id in enumerate(self.cache2_id_list):
+ if cache2_id == policy.cache_id:
+ self.policy_list.append(policy)
+ else:
+ self.policy_list.append(Policy(None, None))
+
+ def get_cache_id(self, index):
+ return self.policy_list[index].get_cache_id()
+
+ def get_clos_mask(self, index):
+ return self.policy_list[index].get_clos_mask()
+
+ def merge_policy(self, src):
+ could_merge = True
+ for index in range(0, len(self.policy_list)):
+ if not self.policy_list[index].match_policy(src.policy_list[index]):
+ could_merge = False
+ break
+ if could_merge:
+ for index in range(0, len(self.policy_list)):
+ if self.policy_list[index].clos_mask is None:
+ self.policy_list[index].clos_mask = src.policy_list[index].clos_mask
+ return could_merge
+
+class RdtPolicy:
+ l2policy = None
+ l3policy = None
+ policy_owner_list = []
+
+ def __init__(self, policy_list, policy_owner):
+ cache2_id = None
+ cache3_id = None
+ l2_mask = None
+ l3_mask = None
+ for policy in policy_list:
+ cache_level = common.get_node("../CACHE_LEVEL/text()", policy)
+ cache_id = common.get_node("../CACHE_ID/text()", policy)
+ clos_mask = common.get_node("./CLOS_MASK/text()", policy)
+ if cache_level == "2":
+ l2_mask = clos_mask
+ cache2_id = cache_id
+ else:
+ l3_mask = clos_mask
+ cache3_id = cache_id
+ self.l2policy = L2Policy(Policy(cache2_id, l2_mask))
+ self.l3policy = L3Policy(Policy(cache3_id, l3_mask))
+
+ # a list stored the vCPU or VM info
+ self.policy_owner_list = [policy_owner]
+
+ #check whether the src could be merged, if yes, add the src owner to policy_owner_list list and return True
+ def merge_policy(self, src):
+ if self.l2policy.merge_policy(src.l2policy) and self.l3policy.merge_policy(src.l3policy):
+ self.policy_owner_list += src.policy_owner_list
+ return True
+ return False
+
+ #check whether a VM/vCPU could use this policy
+ def find_policy_owner(self, policy_owner):
+ return policy_owner in self.policy_owner_list
+
+class vCatPolicy(RdtPolicy):
+ def merge_policy(self, src):
+ return False
+
+def create_clos_node(scenario_etree, vm_id, index_list):
+ allocation_vm_node = common.get_node(f"/acrn-config/vm[@id = '{vm_id}']", scenario_etree)
if allocation_vm_node is None:
- allocation_vm_node = common.append_node("/acrn-config/vm", None, etree, id = vm_id)
+ allocation_vm_node = common.append_node("/acrn-config/vm", None, scenario_etree, id = vm_id)
if common.get_node("./clos", allocation_vm_node) is None:
clos_node = common.append_node("./clos", None, allocation_vm_node)
for index in index_list:
common.append_node(f"./vcpu_clos", str(index), clos_node)

-def find_cache2_id(mask, cache2_id_list):
- for cache2 in cache2_id_list:
- if mask[cache2] != "None":
- return cache2
- return "None"
-
-def merge_policy_list(mask_list, cache2_id_list):
- index = 0
+def merge_policy_list(policy_list):
result_list = []
- for index,mask in enumerate(mask_list):
- merged = 0
- if index == 0:
- result_list.append(mask)
- continue
+ for index,p in enumerate(policy_list):
+ merged = False
for result in result_list:
- if result["l3"] != mask["l3"]:
- continue
- else:
- cache2_id = find_cache2_id(mask, cache2_id_list)
- if cache2_id == "None" or result[cache2_id] == mask[cache2_id]:
- merged = 1
- break
- if result[cache2_id] == "None":
- merged = 1
- result[cache2_id] = mask[cache2_id]
- break
- if merged == 0:
- result_list.append(mask)
+ if result.merge_policy(p):
+ merged = True
+ break;
+ if not merged:
+ result_list.append(p)
return result_list

-def gen_all_clos_index(board_etree, scenario_etree, allocation_etree):
- policy_list = []
- allocation_list = scenario_etree.xpath(f"//POLICY")
- cache2_id_list = scenario_etree.xpath("//CACHE_ALLOCATION[CACHE_LEVEL = 2]/CACHE_ID/text()")
- cache2_id_list.sort()
+def gen_policy_owner_list(scenario_etree):
+ policy_owner_list = []
+ vm_list = scenario_etree.xpath("//POLICY/VM")
+ for vm in vm_list:
+ vm_name = common.get_node("./text()", vm)
+ vcpu = common.get_node("../VCPU/text()", vm)
+ cache_type = common.get_node("../TYPE/text()", vm)
+ policy_owner_list.append(policy_owner(vm_name, vcpu, cache_type))
+ return policy_owner_list
+
+def vm_vcat_enable(scenario_etree, vm_name):
+ vcat_enable = common.get_node(f"//VCAT_ENABLED/text()", scenario_etree)
+ virtual_cat_support = common.get_node(f"//vm[name = '{vm_name}']/virtual_cat_support/text()", scenario_etree)
+ return (vcat_enable == "y") and (virtual_cat_support == "y")

- for policy in allocation_list:
- cache_level = common.get_node("../CACHE_LEVEL/text()", policy)
- cache_id = common.get_node("../CACHE_ID/text()", policy)
- vcpu = common.get_node("./VCPU/text()", policy)
- mask = common.get_node("./CLOS_MASK/text()", policy)
- tmp = (cache_level, cache_id, vcpu, mask)
- policy_list.append(tmp)
-
- vCPU_list = scenario_etree.xpath(f"//POLICY/VCPU/text()")
- l3_mask_list = scenario_etree.xpath(f"//CACHE_ALLOCATION[CACHE_LEVEL = 3]/POLICY/CLOS_MASK")
- mask_list = []
- for vCPU in vCPU_list:
+def get_policy_list(board_etree, scenario_etree, allocation_etree):
+ policy_owner_list = gen_policy_owner_list(scenario_etree)
+
+ result_list = []
+ for policy_owner in policy_owner_list:
dict_tmp = {}
- l3_mask = l2_mask = "None"
- l3_mask_list = scenario_etree.xpath(f"//CACHE_ALLOCATION[CACHE_LEVEL = 3]/POLICY[VCPU = '{vCPU}']/CLOS_MASK/text()")
- if len(l3_mask_list) > 0:
- l3_mask = l3_mask_list[0]
- dict_tmp["l3"] = l3_mask
-
- l2_mask_list = scenario_etree.xpath(f"//CACHE_ALLOCATION[CACHE_LEVEL = 2]/POLICY[VCPU = '{vCPU}']/CLOS_MASK")
- if len(l2_mask_list) > 0:
- l2_mask = l2_mask_list[0].text
- cache_id = scenario_etree.xpath(f"//CACHE_ALLOCATION[CACHE_LEVEL = 2 and POLICY/VCPU = '{vCPU}']/CACHE_ID/text()")[0]
- for cache2 in cache2_id_list:
- if cache2 == cache_id:
- dict_tmp[cache_id] = l2_mask
- else:
- dict_tmp[cache2] = "None"
- mask_list.append(dict_tmp)
- mask_list = merge_policy_list(mask_list, cache2_id_list)
- return mask_list
-
-def get_clos_index(cache_level, cache_id, clos_mask):
- mask_list = common.get_mask_list(cache_level, cache_id)
- idx = 0
- for mask in mask_list:
- idx += 1
- if mask == clos_mask:
- break
- return idx
-def get_clos_id(mask_list, l2_id, l2_mask, l3_mask):
- for mask in mask_list:
- if mask[l2_id] == l2_mask and mask["l3"] == l3_mask:
- return mask_list.index(mask)
+ policy_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}' and TYPE = '{policy_owner.cache_type}']")
+ if vm_vcat_enable(scenario_etree, policy_owner.vm_name):
+ result_list.append(vCatPolicy(policy_list, policy_owner))
+ else:
+ result_list.append(RdtPolicy(policy_list, policy_owner))
+ return merge_policy_list(result_list)
+
+def get_clos_id(rdt_list, policy_owner):
+ for index,rdt in enumerate(rdt_list):
+ if rdt.find_policy_owner(policy_owner):
+ return index
return 0

def alloc_clos_index(board_etree, scenario_etree, allocation_etree, mask_list):
vm_node_list = scenario_etree.xpath("//vm")
for vm_node in vm_node_list:
- vmname = common.get_node("./name/text()", vm_node)
- allocation_list = scenario_etree.xpath(f"//CACHE_ALLOCATION[POLICY/VM = '{vmname}']")
- for allocation in allocation_list:
- index_list = []
- cache_level = common.get_node("./CACHE_LEVEL/text()", allocation)
- cache_id = common.get_node("./CACHE_ID/text()", allocation)
- clos_mask_list = allocation.xpath(f".//POLICY[VM = '{vmname}']/CLOS_MASK/text()")
-
- for clos_mask in clos_mask_list:
- index = get_clos_id(mask_list, cache_id, clos_mask, "None")
+ vm_name = common.get_node("./name/text()", vm_node)
+ vcpu_list = scenario_etree.xpath(f"//POLICY[VM = '{vm_name}']/VCPU/text()")
+ index_list = []
+ for vcpu in sorted(list(set(vcpu_list))):
+ type_list = scenario_etree.xpath(f"//POLICY[VM = '{vm_name}' and VCPU = '{vcpu}']/TYPE/text()")
+ for cache_type in sorted(list(set(type_list))):
+ if cache_type == "Data":
+ continue
+ index = get_clos_id(mask_list, policy_owner(vm_name, vcpu, cache_type))
index_list.append(index)
- create_clos_node(allocation_etree, common.get_node("./@id", vm_node), index_list)
+ create_clos_node(allocation_etree, common.get_node("./@id", vm_node), index_list)

-def creat_mask_list_node(board_etree, scenario_etree, allocation_etree, mask_list):
+def create_mask_list_node(board_etree, scenario_etree, allocation_etree, rdt_policy_list):
allocation_hv_node = common.get_node(f"//hv", allocation_etree)
if allocation_hv_node is None:
allocation_hv_node = common.append_node(f"/acrn-config/hv", None, allocation_etree)
- cache2_id_list = scenario_etree.xpath("//CACHE_ALLOCATION[CACHE_LEVEL = 2]/CACHE_ID/text()")
- cache2_id_list.sort()
+
if common.get_node("./clos_mask[@id = l3]", allocation_hv_node) is None:
clos_mask = common.append_node("./clos_mask", None, allocation_hv_node, id="l3")
- for i in range(0, len(mask_list)):
- if mask_list[i]["l3"] == "None":
- value = "0xffff"
- else:
- value = str(mask_list[i]["l3"])
+ length = common.get_node(f"//cache[@level='3']/capability/capacity_mask_length/text()", board_etree)
+ value = hex((1 << int(length)) - 1)
+ for i in range(0, len(rdt_policy_list)):
+ if rdt_policy_list[i].l3policy.get_clos_mask() is not None:
+ value = str(rdt_policy_list[i].l3policy.get_clos_mask())
common.append_node(f"./clos", value, clos_mask)
-
- for cache2 in cache2_id_list:
+ for index,cache2 in enumerate(L2Policy.cache2_id_list):
+ length = common.get_node(f"//cache[@level='2' and @id = '{cache2}']/capability/capacity_mask_length/text()", board_etree)
+ value = hex((1 << int(length)) - 1)
if common.get_node("./clos_mask[@id = '{cache2}']", allocation_hv_node) is None:
clos_mask = common.append_node("./clos_mask", None, allocation_hv_node, id=cache2)
- for i in range(0, len(mask_list)):
- if mask_list[i][cache2] == "None":
- value = "0xffff"
- else:
- value = str(mask_list[i][cache2] )
+ for i in range(0, len(rdt_policy_list)):
+ if rdt_policy_list[i].l2policy.get_clos_mask(index) is not None:
+ value = str(rdt_policy_list[i].l2policy.get_clos_mask(index))
common.append_node(f"./clos", value, clos_mask)

+def init_cache2_id_list(scenario_etree):
+ cache2_id_list = scenario_etree.xpath("//CACHE_ALLOCATION[CACHE_LEVEL = 2]/CACHE_ID/text()")
+ cache2_id_list.sort()
+ L2Policy.cache2_id_list = cache2_id_list
+
def fn(board_etree, scenario_etree, allocation_etree):
- mask_list = gen_all_clos_index(board_etree, scenario_etree, allocation_etree)
- creat_mask_list_node(board_etree, scenario_etree, allocation_etree, mask_list)
- alloc_clos_index(board_etree, scenario_etree, allocation_etree, mask_list)
+ init_cache2_id_list(scenario_etree)
+ policy_list = get_policy_list(board_etree, scenario_etree, allocation_etree)
+ create_mask_list_node(board_etree, scenario_etree, allocation_etree, policy_list)
+ alloc_clos_index(board_etree, scenario_etree, allocation_etree, policy_list)
--
2.17.1