From a1b266f80795ed7c4c22377273bc682b33f683f3 Mon Sep 17 00:00:00 2001 From: Chenli Wei Date: Fri, 29 Apr 2022 17:13:31 +0800 Subject: [PATCH] misc: refine CLOS module for expansibility 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 Signed-off-by: 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 | 270 ++++++++++++-------- 3 files changed, 171 insertions(+), 109 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 4ad2077c8..b48feef6b 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. - + diff --git a/misc/config_tools/static_allocators/clos.py b/misc/config_tools/static_allocators/clos.py index 1f0476422..a6130a20f 100644 --- a/misc/config_tools/static_allocators/clos.py +++ b/misc/config_tools/static_allocators/clos.py @@ -11,140 +11,202 @@ 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: + cache2_id_list = [] + + def __init__(self, policy): + self.policy_list = [] + 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: + 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 - 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) +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") - 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 + 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) - 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) +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) + if length is not None: + value = hex((1 << int(length)) - 1) + else: + value = "0xffff" + 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)