Skip to content

Commit b7da02c

Browse files
authored
[hec-assembler]: Optimize linking at xinst/cinst/minst levels (#126)
* Linking up to SPAD boundary * Adding unit tests * Adding integration tests
1 parent cbe7956 commit b7da02c

File tree

79 files changed

+8068
-627
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

79 files changed

+8068
-627
lines changed

assembler_tools/hec-assembler-tools/assembler/instructions/cinst/csyncm.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,6 @@ class Instruction(CInstruction):
1717
https://github.com/IntelLabs/hec-assembler-tools/blob/master/docsrc/inst_spec/cinst/cinst_csyncm.md
1818
"""
1919

20-
@classmethod
21-
def get_throughput(cls) -> int:
22-
return cls._OP_DEFAULT_THROUGHPUT
23-
2420
@classmethod
2521
def _get_op_name_asm(cls) -> str:
2622
"""

assembler_tools/hec-assembler-tools/assembler/instructions/instruction.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,15 @@ class BaseInstruction(CycleTracker):
117117

118118
# Class methods and properties
119119
# ----------------------------
120+
121+
@classmethod
122+
def get_latency(cls) -> int:
123+
return cls._OP_DEFAULT_LATENCY
124+
125+
@classmethod
126+
def get_throughput(cls) -> int:
127+
return cls._OP_DEFAULT_THROUGHPUT
128+
120129
@classmethod
121130
def isa_spec_as_dict(cls) -> dict:
122131
"""Returns attributes as dictionary."""

assembler_tools/hec-assembler-tools/he_link.py

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
from linker.kern_trace.trace_info import TraceInfo
5151
from linker.linker_run_config import LinkerRunConfig
5252
from linker.loader import Loader
53-
from linker.steps import program_linker
53+
from linker.steps.program_linker import LinkedProgram
5454
from linker.steps.variable_discovery import check_unused_variables, scan_variables
5555

5656

@@ -100,6 +100,8 @@ def main(run_config: LinkerRunConfig, verbose_stream=None):
100100
print("", file=verbose_stream)
101101
print("Interpreting variable meta information...", file=verbose_stream)
102102

103+
p_linker = LinkedProgram(keep_spad_boundary=run_config.keep_spad_boundary, keep_hbm_boundary=run_config.keep_hbm_boundary)
104+
103105
# Process kernel DInstructions when using trace file
104106
program_dinstrs = []
105107
if run_config.using_trace_file:
@@ -111,7 +113,7 @@ def main(run_config: LinkerRunConfig, verbose_stream=None):
111113
remap_vars(kernels_info, dinstrs_per_kernel, kernel_ops, verbose_stream)
112114

113115
# Concatenate all mem info objects into one
114-
program_dinstrs = program_linker.LinkedProgram.join_dinst_kernels(dinstrs_per_kernel)
116+
program_dinstrs = p_linker.join_n_prune_dinst_kernels(dinstrs_per_kernel)
115117

116118
# Write new program memory model to an output file
117119
if program_info.mem is None:
@@ -121,19 +123,22 @@ def main(run_config: LinkerRunConfig, verbose_stream=None):
121123
# Initialize memory model
122124
mem_model = initialize_memory_model(run_config, program_dinstrs, verbose_stream)
123125

126+
# Preload xinst and pre-process intermediate variables for future cinst pruning
127+
p_linker.preload_kernels(kernels_info)
128+
124129
# Discover variables
125130
print(" Finding all program variables...", file=verbose_stream)
126131
print(" Scanning", file=verbose_stream)
127132

128-
scan_variables(kernels_info=kernels_info, mem_model=mem_model, verbose_stream=verbose_stream)
133+
scan_variables(p_linker, kernels_info, mem_model, verbose_stream)
129134

130135
check_unused_variables(mem_model)
131136

132137
print(f" Variables found: {len(mem_model.variables)}", file=verbose_stream)
133138
print("Linking started", file=verbose_stream)
134139

135140
# Link kernels and generate outputs
136-
program_linker.LinkedProgram.link_kernels_to_files(kernels_info, program_info, mem_model, verbose_stream=verbose_stream)
141+
p_linker.link_kernels_to_files(kernels_info, program_info, mem_model, verbose_stream=verbose_stream)
137142

138143
# Flush cached kernels
139144
Loader.flush_cache()
@@ -253,7 +258,25 @@ def parse_args():
253258
"--no_hbm",
254259
dest="has_hbm",
255260
action="store_false",
256-
help="If set, this flag tells he_prep there is no HBM in the target chip.",
261+
help="If set, this flag tells he_link there is no HBM in the target chip.",
262+
)
263+
parser.add_argument(
264+
"--keep_spad_boundary",
265+
action="store_true",
266+
help=(
267+
"If used along with '--use_trace_file', this flag tells he_link to keep a data boundary "
268+
"among kernels in the final cinst output. This can be useful for debugging purposes. "
269+
"This flag is ignored if '--keep_hbm_boundary' is set."
270+
),
271+
)
272+
parser.add_argument(
273+
"--keep_hbm_boundary",
274+
action="store_true",
275+
help=(
276+
"If used along with '--use_trace_file', this flag tells he_link to keep a data boundary "
277+
"among kernels in the final minst output. This can be useful for debugging purposes. "
278+
"This flag will override the '--keep_spad_boundary' flag."
279+
),
257280
)
258281
parser.add_argument(
259282
"--suppress_comments",
@@ -282,6 +305,11 @@ def parse_args():
282305
if p_args.input_dir == "" and p_args.trace_file:
283306
p_args.input_dir = os.path.dirname(p_args.trace_file)
284307

308+
# If no trace file is used boundaries should be kept
309+
p_args.keep_hbm_boundary = True if not p_args.using_trace_file else p_args.keep_hbm_boundary
310+
# If HBM boundary is kept, SPAD boundary is kept as a consequence
311+
p_args.keep_spad_boundary = True if p_args.keep_hbm_boundary else p_args.keep_spad_boundary
312+
285313
# Enforce only if use_trace_file is not set
286314
if not p_args.using_trace_file:
287315
if p_args.input_mem_file == "":

assembler_tools/hec-assembler-tools/linker/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,14 @@ def add_variable(self, var_name: str):
214214
# with predefined HBM address
215215
if var_name in self.__mem_info_fixed_addr_vars:
216216
var_info.uses = float("inf")
217+
else:
218+
var_info.uses = 0
217219
self.hbm.force_allocate(var_info, self.__mem_info_vars[var_name].hbm_address)
220+
else:
221+
# Variables not explicitly marked in mem file are allocated on demand
222+
var_info.hbm_address = -1
218223
self.variables[var_name] = var_info
224+
219225
var_info.uses += 1
220226

221227
def use_variable(self, var_name: str, kernel: int) -> int:
@@ -234,7 +240,6 @@ def use_variable(self, var_name: str, kernel: int) -> int:
234240

235241
var_info.uses -= 1 # Mark the usage
236242
var_info.last_kernel_used = kernel
237-
238243
if var_info.hbm_address < 0:
239244
# Find HBM address for variable
240245
self.hbm.allocate(var_info)

assembler_tools/hec-assembler-tools/linker/he_link_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ def update_input_prefixes(kernel_ops, run_config):
111111
def remap_vars(kernels_info: list[KernelInfo], kernels_dinstrs, kernel_ops, verbose_stream):
112112
"""
113113
@brief Process kernel DInstructions to remap variables based on kernel operations
114-
and update KernelInfo with remap_dict.
114+
and update KernelInfo with hbm_remap_dict.
115115
116116
@param kernels_info List of input KernelInfo.
117117
@param kernels_dinstrs List of kernel DInstructions.
@@ -131,7 +131,7 @@ def remap_vars(kernels_info: list[KernelInfo], kernels_dinstrs, kernel_ops, verb
131131

132132
# Remap dintrs' variables in kernel_dinstrs and return a mapping dict
133133
var_map = remap_dinstrs_vars(kernel_dinstrs, kernel_op)
134-
kernel_info.remap_dict = var_map
134+
kernel_info.hbm_remap_dict = var_map
135135

136136

137137
def initialize_memory_model(run_config, kernel_dinstrs=None, verbose_stream=None):

assembler_tools/hec-assembler-tools/linker/instructions/cinst/bload.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,38 @@ def __init__(self, tokens: list, comment: str = ""):
5050
@throws ValueError If the number of tokens is invalid or the instruction name is incorrect.
5151
"""
5252
super().__init__(tokens, comment=comment)
53+
self._var_name = tokens[3]
54+
# set spad_address to '0' if tokens[3] is a variable name
55+
if not tokens[3].isdigit():
56+
self.tokens[3] = "0" # Should be set to SPAD address to write back.
5357

5458
@property
55-
def source(self) -> str:
59+
def var_name(self) -> str:
5660
"""
57-
@brief Name of the source.
58-
This is a Variable name when loaded. Should be set to HBM address to write back.
61+
@brief Gets the name of the variable.
62+
63+
This is a Variable name when loaded with no_hbm.
64+
65+
@return The name of the variable.
66+
"""
67+
return self._var_name
68+
69+
@var_name.setter
70+
def var_name(self, value: str):
71+
"""
72+
@brief Sets the name of the variable.
73+
74+
@param value The name of the variable to set.
75+
"""
76+
self._var_name = value
77+
78+
@property
79+
def spad_address(self) -> int:
80+
"""
81+
@brief Source SPAD address.
5982
"""
60-
return self.tokens[3]
83+
return int(self.tokens[3])
6184

62-
@source.setter
63-
def source(self, value: str):
64-
self.tokens[3] = value
85+
@spad_address.setter
86+
def spad_address(self, value: int):
87+
self.tokens[3] = str(value)

assembler_tools/hec-assembler-tools/linker/instructions/cinst/bones.py

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,35 @@ def __init__(self, tokens: list, comment: str = ""):
5050
@throws ValueError If the number of tokens is invalid or the instruction name is incorrect.
5151
"""
5252
super().__init__(tokens, comment=comment)
53+
self._var_name = tokens[2]
54+
if not tokens[2].isdigit():
55+
self.tokens[2] = "0" # Should be set to SPAD address to write back.
5356

5457
@property
55-
def source(self) -> str:
58+
def var_name(self) -> str:
5659
"""
57-
@brief Name of the source.
58-
This is a Variable name when loaded. Should be set to HBM address to write back.
60+
@brief Gets the name of the variable.
61+
62+
This is a Variable name when loaded and there is no HBM.
63+
"""
64+
return self._var_name
65+
66+
@var_name.setter
67+
def var_name(self, value: str):
68+
"""
69+
@brief Sets the name of the variable.
70+
71+
@param value The name of the variable to set.
72+
"""
73+
self._var_name = value
74+
75+
@property
76+
def spad_address(self) -> int:
77+
"""
78+
@brief Source SPAD address.
5979
"""
60-
return self.tokens[2]
80+
return int(self.tokens[2])
6181

62-
@source.setter
63-
def source(self, value: str):
64-
self.tokens[2] = value
82+
@spad_address.setter
83+
def spad_address(self, value: int):
84+
self.tokens[2] = str(value)

assembler_tools/hec-assembler-tools/linker/instructions/cinst/cinstruction.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,23 @@ def to_line(self) -> str:
6161
str: The string representation of the instruction, excluding the first token.
6262
"""
6363
return ", ".join(self.tokens[1:])
64+
65+
@property
66+
def idx(self) -> int:
67+
"""
68+
@brief Gets the instruction index.
69+
70+
This is the line number in the MInstruction file.
71+
72+
@return The instruction index.
73+
"""
74+
return int(self.tokens[0])
75+
76+
@idx.setter
77+
def idx(self, value: int):
78+
"""
79+
@brief Sets the instruction index.
80+
81+
@param value The instruction index to set.
82+
"""
83+
self.tokens[0] = str(value)

assembler_tools/hec-assembler-tools/linker/instructions/cinst/cload.py

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,48 @@ def __init__(self, tokens: list, comment: str = ""):
5050
@throws ValueError If the number of tokens is invalid or the instruction name is incorrect.
5151
"""
5252
super().__init__(tokens, comment=comment)
53+
if not tokens[3].isdigit():
54+
self._var_name = tokens[3]
55+
self.tokens[3] = "-1" # Should be set to SPAD address to write back.
56+
else:
57+
self._var_name = ""
5358

5459
@property
55-
def source(self) -> str:
60+
def var_name(self) -> str:
5661
"""
57-
@brief Name of the source.
58-
This is a Variable name when loaded. Should be set to HBM address to write back.
62+
@brief Gets the name of the original source variable.
63+
64+
This is a Variable name when there is no HBM.
65+
"""
66+
return self._var_name
67+
68+
@var_name.setter
69+
def var_name(self, value: str):
70+
self._var_name = value
71+
72+
@property
73+
def spad_address(self) -> int:
74+
"""
75+
@brief Source SPAD address.
76+
"""
77+
return int(self.tokens[3])
78+
79+
@spad_address.setter
80+
def spad_address(self, value: int):
81+
self.tokens[3] = str(value)
82+
83+
@property
84+
def register(self) -> str:
85+
"""
86+
@brief Gets the name of the destination register.
5987
"""
60-
return self.tokens[3]
88+
return self.tokens[2]
6189

62-
@source.setter
63-
def source(self, value: str):
64-
self.tokens[3] = value
90+
@register.setter
91+
def register(self, value: str):
92+
"""
93+
@brief Sets the name of the destination register.
94+
95+
@param value The name of the register to set.
96+
"""
97+
self.tokens[2] = value

assembler_tools/hec-assembler-tools/linker/instructions/cinst/cstore.py

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,22 +50,43 @@ def __init__(self, tokens: list, comment: str = ""):
5050
@throws ValueError If the number of tokens is invalid or the instruction name is incorrect.
5151
"""
5252
super().__init__(tokens, comment=comment)
53+
self._var_name = tokens[2]
54+
if not tokens[2].isdigit():
55+
self.tokens[2] = "0" # Should be set to SPAD address to write back.
5356

5457
@property
55-
def dest(self) -> str:
58+
def var_name(self) -> str:
5659
"""
57-
@brief Name of the destination.
58-
This is a Variable name when loaded. Should be set to HBM address to write back.
60+
@brief Gets the name of the variable.
5961
60-
@return The destination variable name or address.
62+
@return The name of the variable.
6163
"""
62-
return self.tokens[2]
64+
return self._var_name
6365

64-
@dest.setter
65-
def dest(self, value: str):
66+
@var_name.setter
67+
def var_name(self, value: str):
68+
"""
69+
@brief Sets the name of the variable.
70+
71+
@param value The name of the variable to set.
72+
"""
73+
self._var_name = value
74+
75+
@property
76+
def spad_address(self) -> int:
77+
"""
78+
@brief SPAD address of destination.
79+
Should be set to HBM address to write back.
80+
81+
@return The destination variable address.
82+
"""
83+
return int(self.tokens[2])
84+
85+
@spad_address.setter
86+
def spad_address(self, value: int):
6687
"""
6788
@brief Sets the destination of the instruction.
6889
6990
@param value The new destination value to set.
7091
"""
71-
self.tokens[2] = value
92+
self.tokens[2] = str(value)

0 commit comments

Comments
 (0)