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 <chenli.wei@intel.com> Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
27525d0ae6
commit
72c406c2b7
|
@ -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
|
|
@ -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
|
||||
|
||||
|
|
|
@ -89,4 +89,12 @@ This error cannot be fixed by adjusting the configuration. Report a `GitHub issu
|
|||
</xs:annotation>
|
||||
</xs:assert>
|
||||
|
||||
<xs:assert test="every $needed in number-of-clos-id-needed(/acrn-config) satisfies
|
||||
every $capacity in min(//caches/cache/capability[@id='CAT']/clos_number) satisfies
|
||||
$needed < 0">
|
||||
<xs:annotation acrn:severity="error" acrn:report-on="/acrn-config/hv/CACHE_REGION">
|
||||
<xs:documentation>The current CAT configuration requires {string($needed)} CLOS IDs, which exceeds the capacity of the platform which supports {string($capacity)} at most.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:assert>
|
||||
|
||||
</xs:schema>
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
<xi:include href="checks/virtio_devices.xsd" xpointer="xpointer(id('root')/*)" />
|
||||
<xi:include href="checks/vuart_config.xsd" xpointer="xpointer(id('root')/*)" />
|
||||
<xi:include href="checks/ivsh_memory.xsd" xpointer="xpointer(id('root')/*)" />
|
||||
<xi:include href="checks/rdt_support.xsd" xpointer="xpointer(id('root')/*)" />
|
||||
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue