From 2cd13026ed09eb8d7d809206b5d091c09199f6ac Mon Sep 17 00:00:00 2001 From: Chenli Wei Date: Fri, 10 Jun 2022 16:42:34 +0800 Subject: [PATCH] misc: move the RDT interface to common library The current RDT class and interface was define by the clos.py which is mix get and merge RDT policy, create clos nodes. Now we need call these interface to check the CLOS IDs number after merged RDT policy, so this patch abstract the RDT interface to common and add an assert to check the CLOS IDs number. Tracked-On: #6690 Signed-off-by: Chenli Wei Signed-off-by: Junjie Mao --- misc/config_tools/library/rdt.py | 191 ++++++++++++++++++ .../scenario_config/elementpath_overlay.py | 11 + .../schema/checks/rdt_support.xsd | 8 + misc/config_tools/schema/datachecks.xsd | 1 + misc/config_tools/static_allocators/clos.py | 190 +---------------- 5 files changed, 217 insertions(+), 184 deletions(-) create mode 100644 misc/config_tools/library/rdt.py diff --git a/misc/config_tools/library/rdt.py b/misc/config_tools/library/rdt.py new file mode 100644 index 000000000..34a561ff1 --- /dev/null +++ b/misc/config_tools/library/rdt.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 Intel Corporation. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +import sys, os +sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'library')) +import common +import re +from collections import defaultdict +from collections import namedtuple + +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 match_policy(self, src): + for index in range(0, len(self.policy_list)): + if not self.policy_list[index].match_policy(src.policy_list[index]): + return False + return True + + def merge_policy(self, src): + if self.match_policy(src): + 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 True + return False + +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] + + def match_policy(self, src): + return self.l2policy.match_policy(src.l2policy) and self.l3policy.match_policy(src.l3policy) + + #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.match_policy(src): + self.l2policy.merge_policy(src.l2policy) + 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 + +class CdpPolicy(): + def __init__(self,data_list, code_list, owner): + self.data_policy = RdtPolicy(data_list, policy_owner(owner.vm_name, owner.vcpu, "Data")) + self.code_policy = RdtPolicy(code_list, policy_owner(owner.vm_name, owner.vcpu, "Code")) + + def merge_policy(self, src): + if self.code_policy.match_policy(src.code_policy) and self.data_policy.match_policy(src.data_policy): + self.code_policy.merge_policy(src.code_policy) + self.data_policy.merge_policy(src.data_policy) + return True + return False + +def merge_policy_list(policy_list): + result_list = [] + for index,p in enumerate(policy_list): + merged = False + for result in result_list: + if result.merge_policy(p): + merged = True + break; + if not merged: + result_list.append(p) + return result_list + +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") + +def cdp_enable(scenario_etree): + cdp_enable = common.get_node(f"//CDP_ENABLED/text()", scenario_etree) + return cdp_enable == "y" + +def convert_cdp_to_normal(cdp_policy_list): + policy_list = [] + for cdp_policy in cdp_policy_list: + policy_list.append(cdp_policy.data_policy) + policy_list.append(cdp_policy.code_policy) + return policy_list + +def get_policy_list(scenario_etree): + init_cache2_id_list(scenario_etree) + policy_owner_list = gen_policy_owner_list(scenario_etree) + + result_list = [] + for policy_owner in policy_owner_list: + dict_tmp = {} + policy_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}']") + if cdp_enable(scenario_etree): + data_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}' and TYPE = 'Data']") + code_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}' and TYPE = 'Code']") + if policy_owner.cache_type == "Code": + continue + elif policy_owner.cache_type == "Data": + result_list.append(CdpPolicy(data_list, code_list, policy_owner)) + elif 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)) + result_list = merge_policy_list(result_list) + + if cdp_enable(scenario_etree): + result_list = convert_cdp_to_normal(result_list) + + return result_list + +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 diff --git a/misc/config_tools/scenario_config/elementpath_overlay.py b/misc/config_tools/scenario_config/elementpath_overlay.py index 5178db3bd..c95015ee9 100644 --- a/misc/config_tools/scenario_config/elementpath_overlay.py +++ b/misc/config_tools/scenario_config/elementpath_overlay.py @@ -9,6 +9,7 @@ from decimal import Decimal from copy import copy import operator +import rdt import elementpath BaseParser = elementpath.XPath2Parser @@ -20,6 +21,8 @@ class CustomParser(BaseParser): 'has', 'duplicate-values', + + 'number-of-clos-id-needed', } method = CustomParser.method @@ -84,6 +87,14 @@ def select_duplicate_values_function(self, context=None): yield from duplicate_values() +@method(function('number-of-clos-id-needed', nargs=1)) +def evaluate_number_of_clos_id_needed(self, context=None): + op = self.get_argument(context, index=0) + try: + return len(rdt.get_policy_list(op.elem)) if op else 0 + except AttributeError as err: + raise self.error('XPTY0004', err) + ### # Collection of counter examples diff --git a/misc/config_tools/schema/checks/rdt_support.xsd b/misc/config_tools/schema/checks/rdt_support.xsd index 38c045471..74b0b64ed 100644 --- a/misc/config_tools/schema/checks/rdt_support.xsd +++ b/misc/config_tools/schema/checks/rdt_support.xsd @@ -89,4 +89,12 @@ This error cannot be fixed by adjusting the configuration. Report a `GitHub issu + + + The current CAT configuration requires {string($needed)} CLOS IDs, which exceeds the capacity of the platform which supports {string($capacity)} at most. + + + diff --git a/misc/config_tools/schema/datachecks.xsd b/misc/config_tools/schema/datachecks.xsd index ff32e973c..3f6b2ebca 100644 --- a/misc/config_tools/schema/datachecks.xsd +++ b/misc/config_tools/schema/datachecks.xsd @@ -17,6 +17,7 @@ + diff --git a/misc/config_tools/static_allocators/clos.py b/misc/config_tools/static_allocators/clos.py index f2add7d35..a9c4c348c 100644 --- a/misc/config_tools/static_allocators/clos.py +++ b/misc/config_tools/static_allocators/clos.py @@ -8,121 +8,12 @@ import sys, os sys.path.append(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', 'library')) import common +import rdt import re from collections import defaultdict from itertools import combinations from collections import namedtuple - -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 match_policy(self, src): - for index in range(0, len(self.policy_list)): - if not self.policy_list[index].match_policy(src.policy_list[index]): - return False - return True - - def merge_policy(self, src): - if self.match_policy(src): - 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 True - return False - -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] - - def match_policy(self, src): - return self.l2policy.match_policy(src.l2policy) and self.l3policy.match_policy(src.l3policy) - - #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.match_policy(src): - self.l2policy.merge_policy(src.l2policy) - 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 - -class CdpPolicy(): - def __init__(self,data_list, code_list, owner): - self.data_policy = RdtPolicy(data_list, policy_owner(owner.vm_name, owner.vcpu, "Data")) - self.code_policy = RdtPolicy(code_list, policy_owner(owner.vm_name, owner.vcpu, "Code")) - - def merge_policy(self, src): - if self.code_policy.match_policy(src.code_policy) and self.data_policy.match_policy(src.data_policy): - self.code_policy.merge_policy(src.code_policy) - self.data_policy.merge_policy(src.data_policy) - return True - 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: @@ -132,69 +23,6 @@ def create_clos_node(scenario_etree, vm_id, index_list): for index in index_list: common.append_node(f"./vcpu_clos", str(index), clos_node) -def merge_policy_list(policy_list): - result_list = [] - for index,p in enumerate(policy_list): - merged = False - for result in result_list: - if result.merge_policy(p): - merged = True - break; - if not merged: - result_list.append(p) - return result_list - -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") - -def cdp_enable(scenario_etree): - cdp_enable = common.get_node(f"//CDP_ENABLED/text()", scenario_etree) - return cdp_enable == "y" - -def convert_cdp_to_normal(cdp_policy_list): - policy_list = [] - for cdp_policy in cdp_policy_list: - policy_list.append(cdp_policy.data_policy) - policy_list.append(cdp_policy.code_policy) - return policy_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 = {} - policy_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}']") - if cdp_enable(scenario_etree): - data_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}' and TYPE = 'Data']") - code_list = scenario_etree.xpath(f"//POLICY[VM = '{policy_owner.vm_name}' and VCPU = '{policy_owner.vcpu}' and TYPE = 'Code']") - if policy_owner.cache_type == "Code": - continue - elif policy_owner.cache_type == "Data": - result_list.append(CdpPolicy(data_list, code_list, policy_owner)) - elif 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)) - result_list = merge_policy_list(result_list) - - if cdp_enable(scenario_etree): - result_list = convert_cdp_to_normal(result_list) - - return result_list - def get_clos_id(rdt_list, policy_owner): for index,rdt in enumerate(rdt_list): if rdt.find_policy_owner(policy_owner): @@ -208,10 +36,10 @@ def alloc_clos_index(board_etree, scenario_etree, allocation_etree, mask_list): vcpu_list = scenario_etree.xpath(f"//POLICY[VM = '{vm_name}']/VCPU/text()") index_list = [] for vcpu in sorted(list(set(vcpu_list))): - if cdp_enable(scenario_etree): - index = get_clos_id(mask_list, policy_owner(vm_name, vcpu, "Data")) // 2 + if rdt.cdp_enable(scenario_etree): + index = get_clos_id(mask_list, rdt.policy_owner(vm_name, vcpu, "Data")) // 2 else: - index = get_clos_id(mask_list, policy_owner(vm_name, vcpu, "Unified")) + index = get_clos_id(mask_list, rdt.policy_owner(vm_name, vcpu, "Unified")) index_list.append(index) create_clos_node(allocation_etree, common.get_node("./@id", vm_node), index_list) @@ -233,7 +61,7 @@ def create_mask_list_node(board_etree, scenario_etree, allocation_etree, rdt_pol else: value = default_l3_value common.append_node(f"./clos", value, clos_mask) - for index,cache2 in enumerate(L2Policy.cache2_id_list): + for index,cache2 in enumerate(rdt.L2Policy.cache2_id_list): length = common.get_node(f"//cache[@level='2' and @id = '{cache2}']/capability/capacity_mask_length/text()", board_etree) if length is not None: default_l2_value = hex((1 << int(length)) - 1) @@ -249,13 +77,7 @@ def create_mask_list_node(board_etree, scenario_etree, allocation_etree, rdt_pol value = default_l2_value 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): - init_cache2_id_list(scenario_etree) - policy_list = get_policy_list(board_etree, scenario_etree, allocation_etree) + policy_list = rdt.get_policy_list(scenario_etree) create_mask_list_node(board_etree, scenario_etree, allocation_etree, policy_list) alloc_clos_index(board_etree, scenario_etree, allocation_etree, policy_list)