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)