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:
Chenli Wei 2022-06-10 16:42:34 +08:00 committed by acrnsi-robot
parent 27525d0ae6
commit 72c406c2b7
5 changed files with 217 additions and 184 deletions

View File

@ -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

View File

@ -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

View File

@ -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 &lt; 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>

View File

@ -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>

View File

@ -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)