Added condition operand, adjusted tests to parse it & a few changes to get the kernelDG tests working

This commit is contained in:
stefandesouza
2023-10-29 16:36:00 +01:00
parent 14a2aa0b52
commit ebb973493b
20 changed files with 728 additions and 672 deletions

View File

@@ -10,8 +10,8 @@ import osaca.db_interface as dbi
from osaca.db_interface import sanity_check
from osaca.semantics import MachineModel
from osaca.parser import instructionForm
from osaca.parser.memory import memoryOperand
from osaca.parser.register import registerOperand
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
import copy
@@ -21,8 +21,8 @@ class TestDBInterface(unittest.TestCase):
sample_entry = instructionForm(
instruction_id="DoItRightAndDoItFast",
operands_id=[
memoryOperand(offset_ID="imd", base_id="gpr", index_id="gpr", scale_id=8),
registerOperand(name_id="xmm"),
MemoryOperand(offset_ID="imd", base_id="gpr", index_id="gpr", scale_id=8),
RegisterOperand(name_id="xmm"),
],
throughput=1.25,
latency=125,

View File

@@ -9,6 +9,7 @@ import unittest
from osaca.frontend import Frontend
from osaca.parser import ParserAArch64, ParserX86ATT
from osaca.semantics import ArchSemantics, KernelDG, MachineModel, reduce_to_section
from osaca.parser.operand import Operand
class TestFrontend(unittest.TestCase):
@@ -41,6 +42,7 @@ class TestFrontend(unittest.TestCase):
self.machine_model_tx2,
path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "isa/aarch64.yml"),
)
for i in range(len(self.kernel_x86)):
self.semantics_csx.assign_src_dst(self.kernel_x86[i])
self.semantics_csx.assign_tp_lt(self.kernel_x86[i])

View File

@@ -10,10 +10,10 @@ from pyparsing import ParseException
from osaca.parser import ParserAArch64, instructionForm
from osaca.parser.operand import Operand
from osaca.parser.directive import directiveOperand
from osaca.parser.memory import memoryOperand
from osaca.parser.register import registerOperand
from osaca.parser.immediate import immediateOperand
from osaca.parser.directive import DirectiveOperand
from osaca.parser.memory import MemoryOperand
from osaca.parser.register import RegisterOperand
from osaca.parser.immediate import ImmediateOperand
class TestParserAArch64(unittest.TestCase):
@@ -203,7 +203,7 @@ class TestParserAArch64(unittest.TestCase):
instruction_form_3 = instructionForm(
instruction_id=None,
operands_id=[],
directive_id=directiveOperand(name_id="cfi_def_cfa", parameter_id=["w29", "-16"]),
directive_id=DirectiveOperand(name_id="cfi_def_cfa", parameter_id=["w29", "-16"]),
comment_id=None,
label_id=None,
line=".cfi_def_cfa w29, -16",
@@ -212,10 +212,10 @@ class TestParserAArch64(unittest.TestCase):
instruction_form_4 = instructionForm(
instruction_id="ldr",
operands_id=[
registerOperand(prefix_id="s", name_id="0"),
memoryOperand(
RegisterOperand(prefix_id="s", name_id="0"),
MemoryOperand(
offset_ID=None,
base_id=registerOperand(prefix_id="x", name_id="11"),
base_id=RegisterOperand(prefix_id="x", name_id="11"),
index_id={
"prefix": "w",
"name": "10",
@@ -236,9 +236,9 @@ class TestParserAArch64(unittest.TestCase):
instruction_id="prfm",
operands_id=[
{"prfop": {"type": ["PLD"], "target": ["L1"], "policy": ["KEEP"]}},
memoryOperand(
MemoryOperand(
offset_ID={"value": 2048},
base_id=registerOperand(prefix_id="x", name_id="26"),
base_id=RegisterOperand(prefix_id="x", name_id="26"),
index_id=None,
scale_id=1,
),
@@ -252,11 +252,11 @@ class TestParserAArch64(unittest.TestCase):
instruction_form_6 = instructionForm(
instruction_id="stp",
operands_id=[
registerOperand(prefix_id="x", name_id="29"),
registerOperand(prefix_id="x", name_id="30"),
memoryOperand(
RegisterOperand(prefix_id="x", name_id="29"),
RegisterOperand(prefix_id="x", name_id="30"),
MemoryOperand(
offset_ID={"value": -16},
base_id=registerOperand(name_id="sp", prefix_id="x"),
base_id=RegisterOperand(name_id="sp", prefix_id="x"),
index_id=None,
scale_id=1,
pre_indexed=True,
@@ -271,11 +271,11 @@ class TestParserAArch64(unittest.TestCase):
instruction_form_7 = instructionForm(
instruction_id="ldp",
operands_id=[
registerOperand(prefix_id="q", name_id="2"),
registerOperand(prefix_id="q", name_id="3"),
memoryOperand(
RegisterOperand(prefix_id="q", name_id="2"),
RegisterOperand(prefix_id="q", name_id="3"),
MemoryOperand(
offset_ID=None,
base_id=registerOperand(name_id="11", prefix_id="x"),
base_id=RegisterOperand(name_id="11", prefix_id="x"),
index_id=None,
scale_id=1,
post_indexed={"value": 64},
@@ -290,11 +290,11 @@ class TestParserAArch64(unittest.TestCase):
instruction_form_8 = instructionForm(
instruction_id="fcmla",
operands_id=[
registerOperand(prefix_id="z", name_id="26", shape="d"),
registerOperand(prefix_id="p", name_id="0", predication="m"),
registerOperand(prefix_id="z", name_id="29", shape="d"),
registerOperand(prefix_id="z", name_id="21", shape="d"),
immediateOperand(value_id=90, type_id="int"),
RegisterOperand(prefix_id="z", name_id="26", shape="d"),
RegisterOperand(prefix_id="p", name_id="0", predication="m"),
RegisterOperand(prefix_id="z", name_id="29", shape="d"),
RegisterOperand(prefix_id="z", name_id="21", shape="d"),
ImmediateOperand(value_id=90, type_id="int"),
],
directive_id=None,
comment_id=None,
@@ -305,9 +305,9 @@ class TestParserAArch64(unittest.TestCase):
instruction_form_9 = instructionForm(
instruction_id="ccmn",
operands_id=[
registerOperand(prefix_id="x", name_id="11"),
immediateOperand(value_id=1, type_id="int"),
immediateOperand(value_id=3, type_id="int"),
RegisterOperand(prefix_id="x", name_id="11"),
ImmediateOperand(value_id=1, type_id="int"),
ImmediateOperand(value_id=3, type_id="int"),
{"condition": "EQ"},
],
directive_id=None,
@@ -372,17 +372,17 @@ class TestParserAArch64(unittest.TestCase):
instr_list_with_index = "ld4 {v0.S, v1.S, v2.S, v3.S}[2]"
instr_range_single = "dummy { z1.d }"
reg_list = [
registerOperand(prefix_id="x", name_id="5"),
registerOperand(prefix_id="x", name_id="6"),
registerOperand(prefix_id="x", name_id="7"),
RegisterOperand(prefix_id="x", name_id="5"),
RegisterOperand(prefix_id="x", name_id="6"),
RegisterOperand(prefix_id="x", name_id="7"),
]
reg_list_idx = [
registerOperand(prefix_id="v", name_id="0", shape="S", index=2),
registerOperand(prefix_id="v", name_id="1", shape="S", index=2),
registerOperand(prefix_id="v", name_id="2", shape="S", index=2),
registerOperand(prefix_id="v", name_id="3", shape="S", index=2),
RegisterOperand(prefix_id="v", name_id="0", shape="S", index=2),
RegisterOperand(prefix_id="v", name_id="1", shape="S", index=2),
RegisterOperand(prefix_id="v", name_id="2", shape="S", index=2),
RegisterOperand(prefix_id="v", name_id="3", shape="S", index=2),
]
reg_list_single = [registerOperand(prefix_id="z", name_id="1", shape="d")]
reg_list_single = [RegisterOperand(prefix_id="z", name_id="1", shape="d")]
prange = self.parser.parse_line(instr_range)
plist = self.parser.parse_line(instr_list)
@@ -397,22 +397,22 @@ class TestParserAArch64(unittest.TestCase):
# self.assertEqual(p_single.operands, reg_list_single)
def test_reg_dependency(self):
reg_1_1 = registerOperand(prefix_id="b", name_id="1")
reg_1_2 = registerOperand(prefix_id="h", name_id="1")
reg_1_3 = registerOperand(prefix_id="s", name_id="1")
reg_1_4 = registerOperand(prefix_id="d", name_id="1")
reg_1_4 = registerOperand(prefix_id="q", name_id="1")
reg_2_1 = registerOperand(prefix_id="w", name_id="2")
reg_2_2 = registerOperand(prefix_id="x", name_id="2")
reg_v1_1 = registerOperand(prefix_id="v", name_id="11", lanes="16", shape="b")
reg_v1_2 = registerOperand(prefix_id="v", name_id="11", lanes="8", shape="h")
reg_v1_3 = registerOperand(prefix_id="v", name_id="11", lanes="4", shape="s")
reg_v1_4 = registerOperand(prefix_id="v", name_id="11", lanes="2", shape="d")
reg_1_1 = RegisterOperand(prefix_id="b", name_id="1")
reg_1_2 = RegisterOperand(prefix_id="h", name_id="1")
reg_1_3 = RegisterOperand(prefix_id="s", name_id="1")
reg_1_4 = RegisterOperand(prefix_id="d", name_id="1")
reg_1_4 = RegisterOperand(prefix_id="q", name_id="1")
reg_2_1 = RegisterOperand(prefix_id="w", name_id="2")
reg_2_2 = RegisterOperand(prefix_id="x", name_id="2")
reg_v1_1 = RegisterOperand(prefix_id="v", name_id="11", lanes="16", shape="b")
reg_v1_2 = RegisterOperand(prefix_id="v", name_id="11", lanes="8", shape="h")
reg_v1_3 = RegisterOperand(prefix_id="v", name_id="11", lanes="4", shape="s")
reg_v1_4 = RegisterOperand(prefix_id="v", name_id="11", lanes="2", shape="d")
reg_b5 = registerOperand(prefix_id="b", name_id="5")
reg_q15 = registerOperand(prefix_id="q", name_id="15")
reg_v10 = registerOperand(prefix_id="v", name_id="10", lanes="2", shape="s")
reg_v20 = registerOperand(prefix_id="v", name_id="20", lanes="2", shape="d")
reg_b5 = RegisterOperand(prefix_id="b", name_id="5")
reg_q15 = RegisterOperand(prefix_id="q", name_id="15")
reg_v10 = RegisterOperand(prefix_id="v", name_id="10", lanes="2", shape="s")
reg_v20 = RegisterOperand(prefix_id="v", name_id="20", lanes="2", shape="d")
reg_1 = [reg_1_1, reg_1_2, reg_1_3, reg_1_4]
reg_2 = [reg_2_1, reg_2_2]

View File

@@ -9,7 +9,7 @@ import unittest
from pyparsing import ParseException
from osaca.parser import ParserX86ATT, instructionForm
from osaca.parser.register import registerOperand
from osaca.parser.register import RegisterOperand
class TestParserX86ATT(unittest.TestCase):
@@ -233,10 +233,10 @@ class TestParserX86ATT(unittest.TestCase):
register_str_3 = "%xmm1"
register_str_4 = "%rip"
parsed_reg_1 = registerOperand(name_id="rax")
parsed_reg_2 = registerOperand(name_id="r9")
parsed_reg_3 = registerOperand(name_id="xmm1")
parsed_reg_4 = registerOperand(name_id="rip")
parsed_reg_1 = RegisterOperand(name_id="rax")
parsed_reg_2 = RegisterOperand(name_id="r9")
parsed_reg_3 = RegisterOperand(name_id="xmm1")
parsed_reg_4 = RegisterOperand(name_id="rip")
self.assertEqual(self.parser.parse_register(register_str_1), parsed_reg_1)
self.assertEqual(self.parser.parse_register(register_str_2), parsed_reg_2)
@@ -259,22 +259,22 @@ class TestParserX86ATT(unittest.TestCase):
)
def test_reg_dependency(self):
reg_a1 = registerOperand(name_id="rax")
reg_a2 = registerOperand(name_id="eax")
reg_a3 = registerOperand(name_id="ax")
reg_a4 = registerOperand(name_id="al")
reg_r11 = registerOperand(name_id="r11")
reg_r11b = registerOperand(name_id="r11b")
reg_r11d = registerOperand(name_id="r11d")
reg_r11w = registerOperand(name_id="r11w")
reg_xmm1 = registerOperand(name_id="xmm1")
reg_ymm1 = registerOperand(name_id="ymm1")
reg_zmm1 = registerOperand(name_id="zmm1")
reg_a1 = RegisterOperand(name_id="rax")
reg_a2 = RegisterOperand(name_id="eax")
reg_a3 = RegisterOperand(name_id="ax")
reg_a4 = RegisterOperand(name_id="al")
reg_r11 = RegisterOperand(name_id="r11")
reg_r11b = RegisterOperand(name_id="r11b")
reg_r11d = RegisterOperand(name_id="r11d")
reg_r11w = RegisterOperand(name_id="r11w")
reg_xmm1 = RegisterOperand(name_id="xmm1")
reg_ymm1 = RegisterOperand(name_id="ymm1")
reg_zmm1 = RegisterOperand(name_id="zmm1")
reg_b1 = registerOperand(name_id="rbx")
reg_r15 = registerOperand(name_id="r15")
reg_xmm2 = registerOperand(name_id="xmm2")
reg_ymm3 = registerOperand(name_id="ymm3")
reg_b1 = RegisterOperand(name_id="rbx")
reg_r15 = RegisterOperand(name_id="r15")
reg_xmm2 = RegisterOperand(name_id="xmm2")
reg_ymm3 = RegisterOperand(name_id="ymm3")
reg_a = [reg_a1, reg_a2, reg_a3, reg_a4]
reg_r = [reg_r11, reg_r11b, reg_r11d, reg_r11w]

View File

@@ -19,9 +19,9 @@ from osaca.semantics import (
MachineModel,
reduce_to_section,
)
from osaca.parser.register import registerOperand
from osaca.parser.memory import memoryOperand
from osaca.parser.identifier import identifierOperand
from osaca.parser.register import RegisterOperand
from osaca.parser.memory import MemoryOperand
from osaca.parser.identifier import IdentifierOperand
class TestSemanticTools(unittest.TestCase):
@@ -94,6 +94,7 @@ class TestSemanticTools(unittest.TestCase):
)
cls.machine_model_zen = MachineModel(arch="zen1")
"""
for i in range(len(cls.kernel_x86)):
cls.semantics_csx.assign_src_dst(cls.kernel_x86[i])
cls.semantics_csx.assign_tp_lt(cls.kernel_x86[i])
@@ -103,9 +104,11 @@ class TestSemanticTools(unittest.TestCase):
for i in range(len(cls.kernel_x86_long_LCD)):
cls.semantics_csx.assign_src_dst(cls.kernel_x86_long_LCD[i])
cls.semantics_csx.assign_tp_lt(cls.kernel_x86_long_LCD[i])
for i in range(len(cls.kernel_AArch64)):
cls.semantics_tx2.assign_src_dst(cls.kernel_AArch64[i])
cls.semantics_tx2.assign_tp_lt(cls.kernel_AArch64[i])
for i in range(len(cls.kernel_aarch64_memdep)):
cls.semantics_tx2.assign_src_dst(cls.kernel_aarch64_memdep[i])
cls.semantics_tx2.assign_tp_lt(cls.kernel_aarch64_memdep[i])
@@ -115,7 +118,11 @@ class TestSemanticTools(unittest.TestCase):
for i in range(len(cls.kernel_aarch64_deps)):
cls.semantics_a64fx.assign_src_dst(cls.kernel_aarch64_deps[i])
cls.semantics_a64fx.assign_tp_lt(cls.kernel_aarch64_deps[i])
"""
print(cls.kernel_AArch64[2], "\n")
cls.semantics_tx2.assign_src_dst(cls.kernel_AArch64[2])
cls.semantics_tx2.assign_tp_lt(cls.kernel_AArch64[2])
print(cls.kernel_AArch64[2])
###########
# Tests
###########
@@ -126,7 +133,7 @@ class TestSemanticTools(unittest.TestCase):
ArchSemantics(tmp_mm)
except ValueError:
self.fail()
'''
def test_machine_model_various_functions(self):
# check dummy MachineModel creation
try:
@@ -148,31 +155,31 @@ class TestSemanticTools(unittest.TestCase):
self.assertIsNone(test_mm_arm.get_instruction("NOT_IN_DB", []))
name_x86_1 = "vaddpd"
operands_x86_1 = [
registerOperand(name_id="xmm"),
registerOperand(name_id="xmm"),
registerOperand(name_id="xmm"),
RegisterOperand(name_id="xmm"),
RegisterOperand(name_id="xmm"),
RegisterOperand(name_id="xmm"),
]
instr_form_x86_1 = test_mm_x86.get_instruction(name_x86_1, operands_x86_1)
self.assertEqual(instr_form_x86_1, test_mm_x86.get_instruction(name_x86_1, operands_x86_1))
self.assertEqual(
test_mm_x86.get_instruction("jg", [identifierOperand()]),
test_mm_x86.get_instruction("jg", [identifierOperand()]),
test_mm_x86.get_instruction("jg", [IdentifierOperand()]),
test_mm_x86.get_instruction("jg", [IdentifierOperand()]),
)
name_arm_1 = "fadd"
operands_arm_1 = [
registerOperand(prefix_id="v", shape="s"),
registerOperand(prefix_id="v", shape="s"),
registerOperand(prefix_id="v", shape="s"),
RegisterOperand(prefix_id="v", shape="s"),
RegisterOperand(prefix_id="v", shape="s"),
RegisterOperand(prefix_id="v", shape="s"),
]
instr_form_arm_1 = test_mm_arm.get_instruction(name_arm_1, operands_arm_1)
self.assertEqual(instr_form_arm_1, test_mm_arm.get_instruction(name_arm_1, operands_arm_1))
self.assertEqual(
test_mm_arm.get_instruction("b.ne", [identifierOperand()]),
test_mm_arm.get_instruction("b.ne", [identifierOperand()]),
test_mm_arm.get_instruction("b.ne", [IdentifierOperand()]),
test_mm_arm.get_instruction("b.ne", [IdentifierOperand()]),
)
self.assertEqual(
test_mm_arm.get_instruction("b.someNameThatDoesNotExist", [identifierOperand()]),
test_mm_arm.get_instruction("b.someOtherName", [identifierOperand()]),
test_mm_arm.get_instruction("b.someNameThatDoesNotExist", [IdentifierOperand()]),
test_mm_arm.get_instruction("b.someOtherName", [IdentifierOperand()]),
)
# test full instruction name
@@ -189,8 +196,8 @@ class TestSemanticTools(unittest.TestCase):
# test get_store_tp
self.assertEqual(
test_mm_x86.get_store_throughput(
memoryOperand(
base_id=registerOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
MemoryOperand(
base_id=RegisterOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
)
)[0].port_pressure,
[[2, "237"], [2, "4"]],
@@ -198,8 +205,8 @@ class TestSemanticTools(unittest.TestCase):
self.assertEqual(
test_mm_x86.get_store_throughput(
memoryOperand(
base_id=registerOperand(prefix_id="NOT_IN_DB"),
MemoryOperand(
base_id=RegisterOperand(prefix_id="NOT_IN_DB"),
offset_ID=None,
index_id="NOT_NONE",
scale_id=1,
@@ -210,8 +217,8 @@ class TestSemanticTools(unittest.TestCase):
self.assertEqual(
test_mm_arm.get_store_throughput(
memoryOperand(
base_id=registerOperand(prefix_id="x"),
MemoryOperand(
base_id=RegisterOperand(prefix_id="x"),
offset_ID=None,
index_id=None,
scale_id=1,
@@ -222,8 +229,8 @@ class TestSemanticTools(unittest.TestCase):
self.assertEqual(
test_mm_arm.get_store_throughput(
memoryOperand(
base_id=registerOperand(prefix_id="NOT_IN_DB"),
MemoryOperand(
base_id=RegisterOperand(prefix_id="NOT_IN_DB"),
offset_ID=None,
index_id=None,
scale_id=1,
@@ -234,16 +241,16 @@ class TestSemanticTools(unittest.TestCase):
# test get_store_lt
self.assertEqual(
test_mm_x86.get_store_latency(
memoryOperand(
base_id=registerOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
MemoryOperand(
base_id=RegisterOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
)
),
0,
)
self.assertEqual(
test_mm_arm.get_store_latency(
memoryOperand(
base_id=registerOperand(prefix_id="x"),
MemoryOperand(
base_id=RegisterOperand(prefix_id="x"),
offset_ID=None,
index_id=None,
scale_id=1,
@@ -258,8 +265,8 @@ class TestSemanticTools(unittest.TestCase):
# test default load tp
self.assertEqual(
test_mm_x86.get_load_throughput(
memoryOperand(
base_id=registerOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
MemoryOperand(
base_id=RegisterOperand(name_id="x"), offset_ID=None, index_id=None, scale_id=1
)
)[0].port_pressure,
[[1, "23"], [1, ["2D", "3D"]]],
@@ -310,391 +317,397 @@ class TestSemanticTools(unittest.TestCase):
self.assertTrue(instruction_form.latency != None)
self.assertIsInstance(instruction_form.port_pressure, list)
self.assertEqual(len(instruction_form.port_pressure), port_num)
'''
def test_optimal_throughput_assignment(self):
# x86
kernel_fixed = deepcopy(self.kernel_x86)
self.semantics_csx.add_semantics(kernel_fixed)
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
"""
# x86
kernel_fixed = deepcopy(self.kernel_x86)
self.semantics_csx.add_semantics(kernel_fixed)
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
kernel_optimal = deepcopy(kernel_fixed)
self.semantics_csx.assign_optimal_throughput(kernel_optimal)
tp_fixed = self.semantics_csx.get_throughput_sum(kernel_fixed)
tp_optimal = self.semantics_csx.get_throughput_sum(kernel_optimal)
self.assertNotEqual(tp_fixed, tp_optimal)
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
# test multiple port assignment options
test_mm_x86 = MachineModel(path_to_yaml=self._find_file("test_db_x86.yml"))
tmp_semantics = ArchSemantics(test_mm_x86)
tmp_code_1 = "fantasyinstr1 %rax, %rax\n"
tmp_code_2 = "fantasyinstr1 %rax, %rax\nfantasyinstr2 %rbx, %rbx\n"
tmp_kernel_1 = self.parser_x86.parse_file(tmp_code_1)
tmp_kernel_2 = self.parser_x86.parse_file(tmp_code_2)
tmp_semantics.add_semantics(tmp_kernel_1)
tmp_semantics.add_semantics(tmp_kernel_2)
tmp_semantics.assign_optimal_throughput(tmp_kernel_1)
tmp_semantics.assign_optimal_throughput(tmp_kernel_2)
k1i1_pp = [round(x, 2) for x in tmp_kernel_1[0]["port_pressure"]]
k2i1_pp = [round(x, 2) for x in tmp_kernel_2[0]["port_pressure"]]
self.assertEqual(k1i1_pp, [0.33, 0.0, 0.33, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.0, 0.0])
self.assertEqual(k2i1_pp, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])
kernel_optimal = deepcopy(kernel_fixed)
self.semantics_csx.assign_optimal_throughput(kernel_optimal)
tp_fixed = self.semantics_csx.get_throughput_sum(kernel_fixed)
tp_optimal = self.semantics_csx.get_throughput_sum(kernel_optimal)
self.assertNotEqual(tp_fixed, tp_optimal)
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
# test multiple port assignment options
test_mm_x86 = MachineModel(path_to_yaml=self._find_file("test_db_x86.yml"))
tmp_semantics = ArchSemantics(test_mm_x86)
tmp_code_1 = "fantasyinstr1 %rax, %rax\n"
tmp_code_2 = "fantasyinstr1 %rax, %rax\nfantasyinstr2 %rbx, %rbx\n"
tmp_kernel_1 = self.parser_x86.parse_file(tmp_code_1)
tmp_kernel_2 = self.parser_x86.parse_file(tmp_code_2)
tmp_semantics.add_semantics(tmp_kernel_1)
tmp_semantics.add_semantics(tmp_kernel_2)
tmp_semantics.assign_optimal_throughput(tmp_kernel_1)
tmp_semantics.assign_optimal_throughput(tmp_kernel_2)
k1i1_pp = [round(x, 2) for x in tmp_kernel_1[0].port_pressure]
k2i1_pp = [round(x, 2) for x in tmp_kernel_2[0].port_pressure]
self.assertEqual(k1i1_pp, [0.33, 0.0, 0.33, 0.0, 0.0, 0.0, 0.0, 0.0, 0.33, 0.0, 0.0])
self.assertEqual(k2i1_pp, [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0])
# arm
kernel_fixed = deepcopy(self.kernel_AArch64)
self.semantics_tx2.add_semantics(kernel_fixed)
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
kernel_optimal = deepcopy(kernel_fixed)
self.semantics_tx2.assign_optimal_throughput(kernel_optimal)
tp_fixed = self.semantics_tx2.get_throughput_sum(kernel_fixed)
tp_optimal = self.semantics_tx2.get_throughput_sum(kernel_optimal)
self.assertNotEqual(tp_fixed, tp_optimal)
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
# arm
kernel_fixed = deepcopy(self.kernel_AArch64)
def test_kernelDG_x86(self):
#
# 4
# \___>6__>7
# /
# 3
# 5_______>9
#
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=3))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=3)), 6)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=4))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=4)), 6)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=5))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=5)), 9)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=6))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=6)), 7)
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=7)), [])
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=8)), [])
with self.assertRaises(ValueError):
dg.get_dependent_instruction_forms()
# test dot creation
dg.export_graph(filepath="/dev/null")
self.semantics_tx2.add_semantics(kernel_fixed)
def test_memdependency_x86(self):
dg = KernelDG(
self.kernel_x86_memdep,
self.parser_x86,
self.machine_model_csx,
self.semantics_csx,
)
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {6, 8})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {10, 12})
with self.assertRaises(ValueError):
dg.get_dependent_instruction_forms()
# test dot creation
dg.export_graph(filepath="/dev/null")
self.assertEqual(get_unmatched_instruction_ratio(kernel_fixed), 0)
def test_kernelDG_AArch64(self):
dg = KernelDG(
self.kernel_AArch64,
self.parser_AArch64,
self.machine_model_tx2,
self.semantics_tx2,
)
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {7, 8})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=4)), {9, 10})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {6, 7, 8})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=6)), {9, 10})
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=7)), 13)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=8)), 14)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=9)), 16)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=10)), 17)
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=11)), {13, 14})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=12)), {16, 17})
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=13)), 15)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=14)), 15)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=15))), 0)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=16)), 18)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=17)), 18)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=18))), 0)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=19))), 0)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=20))), 0)
with self.assertRaises(ValueError):
dg.get_dependent_instruction_forms()
# test dot creation
dg.export_graph(filepath="/dev/null")
kernel_optimal = deepcopy(kernel_fixed)
self.semantics_tx2.assign_optimal_throughput(kernel_optimal)
tp_fixed = self.semantics_tx2.get_throughput_sum(kernel_fixed)
tp_optimal = self.semantics_tx2.get_throughput_sum(kernel_optimal)
self.assertNotEqual(tp_fixed, tp_optimal)
self.assertTrue(max(tp_optimal) <= max(tp_fixed))
def test_kernelDG_SVE(self):
KernelDG(
self.kernel_aarch64_SVE,
self.parser_AArch64,
self.machine_model_a64fx,
self.semantics_a64fx,
)
# TODO check for correct analysis
def test_kernelDG_x86(self):
#
# 4
# \___>6__>7
# /
# 3
# 5_______>9
#
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=3))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=3)), 6)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=4))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=4)), 6)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=5))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=5)), 9)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=6))), 1)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=6)), 7)
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=7)), [])
self.assertEqual(list(dg.get_dependent_instruction_forms(line_number=8)), [])
with self.assertRaises(ValueError):
dg.get_dependent_instruction_forms()
# test dot creation
dg.export_graph(filepath="/dev/null")
def test_hidden_load(self):
machine_model_hld = MachineModel(
path_to_yaml=self._find_file("hidden_load_machine_model.yml")
)
self.assertTrue(machine_model_hld.has_hidden_loads())
semantics_hld = ArchSemantics(machine_model_hld)
kernel_hld = self.parser_x86.parse_file(self.code_x86)
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)[-3:]
kernel_hld_3 = self.parser_x86.parse_file(self.code_x86)[5:8]
semantics_hld.add_semantics(kernel_hld)
semantics_hld.add_semantics(kernel_hld_2)
semantics_hld.add_semantics(kernel_hld_3)
num_hidden_loads = len([x for x in kernel_hld if INSTR_flags.HIDDEN_LD in x.flags])
num_hidden_loads_2 = len([x for x in kernel_hld_2 if INSTR_flags.HIDDEN_LD in x.flags])
num_hidden_loads_3 = len([x for x in kernel_hld_3 if INSTR_flags.HIDDEN_LD in x.flags])
self.assertEqual(num_hidden_loads, 1)
self.assertEqual(num_hidden_loads_2, 0)
self.assertEqual(num_hidden_loads_3, 1)
def test_cyclic_dag(self):
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
dg.dg.add_edge(100, 101, latency=1.0)
dg.dg.add_edge(101, 102, latency=2.0)
dg.dg.add_edge(102, 100, latency=3.0)
with self.assertRaises(NotImplementedError):
dg.get_critical_path()
with self.assertRaises(NotImplementedError):
dg.get_loopcarried_dependencies()
def test_loop_carried_dependency_aarch64(self):
dg = KernelDG(
self.kernel_aarch64_memdep,
self.parser_AArch64,
self.machine_model_tx2,
self.semantics_tx2,
)
lc_deps = dg.get_loopcarried_dependencies()
self.assertEqual(len(lc_deps), 4)
# based on line 6
dep_path = "6-10-11-12-13-14"
self.assertEqual(lc_deps[dep_path]["latency"], 29.0)
self.assertEqual(
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
[(6, 4.0), (10, 6.0), (11, 6.0), (12, 6.0), (13, 6.0), (14, 1.0)],
)
dg = KernelDG(
self.kernel_aarch64_deps,
self.parser_AArch64,
self.machine_model_a64fx,
self.semantics_a64fx,
flag_dependencies=True,
)
lc_deps = dg.get_loopcarried_dependencies()
self.assertEqual(len(lc_deps), 2)
# based on line 4
dep_path = "4-5-6-9-10-11-12"
self.assertEqual(lc_deps[dep_path]["latency"], 7.0)
self.assertEqual(
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
[(4, 1.0), (5, 1.0), (6, 1.0), (9, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
)
dg = KernelDG(
self.kernel_aarch64_deps,
self.parser_AArch64,
self.machine_model_a64fx,
self.semantics_a64fx,
flag_dependencies=False,
)
lc_deps = dg.get_loopcarried_dependencies()
self.assertEqual(len(lc_deps), 1)
# based on line 4
dep_path = "4-5-10-11-12"
self.assertEqual(lc_deps[dep_path]["latency"], 5.0)
self.assertEqual(
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
[(4, 1.0), (5, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
)
def test_loop_carried_dependency_x86(self):
lcd_id = "8"
lcd_id2 = "5"
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
lc_deps = dg.get_loopcarried_dependencies()
# self.assertEqual(len(lc_deps), 2)
# ID 8
self.assertEqual(
lc_deps[lcd_id]["root"], dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"]
)
self.assertEqual(len(lc_deps[lcd_id]["dependencies"]), 1)
self.assertEqual(
lc_deps[lcd_id]["dependencies"][0][0],
dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"],
)
# w/ flag dependencies: ID 9 w/ len=2
# w/o flag dependencies: ID 5 w/ len=1
# TODO discuss
self.assertEqual(
lc_deps[lcd_id2]["root"],
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
)
self.assertEqual(len(lc_deps[lcd_id2]["dependencies"]), 1)
self.assertEqual(
lc_deps[lcd_id2]["dependencies"][0][0],
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
)
def test_timeout_during_loop_carried_dependency(self):
start_time = time.perf_counter()
KernelDG(
self.kernel_x86_long_LCD,
self.parser_x86,
self.machine_model_csx,
self.semantics_x86,
timeout=10,
)
end_time = time.perf_counter()
time_10 = end_time - start_time
start_time = time.perf_counter()
KernelDG(
self.kernel_x86_long_LCD,
self.parser_x86,
self.machine_model_csx,
self.semantics_x86,
timeout=2,
)
end_time = time.perf_counter()
time_2 = end_time - start_time
# self.assertTrue(time_10 > 10)
self.assertTrue(2 < time_2)
# self.assertTrue(time_2 < (time_10 - 7))
def test_is_read_is_written_x86(self):
# independent form HW model
dag = KernelDG(self.kernel_x86, self.parser_x86, None, None)
reg_rcx = registerOperand(name_id="rcx")
reg_ymm1 = registerOperand(name_id="ymm1")
instr_form_r_c = self.parser_x86.parse_line("vmovsd %xmm0, (%r15,%rcx,8)")
self.semantics_csx.assign_src_dst(instr_form_r_c)
instr_form_non_r_c = self.parser_x86.parse_line("movl %xmm0, (%r15,%rax,8)")
self.semantics_csx.assign_src_dst(instr_form_non_r_c)
instr_form_w_c = self.parser_x86.parse_line("movi $0x05ACA, %rcx")
self.semantics_csx.assign_src_dst(instr_form_w_c)
instr_form_rw_ymm_1 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm1, %ymm0, %ymm1")
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_1)
instr_form_rw_ymm_2 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm0, %ymm1, %ymm1")
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_2)
instr_form_r_ymm = self.parser_x86.parse_line("vmovapd %ymm1, %ymm0")
self.semantics_csx.assign_src_dst(instr_form_r_ymm)
self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c))
self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c))
self.assertFalse(dag.is_read(reg_rcx, instr_form_w_c))
self.assertTrue(dag.is_written(reg_rcx, instr_form_w_c))
self.assertFalse(dag.is_written(reg_rcx, instr_form_r_c))
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_1))
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_2))
self.assertTrue(dag.is_read(reg_ymm1, instr_form_r_ymm))
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_1))
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_2))
self.assertFalse(dag.is_written(reg_ymm1, instr_form_r_ymm))
def test_is_read_is_written_AArch64(self):
# independent form HW model
dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None, None)
reg_x1 = registerOperand(prefix_id="x", name_id="1")
reg_w1 = registerOperand(prefix_id="w", name_id="1")
reg_d1 = registerOperand(prefix_id="d", name_id="1")
reg_q1 = registerOperand(prefix_id="q", name_id="1")
reg_v1 = registerOperand(prefix_id="v", name_id="1", lanes="2", shape="d")
regs = [reg_d1, reg_q1, reg_v1]
regs_gp = [reg_w1, reg_x1]
instr_form_r_1 = self.parser_AArch64.parse_line("stp q1, q3, [x12, #192]")
self.semantics_tx2.assign_src_dst(instr_form_r_1)
instr_form_r_2 = self.parser_AArch64.parse_line("fadd v2.2d, v1.2d, v0.2d")
self.semantics_tx2.assign_src_dst(instr_form_r_2)
instr_form_w_1 = self.parser_AArch64.parse_line("ldr d1, [x1, #:got_lo12:q2c]")
self.semantics_tx2.assign_src_dst(instr_form_w_1)
instr_form_non_w_1 = self.parser_AArch64.parse_line("ldr x1, [x1, #:got_lo12:q2c]")
self.semantics_tx2.assign_src_dst(instr_form_non_w_1)
instr_form_rw_1 = self.parser_AArch64.parse_line("fmul v1.2d, v1.2d, v0.2d")
self.semantics_tx2.assign_src_dst(instr_form_rw_1)
instr_form_rw_2 = self.parser_AArch64.parse_line("ldp q2, q4, [x1, #64]!")
self.semantics_tx2.assign_src_dst(instr_form_rw_2)
instr_form_rw_3 = self.parser_AArch64.parse_line("str x4, [x1], #64")
self.semantics_tx2.assign_src_dst(instr_form_rw_3)
instr_form_non_rw_1 = self.parser_AArch64.parse_line("adds x1, x11")
self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)
for reg in regs:
with self.subTest(reg=reg):
# self.assertTrue(dag.is_read(reg, instr_form_r_1))
self.assertTrue(dag.is_read(reg, instr_form_r_2))
self.assertTrue(dag.is_read(reg, instr_form_rw_1))
self.assertFalse(dag.is_read(reg, instr_form_rw_2))
self.assertFalse(dag.is_read(reg, instr_form_rw_3))
self.assertFalse(dag.is_read(reg, instr_form_w_1))
self.assertTrue(dag.is_written(reg, instr_form_w_1))
self.assertTrue(dag.is_written(reg, instr_form_rw_1))
self.assertFalse(dag.is_written(reg, instr_form_non_w_1))
self.assertFalse(dag.is_written(reg, instr_form_rw_2))
self.assertFalse(dag.is_written(reg, instr_form_rw_3))
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
for reg in regs_gp:
with self.subTest(reg=reg):
self.assertFalse(dag.is_read(reg, instr_form_r_1))
self.assertFalse(dag.is_read(reg, instr_form_r_2))
self.assertFalse(dag.is_read(reg, instr_form_rw_1))
self.assertTrue(dag.is_read(reg, instr_form_rw_2))
self.assertTrue(dag.is_read(reg, instr_form_rw_3))
self.assertTrue(dag.is_read(reg, instr_form_w_1))
self.assertFalse(dag.is_written(reg, instr_form_w_1))
self.assertFalse(dag.is_written(reg, instr_form_rw_1))
self.assertTrue(dag.is_written(reg, instr_form_non_w_1))
self.assertTrue(dag.is_written(reg, instr_form_rw_2))
self.assertTrue(dag.is_written(reg, instr_form_rw_3))
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
def test_invalid_MachineModel(self):
with self.assertRaises(ValueError):
MachineModel()
with self.assertRaises(ValueError):
MachineModel(arch="CSX", path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "csx.yml"))
with self.assertRaises(FileNotFoundError):
MachineModel(arch="THE_MACHINE")
with self.assertRaises(FileNotFoundError):
MachineModel(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "THE_MACHINE.yml"))
def test_MachineModel_getter(self):
sample_operands = [
memoryOperand(
offset_ID=None,
base_id=registerOperand(name_id="r12"),
index_id=registerOperand(name_id="rcx"),
scale_id=8,
def test_memdependency_x86(self):
dg = KernelDG(
self.kernel_x86_memdep,
self.parser_x86,
self.machine_model_csx,
self.semantics_csx,
)
]
self.assertIsNone(self.machine_model_csx.get_instruction("GETRESULT", sample_operands))
self.assertIsNone(self.machine_model_tx2.get_instruction("GETRESULT", sample_operands))
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {6, 8})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {10, 12})
with self.assertRaises(ValueError):
dg.get_dependent_instruction_forms()
# test dot creation
dg.export_graph(filepath="/dev/null")
self.assertEqual(self.machine_model_csx.get_arch(), "csx")
self.assertEqual(self.machine_model_tx2.get_arch(), "tx2")
def test_kernelDG_AArch64(self):
dg = KernelDG(
self.kernel_AArch64,
self.parser_AArch64,
self.machine_model_tx2,
self.semantics_tx2,
)
self.assertTrue(nx.algorithms.dag.is_directed_acyclic_graph(dg.dg))
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=3)), {7, 8})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=4)), {9, 10})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=5)), {6, 7, 8})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=6)), {9, 10})
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=7)), 13)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=8)), 14)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=9)), 16)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=10)), 17)
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=11)), {13, 14})
self.assertEqual(set(dg.get_dependent_instruction_forms(line_number=12)), {16, 17})
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=13)), 15)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=14)), 15)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=15))), 0)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=16)), 18)
self.assertEqual(next(dg.get_dependent_instruction_forms(line_number=17)), 18)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=18))), 0)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=19))), 0)
self.assertEqual(len(list(dg.get_dependent_instruction_forms(line_number=20))), 0)
with self.assertRaises(ValueError):
dg.get_dependent_instruction_forms()
# test dot creation
dg.export_graph(filepath="/dev/null")
self.assertEqual(self.machine_model_csx.get_ISA(), "x86")
self.assertEqual(self.machine_model_tx2.get_ISA(), "aarch64")
def test_kernelDG_SVE(self):
KernelDG(
self.kernel_aarch64_SVE,
self.parser_AArch64,
self.machine_model_a64fx,
self.semantics_a64fx,
)
# TODO check for correct analysis
ports_csx = ["0", "0DV", "1", "2", "2D", "3", "3D", "4", "5", "6", "7"]
data_ports_csx = ["2D", "3D"]
self.assertEqual(self.machine_model_csx.get_ports(), ports_csx)
self.assertEqual(self.machine_model_csx.get_data_ports(), data_ports_csx)
def test_hidden_load(self):
machine_model_hld = MachineModel(
path_to_yaml=self._find_file("hidden_load_machine_model.yml")
)
self.assertTrue(machine_model_hld.has_hidden_loads())
semantics_hld = ArchSemantics(machine_model_hld)
kernel_hld = self.parser_x86.parse_file(self.code_x86)
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)
kernel_hld_2 = self.parser_x86.parse_file(self.code_x86)[-3:]
kernel_hld_3 = self.parser_x86.parse_file(self.code_x86)[5:8]
self.assertFalse(self.machine_model_tx2.has_hidden_loads())
semantics_hld.add_semantics(kernel_hld)
semantics_hld.add_semantics(kernel_hld_2)
semantics_hld.add_semantics(kernel_hld_3)
self.assertEqual(MachineModel.get_isa_for_arch("CSX"), "x86")
self.assertEqual(MachineModel.get_isa_for_arch("tX2"), "aarch64")
with self.assertRaises(ValueError):
self.assertIsNone(MachineModel.get_isa_for_arch("THE_MACHINE"))
num_hidden_loads = len([x for x in kernel_hld if INSTR_flags.HIDDEN_LD in x.flags])
num_hidden_loads_2 = len([x for x in kernel_hld_2 if INSTR_flags.HIDDEN_LD in x.flags])
num_hidden_loads_3 = len([x for x in kernel_hld_3 if INSTR_flags.HIDDEN_LD in x.flags])
self.assertEqual(num_hidden_loads, 1)
self.assertEqual(num_hidden_loads_2, 0)
self.assertEqual(num_hidden_loads_3, 1)
def test_cyclic_dag(self):
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
dg.dg.add_edge(100, 101, latency=1.0)
dg.dg.add_edge(101, 102, latency=2.0)
dg.dg.add_edge(102, 100, latency=3.0)
with self.assertRaises(NotImplementedError):
dg.get_critical_path()
with self.assertRaises(NotImplementedError):
dg.get_loopcarried_dependencies()
def test_loop_carried_dependency_aarch64(self):
dg = KernelDG(
self.kernel_aarch64_memdep,
self.parser_AArch64,
self.machine_model_tx2,
self.semantics_tx2,
)
lc_deps = dg.get_loopcarried_dependencies()
self.assertEqual(len(lc_deps), 4)
# based on line 6
dep_path = "6-10-11-12-13-14"
self.assertEqual(lc_deps[dep_path]["latency"], 29.0)
self.assertEqual(
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
[(6, 4.0), (10, 6.0), (11, 6.0), (12, 6.0), (13, 6.0), (14, 1.0)],
)
dg = KernelDG(
self.kernel_aarch64_deps,
self.parser_AArch64,
self.machine_model_a64fx,
self.semantics_a64fx,
flag_dependencies=True,
)
lc_deps = dg.get_loopcarried_dependencies()
self.assertEqual(len(lc_deps), 2)
# based on line 4
dep_path = "4-5-6-9-10-11-12"
self.assertEqual(lc_deps[dep_path]["latency"], 7.0)
self.assertEqual(
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
[(4, 1.0), (5, 1.0), (6, 1.0), (9, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
)
dg = KernelDG(
self.kernel_aarch64_deps,
self.parser_AArch64,
self.machine_model_a64fx,
self.semantics_a64fx,
flag_dependencies=False,
)
lc_deps = dg.get_loopcarried_dependencies()
self.assertEqual(len(lc_deps), 1)
# based on line 4
dep_path = "4-5-10-11-12"
self.assertEqual(lc_deps[dep_path]["latency"], 5.0)
self.assertEqual(
[(iform.line_number, lat) for iform, lat in lc_deps[dep_path]["dependencies"]],
[(4, 1.0), (5, 1.0), (10, 1.0), (11, 1.0), (12, 1.0)],
)
def test_loop_carried_dependency_x86(self):
lcd_id = "8"
lcd_id2 = "5"
dg = KernelDG(self.kernel_x86, self.parser_x86, self.machine_model_csx, self.semantics_csx)
lc_deps = dg.get_loopcarried_dependencies()
# self.assertEqual(len(lc_deps), 2)
# ID 8
self.assertEqual(
lc_deps[lcd_id]["root"], dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"]
)
self.assertEqual(len(lc_deps[lcd_id]["dependencies"]), 1)
self.assertEqual(
lc_deps[lcd_id]["dependencies"][0][0],
dg.dg.nodes(data=True)[int(lcd_id)]["instruction_form"],
)
# w/ flag dependencies: ID 9 w/ len=2
# w/o flag dependencies: ID 5 w/ len=1
# TODO discuss
self.assertEqual(
lc_deps[lcd_id2]["root"],
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
)
self.assertEqual(len(lc_deps[lcd_id2]["dependencies"]), 1)
self.assertEqual(
lc_deps[lcd_id2]["dependencies"][0][0],
dg.dg.nodes(data=True)[int(lcd_id2)]["instruction_form"],
)
def test_timeout_during_loop_carried_dependency(self):
start_time = time.perf_counter()
KernelDG(
self.kernel_x86_long_LCD,
self.parser_x86,
self.machine_model_csx,
self.semantics_x86,
timeout=10,
)
end_time = time.perf_counter()
time_10 = end_time - start_time
start_time = time.perf_counter()
KernelDG(
self.kernel_x86_long_LCD,
self.parser_x86,
self.machine_model_csx,
self.semantics_x86,
timeout=2,
)
end_time = time.perf_counter()
time_2 = end_time - start_time
# self.assertTrue(time_10 > 10)
self.assertTrue(2 < time_2)
# self.assertTrue(time_2 < (time_10 - 7))
def test_is_read_is_written_x86(self):
# independent form HW model
dag = KernelDG(self.kernel_x86, self.parser_x86, None, None)
reg_rcx = RegisterOperand(name_id="rcx")
reg_ymm1 = RegisterOperand(name_id="ymm1")
instr_form_r_c = self.parser_x86.parse_line("vmovsd %xmm0, (%r15,%rcx,8)")
self.semantics_csx.assign_src_dst(instr_form_r_c)
instr_form_non_r_c = self.parser_x86.parse_line("movl %xmm0, (%r15,%rax,8)")
self.semantics_csx.assign_src_dst(instr_form_non_r_c)
instr_form_w_c = self.parser_x86.parse_line("movi $0x05ACA, %rcx")
self.semantics_csx.assign_src_dst(instr_form_w_c)
instr_form_rw_ymm_1 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm1, %ymm0, %ymm1")
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_1)
instr_form_rw_ymm_2 = self.parser_x86.parse_line("vinsertf128 $0x1, %xmm0, %ymm1, %ymm1")
self.semantics_csx.assign_src_dst(instr_form_rw_ymm_2)
instr_form_r_ymm = self.parser_x86.parse_line("vmovapd %ymm1, %ymm0")
self.semantics_csx.assign_src_dst(instr_form_r_ymm)
self.assertTrue(dag.is_read(reg_rcx, instr_form_r_c))
self.assertFalse(dag.is_read(reg_rcx, instr_form_non_r_c))
self.assertFalse(dag.is_read(reg_rcx, instr_form_w_c))
self.assertTrue(dag.is_written(reg_rcx, instr_form_w_c))
self.assertFalse(dag.is_written(reg_rcx, instr_form_r_c))
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_1))
self.assertTrue(dag.is_read(reg_ymm1, instr_form_rw_ymm_2))
self.assertTrue(dag.is_read(reg_ymm1, instr_form_r_ymm))
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_1))
self.assertTrue(dag.is_written(reg_ymm1, instr_form_rw_ymm_2))
self.assertFalse(dag.is_written(reg_ymm1, instr_form_r_ymm))
def test_is_read_is_written_AArch64(self):
# independent form HW model
dag = KernelDG(self.kernel_AArch64, self.parser_AArch64, None, None)
reg_x1 = RegisterOperand(prefix_id="x", name_id="1")
reg_w1 = RegisterOperand(prefix_id="w", name_id="1")
reg_d1 = RegisterOperand(prefix_id="d", name_id="1")
reg_q1 = RegisterOperand(prefix_id="q", name_id="1")
reg_v1 = RegisterOperand(prefix_id="v", name_id="1", lanes="2", shape="d")
regs = [reg_d1, reg_q1, reg_v1]
regs_gp = [reg_w1, reg_x1]
instr_form_r_1 = self.parser_AArch64.parse_line("stp q1, q3, [x12, #192]")
self.semantics_tx2.assign_src_dst(instr_form_r_1)
instr_form_r_2 = self.parser_AArch64.parse_line("fadd v2.2d, v1.2d, v0.2d")
self.semantics_tx2.assign_src_dst(instr_form_r_2)
instr_form_w_1 = self.parser_AArch64.parse_line("ldr d1, [x1, #:got_lo12:q2c]")
self.semantics_tx2.assign_src_dst(instr_form_w_1)
instr_form_non_w_1 = self.parser_AArch64.parse_line("ldr x1, [x1, #:got_lo12:q2c]")
self.semantics_tx2.assign_src_dst(instr_form_non_w_1)
instr_form_rw_1 = self.parser_AArch64.parse_line("fmul v1.2d, v1.2d, v0.2d")
self.semantics_tx2.assign_src_dst(instr_form_rw_1)
instr_form_rw_2 = self.parser_AArch64.parse_line("ldp q2, q4, [x1, #64]!")
self.semantics_tx2.assign_src_dst(instr_form_rw_2)
instr_form_rw_3 = self.parser_AArch64.parse_line("str x4, [x1], #64")
self.semantics_tx2.assign_src_dst(instr_form_rw_3)
instr_form_non_rw_1 = self.parser_AArch64.parse_line("adds x1, x11")
self.semantics_tx2.assign_src_dst(instr_form_non_rw_1)
for reg in regs:
with self.subTest(reg=reg):
self.assertTrue(dag.is_read(reg, instr_form_r_1))
self.assertTrue(dag.is_read(reg, instr_form_r_2))
self.assertTrue(dag.is_read(reg, instr_form_rw_1))
self.assertFalse(dag.is_read(reg, instr_form_rw_2))
self.assertFalse(dag.is_read(reg, instr_form_rw_3))
self.assertFalse(dag.is_read(reg, instr_form_w_1))
self.assertTrue(dag.is_written(reg, instr_form_w_1))
self.assertTrue(dag.is_written(reg, instr_form_rw_1))
self.assertFalse(dag.is_written(reg, instr_form_non_w_1))
self.assertFalse(dag.is_written(reg, instr_form_rw_2))
self.assertFalse(dag.is_written(reg, instr_form_rw_3))
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
self.assertFalse(dag.is_written(reg, instr_form_non_rw_1))
for reg in regs_gp:
with self.subTest(reg=reg):
self.assertFalse(dag.is_read(reg, instr_form_r_1))
self.assertFalse(dag.is_read(reg, instr_form_r_2))
self.assertFalse(dag.is_read(reg, instr_form_rw_1))
self.assertTrue(dag.is_read(reg, instr_form_rw_2))
self.assertTrue(dag.is_read(reg, instr_form_rw_3))
self.assertTrue(dag.is_read(reg, instr_form_w_1))
self.assertFalse(dag.is_written(reg, instr_form_w_1))
self.assertFalse(dag.is_written(reg, instr_form_rw_1))
self.assertTrue(dag.is_written(reg, instr_form_non_w_1))
self.assertTrue(dag.is_written(reg, instr_form_rw_2))
self.assertTrue(dag.is_written(reg, instr_form_rw_3))
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
self.assertTrue(dag.is_written(reg, instr_form_non_rw_1))
def test_invalid_MachineModel(self):
with self.assertRaises(ValueError):
MachineModel()
with self.assertRaises(ValueError):
MachineModel(arch="CSX", path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "csx.yml"))
with self.assertRaises(FileNotFoundError):
MachineModel(arch="THE_MACHINE")
with self.assertRaises(FileNotFoundError):
MachineModel(path_to_yaml=os.path.join(self.MODULE_DATA_DIR, "THE_MACHINE.yml"))
def test_MachineModel_getter(self):
sample_operands = [
MemoryOperand(
offset_ID=None,
base_id=RegisterOperand(name_id="r12"),
index_id=RegisterOperand(name_id="rcx"),
scale_id=8,
)
]
self.assertIsNone(self.machine_model_csx.get_instruction("GETRESULT", sample_operands))
self.assertIsNone(self.machine_model_tx2.get_instruction("GETRESULT", sample_operands))
self.assertEqual(self.machine_model_csx.get_arch(), "csx")
self.assertEqual(self.machine_model_tx2.get_arch(), "tx2")
self.assertEqual(self.machine_model_csx.get_ISA(), "x86")
self.assertEqual(self.machine_model_tx2.get_ISA(), "aarch64")
ports_csx = ["0", "0DV", "1", "2", "2D", "3", "3D", "4", "5", "6", "7"]
data_ports_csx = ["2D", "3D"]
self.assertEqual(self.machine_model_csx.get_ports(), ports_csx)
self.assertEqual(self.machine_model_csx.get_data_ports(), data_ports_csx)
self.assertFalse(self.machine_model_tx2.has_hidden_loads())
self.assertEqual(MachineModel.get_isa_for_arch("CSX"), "x86")
self.assertEqual(MachineModel.get_isa_for_arch("tX2"), "aarch64")
with self.assertRaises(ValueError):
self.assertIsNone(MachineModel.get_isa_for_arch("THE_MACHINE"))
"""
##################
# Helper functions