From e0cd588df862bab2f78342f7b33d7fcd5d6f67ce Mon Sep 17 00:00:00 2001 From: Marius Meyer Date: Fri, 8 May 2020 08:51:22 +0200 Subject: [PATCH 1/8] Add code generator --- scripts/code_generator/README.md | 81 ++++++++++++ scripts/code_generator/generator.py | 197 ++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 scripts/code_generator/README.md create mode 100755 scripts/code_generator/generator.py diff --git a/scripts/code_generator/README.md b/scripts/code_generator/README.md new file mode 100644 index 00000000..0ec2e64c --- /dev/null +++ b/scripts/code_generator/README.md @@ -0,0 +1,81 @@ +# Code generation and Replication Tool + +This is a small and highly extendable Python script for Code generation. +The main application area is the generation of OpenCL code, but the generator works independently of the used programming language. +It can be seen as an extension of the usually used preprocessors to adapt the code before compilation. +With this code it is also possible to replicate code sections and do more complex modifications while keeping the code readable. +This is done using inline scripting in commented out code. +A generator code line always starts with `PY_CODE_GEN`. + +## Usage + +The generator takes arbitrary code files as input and only applies changes when specific pragmas are found. +The pragmas have the following syntax: + + PY_CODE_GEN [block_start|block_end STATEMENT|STATEMENT] + +Where `STATEMENT`is a python statement. +It is possible to execute simple statements, but also to define nested blocks, which can be changed or replicated. +Example for the definition of a global variable: + + PY_CODE_GEN replicate=4 + +This variable can then be used within the next pragmas to further modify the code. +E.g. the defined variable can be used to modifiy a code block: + + // PY_CODE_GEN block_start + int i = $R; + printf("i should be $R"); + // PY_CODE_GEN block_end CODE.replace("$R", str(replicate)) + +`CODE` is a global variable containing the code within the recent block. It can be modified like every other Python string. +The result of the given Python statement will then be printed in the modified file. + +This is functionality, which would also be possible using the standard preprocessor. +A case, where this script becomes handy is code replication. +This can easily be doe using list comprehension. +As an example the dynamic construction of a switch statement: + + switch(i) { + // PY_CODE_GEN block_start + case $i$: return $i$; break; + // PY_CODE_GEN block_end [replace(replace_dict=locals()) for i in range(replicate)] + } + +would result in: + + switch(i) { + case 0: return 0; break; + case 1: return 1; break; + case 2: return 2; break; + case 3: return 3; break; + } + +## Built-In Functions + +The generator can easily be extended by including additional file with the `use_file(FILENAME)` command. + + PY_CODE_GEN use_file(helpers.py) + +This will read the file and make all functions and global variables available within following blocks. + +`if_cond(CONDITION, IF, ELSE)` can be used to easily return different values depending on the evaluation result of CONDITION: + + PY_CODE_GEN i=2 + PY_CODE_GEN block_start + PY_CODE_GEN block_end if_cond(i < 1, "Hello", "World") + +will return 'World'. + +`replace()` makes it easier to replace global variables within the code: + + // PY_CODE_GEN i=2 + // PY_CODE_GEN block_start + int var = $i$ + // PY_CODE_GEN block_end replace() + +will generate the code `int var = 2`. + +It is easily possible to add other helper functions and extend the functionality of the generator using the `use_file` method. + + diff --git a/scripts/code_generator/generator.py b/scripts/code_generator/generator.py new file mode 100755 index 00000000..8fc52e7e --- /dev/null +++ b/scripts/code_generator/generator.py @@ -0,0 +1,197 @@ +#!/usr/bin/env python3 +# +# Copyright (c) 2019 Marius Meyer +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +## + +import argparse +import sys +import logging + + +comment_symbol = "//" +pycodegen_cmd = "PY_CODE_GEN" +pragma_cmd = PRAGMA +" "+ pycodegen_cmd + +parser = argparse.ArgumentParser(description='Preprocessor for code replication and advanced code modification.') +parser.add_argument('file', metavar='CODE_FILE', type=str, + help='Path to the file that is used as input') +parser.add_argument("-o", dest="output_file", default=None, help="Path to the output file. If not given, output will printed to stdout.") +parser.add_argument("--comment", dest="comment_symbol", default=comment_symbol, help="Symbols that are used to comment out lines in the target language. Default='%s'" % comment_symbol) +parser.add_argument("-p", dest="params", default=[], action="append", help="Python statement that is parsed before modifying the files. Can be used to define global variables.") + +CODE = "" + +def replace(input_code=None,replace_dict=None, frame="$"): + """ + Replace variables in given code. + Helper function to simplify code replacement + """ + if input_code is None: + input_code = CODE + if replace_dict is None: + replace_dict = {**locals(), **globals()} + mod_code = input_code + for k, v in replace_dict.items(): + mod_code = mod_code.replace(frame + str(k) + frame, str(v)) + return mod_code + + +def if_cond(condition, if_return, else_return): + """ + Evaluate a condition to select a return value + + @param condition Statement that evaluates to a boolean + @param if_return Value that is returned if condition is true + @param else_return Value that is returned if condition is false + + @return if_return or else_return, depending on condition + """ + if condition: + return if_return + else: + return else_return + + +def use_file(file_name): + """ + Read and execute a python script + + This function adds the content of a given file to the current Python environment. + It can be used to define global variables or functions in a separate file, which can then be called + within the pragmas to generate code + + @param file_name Path to the file relative to the current working directory + + @returns None + """ + logging.debug("Try parsing file: %s" % file_name) + try: + with open(file_name) as f: + exec(f.read(), globals()) + except Exception as e: + logging.error("Error while parsing file %s" % file_name) + logging.error(e) + print("Error while parsing external file. See logs for more information.",file=sys.stderr) + exit(1) + + +def modify_block(code_block, cmd_str, out): + global CODE + CODE = code_block + if cmd_str == "": + cmd_str = "None" + try: + mod_code = eval(cmd_str, {**globals(), **locals()}) + except Exception as e: + logging.error("Block: %s \n %s" % (code_block, e)) + logging.error("Global variables: %s" % globals()) + print( "Block: %s \n %s" % (code_block, e),file=sys.stderr) + exit(1) + if type(mod_code) is list: + mod_code = "".join(mod_code) + elif mod_code is None: + mod_code = "" + elif type(mod_code) is not str: + logging.warning("%s is not a string. Automatic convert to string!" % mod_code) + mod_code = str(mod_code) + logging.debug("Start parsing of modified sub-block") + parse_string(mod_code, out) + logging.debug("Finished parsing of modified sub-block") + + +def parse_string(code_string, out): + nested_level = 0 + current_block = "" + for line_number, line in enumerate(code_string.split('\n')): + line += "\n" + sline = line.strip() + if sline.startswith(pragma_cmd) and nested_level == 0: + sline = sline.replace(pragma_cmd,"") + if 'block_start' in sline: + nested_level += 1 + elif 'block_end' in sline: + logging.error("Block end before start! Invalid syntax!") + print("Block end before start! Invalid syntax!", file=sys.stderr) + exit(1) + else: + cmd_str = sline.strip() + try: + exec(cmd_str, globals()) + except Exception as e: + logging.error("Block: %s \n %s" % (current_block, e)) + logging.error("Global variables: %s" % globals()) + print( "Block: %s \n %s" % (current_block, e),file=sys.stderr) + exit(1) + elif sline.startswith(pragma_cmd): + sline = sline.replace(pragma_cmd,"") + if 'block_start' in sline: + nested_level += 1 + current_block += line + elif 'block_end' in sline: + nested_level -= 1 + if nested_level == 0: + cmd_str = sline.replace('block_end', "").strip() + modify_block(current_block, cmd_str, out) + current_block = "" + else: + current_block += line + else: + current_block += line + elif nested_level > 0: + current_block += line + else: + print(line, end='', file=out) + + +def parse_file(file_name, out): + """ + Opens a single source code file and applies the changes to it. + + The function will output the modified source code into the given output stream. + + @param file_name The psth to the source code file relative to the current working directory + @param out Output stream that is used to output the modified source code + """ + try: + with open(file_name) as f: + parse_string(f.read(), out) + except Exception as e: + logging.error("Error when opening and parsing file %s: %s" % (file_name, e)) + print("Error occurred when parsing file. See logs for more details.",file=sys.stderr) + + + + +if __name__=="__main__": + args = parser.parse_args() + log_file_name = args.file + ".genlog" + logging.basicConfig(filename=log_file_name, filemode='w', level=logging.DEBUG) + output = sys.stdout + for p in args.params: + logging.debug("Parse statement: %s" % p) + exec(p, globals()) + if args.output_file: + logging.debug("Use output file: %s" % args.output_file) + output = open(args.output_file, 'w') + pragma_cmd = args.pragma_cmd + logging.debug("Use pragma command: %s", pragma_cmd) + logging.debug("Start parsing file: %s" % args.file) + parse_file(args.file, output) From cc8f655502201b664129ba79bbe265a1186521f9 Mon Sep 17 00:00:00 2001 From: Marius Meyer Date: Fri, 8 May 2020 19:21:50 +0200 Subject: [PATCH 2/8] Update the code generator --- scripts/code_generator/README.md | 98 ++++++++++++------ scripts/code_generator/generator.py | 148 +++++++++++++--------------- 2 files changed, 138 insertions(+), 108 deletions(-) diff --git a/scripts/code_generator/README.md b/scripts/code_generator/README.md index 0ec2e64c..1c6397ce 100644 --- a/scripts/code_generator/README.md +++ b/scripts/code_generator/README.md @@ -1,21 +1,63 @@ -# Code generation and Replication Tool +# Code Generation and Replication Tool This is a small and highly extendable Python script for Code generation. The main application area is the generation of OpenCL code, but the generator works independently of the used programming language. It can be seen as an extension of the usually used preprocessors to adapt the code before compilation. With this code it is also possible to replicate code sections and do more complex modifications while keeping the code readable. -This is done using inline scripting in commented out code. +This is done using inline scripting in code comments. A generator code line always starts with `PY_CODE_GEN`. -## Usage +## Execution -The generator takes arbitrary code files as input and only applies changes when specific pragmas are found. -The pragmas have the following syntax: +The script needs Python3 to run. +It will be used by the CMake build system to generate source code and settings for some of the benchmarks. +A short summary of the usage of the script that can also be printed by running `./generator.py -h`: - PY_CODE_GEN [block_start|block_end STATEMENT|STATEMENT] + usage: generator.py [-h] [-o OUTPUT_FILE] [--comment COMMENT_SYMBOL] + [--comment-ml-start COMMENT_SYMBOL_ML_START] + [--comment-ml-end COMMENT_SYMBOL_ML_END] [-p PARAMS] + CODE_FILE -Where `STATEMENT`is a python statement. -It is possible to execute simple statements, but also to define nested blocks, which can be changed or replicated. + Preprocessor for code replication and advanced code modification. + + positional arguments: + CODE_FILE Path to the file that is used as input + + optional arguments: + -h, --help show this help message and exit + -o OUTPUT_FILE Path to the output file. If not given, output will + printed to stdout. + --comment COMMENT_SYMBOL + Symbols that are used to comment out lines in the + target language. Default='//' + --comment-ml-start COMMENT_SYMBOL_ML_START + Symbols that are used to start a multi line comment in + the target language. Default='/*' + --comment-ml-end COMMENT_SYMBOL_ML_END + Symbols that are used to end a multi line comment in + the target language. Default='*/' + -p PARAMS Python statement that is parsed before modifying the + files. Can be used to define global variables. + + + +## Code Examples + +The generator takes arbitrary code files as input and only applies changes when specific comment patterns are found. +The code insertions have the following syntax: + + // PY_CODE_GEN [block_start STATEMENT|block_end|STATEMENT] + +it is also possible to write multiple lines of code: + + /* PY_CODE_GEN + STATEMENT1 + STATEMENT2 + ... + */ + +Where `STATEMENT`is an arbitrary python statement. +The input file will be parsed from the beginning to the end and generation statements will be executed immediately. Example for the definition of a global variable: PY_CODE_GEN replicate=4 @@ -23,12 +65,13 @@ Example for the definition of a global variable: This variable can then be used within the next pragmas to further modify the code. E.g. the defined variable can be used to modifiy a code block: - // PY_CODE_GEN block_start + // PY_CODE_GEN block_start CODE.replace("$R", str(replicate)) int i = $R; printf("i should be $R"); - // PY_CODE_GEN block_end CODE.replace("$R", str(replicate)) + // PY_CODE_GEN block_end `CODE` is a global variable containing the code within the recent block. It can be modified like every other Python string. +In most cases it is recommended to use the build-in function `replace()` for replacing variables, but it might be used for more advanced code modifications. The result of the given Python statement will then be printed in the modified file. This is functionality, which would also be possible using the standard preprocessor. @@ -37,20 +80,24 @@ This can easily be doe using list comprehension. As an example the dynamic construction of a switch statement: switch(i) { - // PY_CODE_GEN block_start - case $i$: return $i$; break; - // PY_CODE_GEN block_end [replace(replace_dict=locals()) for i in range(replicate)] + // PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(replicate)] + case /*PY_CODE_GEN i*/: return /*PY_CODE_GEN i+1*/; break; + // PY_CODE_GEN block_end } would result in: switch(i) { - case 0: return 0; break; - case 1: return 1; break; - case 2: return 2; break; - case 3: return 3; break; + case 0: return 1; break; + case 1: return 2; break; + case 2: return 3; break; + case 3: return 4; break; } +Note, that the variables that have to be replaced are written in inline comments `/*PY_CODE_GEN i*/`. +The given statement will be evaluated and the comment will be replaced by the result. +Thus, it is also possible to call functions or do arithmetic. + ## Built-In Functions The generator can easily be extended by including additional file with the `use_file(FILENAME)` command. @@ -59,23 +106,14 @@ The generator can easily be extended by including additional file with the `use_ This will read the file and make all functions and global variables available within following blocks. -`if_cond(CONDITION, IF, ELSE)` can be used to easily return different values depending on the evaluation result of CONDITION: - - PY_CODE_GEN i=2 - PY_CODE_GEN block_start - PY_CODE_GEN block_end if_cond(i < 1, "Hello", "World") - -will return 'World'. - `replace()` makes it easier to replace global variables within the code: // PY_CODE_GEN i=2 // PY_CODE_GEN block_start - int var = $i$ - // PY_CODE_GEN block_end replace() + int var = /*PY_CODE_GEN test*/ + // PY_CODE_GEN block_end replace(local_variables={"test": 2}) will generate the code `int var = 2`. -It is easily possible to add other helper functions and extend the functionality of the generator using the `use_file` method. - - +It is easily possible to add other helper functions and extend the functionality of the generator using the `use_file` method +or by declaring functions in multi line comments. diff --git a/scripts/code_generator/generator.py b/scripts/code_generator/generator.py index 8fc52e7e..374b24d4 100755 --- a/scripts/code_generator/generator.py +++ b/scripts/code_generator/generator.py @@ -22,54 +22,29 @@ ## import argparse +import itertools import sys import logging +import re comment_symbol = "//" +ml_comment_symbol_start = "/*" +ml_comment_symbol_end = "*/" pycodegen_cmd = "PY_CODE_GEN" -pragma_cmd = PRAGMA +" "+ pycodegen_cmd +pragma_cmd = comment_symbol +"\\s*"+ pycodegen_cmd parser = argparse.ArgumentParser(description='Preprocessor for code replication and advanced code modification.') parser.add_argument('file', metavar='CODE_FILE', type=str, help='Path to the file that is used as input') parser.add_argument("-o", dest="output_file", default=None, help="Path to the output file. If not given, output will printed to stdout.") parser.add_argument("--comment", dest="comment_symbol", default=comment_symbol, help="Symbols that are used to comment out lines in the target language. Default='%s'" % comment_symbol) +parser.add_argument("--comment-ml-start", dest="comment_symbol_ml_start", default=ml_comment_symbol_start, help="Symbols that are used to start a multi line comment in the target language. Default='%s'" % ml_comment_symbol_start) +parser.add_argument("--comment-ml-end", dest="comment_symbol_ml_end", default=ml_comment_symbol_end, help="Symbols that are used to end a multi line comment in the target language. Default='%s'" % ml_comment_symbol_end) parser.add_argument("-p", dest="params", default=[], action="append", help="Python statement that is parsed before modifying the files. Can be used to define global variables.") CODE = "" -def replace(input_code=None,replace_dict=None, frame="$"): - """ - Replace variables in given code. - Helper function to simplify code replacement - """ - if input_code is None: - input_code = CODE - if replace_dict is None: - replace_dict = {**locals(), **globals()} - mod_code = input_code - for k, v in replace_dict.items(): - mod_code = mod_code.replace(frame + str(k) + frame, str(v)) - return mod_code - - -def if_cond(condition, if_return, else_return): - """ - Evaluate a condition to select a return value - - @param condition Statement that evaluates to a boolean - @param if_return Value that is returned if condition is true - @param else_return Value that is returned if condition is false - - @return if_return or else_return, depending on condition - """ - if condition: - return if_return - else: - return else_return - - def use_file(file_name): """ Read and execute a python script @@ -93,6 +68,41 @@ def use_file(file_name): exit(1) +def replace(code_block=None, local_variables=None): + """ + Evaluate or execute inline code and replace the code with the result. + + @param code_block The input code block that will be parsed and modified + @param local_variables A dictionary containing local variables that should also be considered (like locals()) + + @return the modified code + """ + global CODE + if not code_block: + code_block = CODE + if local_variables is not None: + variables = {**globals(), **local_variables} + else: + variables = globals() + matches = itertools.chain(re.finditer("%s\\s*%s\\s+(?P(.|\n)+?)%s" % (ml_comment_symbol_start, pycodegen_cmd, ml_comment_symbol_end), code_block, flags=0), + re.finditer("%s\\s+((?!block_start)|(?!block_end))\\s+(?P(.)+?)\n" % (pragma_cmd), code_block, flags=0)) + for res_ml in matches: + logging.debug("Found inline code!") + res_ml_code = res_ml.group(0) + try: + code_block = code_block.replace(res_ml_code, str(eval(res_ml.groupdict()["code"], variables))) + continue + except Exception as e: + logging.debug("Failed to evaluate inline code") + try: + logging.debug("Try execution in global space") + exec(res_ml.groupdict()["code"], globals()) + code_block = code_block.replace(res_ml_code, "") + except Exception as e: + logging.warning("Could not execute inline code:\n\tCommand: '''\n%s\n'''\n\tError: %s" % (res_ml.groupdict()["code"], e)) + return code_block + + def modify_block(code_block, cmd_str, out): global CODE CODE = code_block @@ -112,53 +122,29 @@ def modify_block(code_block, cmd_str, out): elif type(mod_code) is not str: logging.warning("%s is not a string. Automatic convert to string!" % mod_code) mod_code = str(mod_code) - logging.debug("Start parsing of modified sub-block") - parse_string(mod_code, out) - logging.debug("Finished parsing of modified sub-block") + return mod_code + #logging.debug("Start parsing of modified sub-block") + #parse_string(mod_code, out) + #logging.debug("Finished parsing of modified sub-block") def parse_string(code_string, out): - nested_level = 0 - current_block = "" - for line_number, line in enumerate(code_string.split('\n')): - line += "\n" - sline = line.strip() - if sline.startswith(pragma_cmd) and nested_level == 0: - sline = sline.replace(pragma_cmd,"") - if 'block_start' in sline: - nested_level += 1 - elif 'block_end' in sline: - logging.error("Block end before start! Invalid syntax!") - print("Block end before start! Invalid syntax!", file=sys.stderr) - exit(1) - else: - cmd_str = sline.strip() - try: - exec(cmd_str, globals()) - except Exception as e: - logging.error("Block: %s \n %s" % (current_block, e)) - logging.error("Global variables: %s" % globals()) - print( "Block: %s \n %s" % (current_block, e),file=sys.stderr) - exit(1) - elif sline.startswith(pragma_cmd): - sline = sline.replace(pragma_cmd,"") - if 'block_start' in sline: - nested_level += 1 - current_block += line - elif 'block_end' in sline: - nested_level -= 1 - if nested_level == 0: - cmd_str = sline.replace('block_end', "").strip() - modify_block(current_block, cmd_str, out) - current_block = "" - else: - current_block += line - else: - current_block += line - elif nested_level > 0: - current_block += line - else: - print(line, end='', file=out) + try: + code_string = replace(code_string) + for res in re.finditer("%s\\s*block_start\\s+(?P.*)\n(?P(.|\n)+?)%s\\s*block_end\\s*\n" % (pragma_cmd, pragma_cmd), code_string, flags=0): + logging.debug("Found block match!") + d = res.groupdict() + code_block = d["code"] + logging.debug("Modify the block!") + code_block = modify_block(code_block, d["cmd"], out) + code_string = code_string.replace(res.group(0), code_block) + logging.debug("Parsing complete. Write result to file.") + output.write(code_string) + except Exception as e: + logging.error("Block: %s \n %s" % (code_string, e)) + logging.error("Global variables: %s" % globals()) + logging.error("Local variables: %s" % locals()) + print( "Error while parsing code block: %s \n %s" % (e),file=sys.stderr) def parse_file(file_name, out): @@ -182,7 +168,10 @@ def parse_file(file_name, out): if __name__=="__main__": args = parser.parse_args() - log_file_name = args.file + ".genlog" + if args.output_file: + log_file_name = args.output_file + ".log" + else: + log_file_name = "generator.log" logging.basicConfig(filename=log_file_name, filemode='w', level=logging.DEBUG) output = sys.stdout for p in args.params: @@ -191,7 +180,10 @@ def parse_file(file_name, out): if args.output_file: logging.debug("Use output file: %s" % args.output_file) output = open(args.output_file, 'w') - pragma_cmd = args.pragma_cmd + comment_symbol = re.escape(args.comment_symbol) + ml_comment_symbol_start = re.escape(args.comment_symbol_ml_start) + ml_comment_symbol_end = re.escape(args.comment_symbol_ml_end) + pragma_cmd = comment_symbol +"\\s*"+ pycodegen_cmd logging.debug("Use pragma command: %s", pragma_cmd) logging.debug("Start parsing file: %s" % args.file) parse_file(args.file, output) From b3964b59d266f99bd4baaf6e8854fc24712edba8 Mon Sep 17 00:00:00 2001 From: Marius Meyer Date: Fri, 8 May 2020 19:23:29 +0200 Subject: [PATCH 3/8] Change code generation to python --- .../device/random_access_kernels_single.cl | 7 +++- ...en.intel.stream_kernels_single.s10mxhbm.py | 7 ++++ ...nk.xilinx.stream_kernels.hbm.generator.ini | 40 ++++++++++++------- ...nx.stream_kernels_single.hbm.generator.ini | 22 +++++++--- STREAM/src/device/stream_kernels.cl | 12 ++++-- STREAM/src/device/stream_kernels_single.cl | 20 +++++++--- cmake/general_benchmark_build_setup.cmake | 3 ++ cmake/kernelTargets.cmake | 9 ++++- 8 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py diff --git a/RandomAccess/src/device/random_access_kernels_single.cl b/RandomAccess/src/device/random_access_kernels_single.cl index 13ab9194..30304051 100644 --- a/RandomAccess/src/device/random_access_kernels_single.cl +++ b/RandomAccess/src/device/random_access_kernels_single.cl @@ -27,6 +27,9 @@ Constant used to update the pseudo random number */ #define POLY 7 + +// PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] + /* Kernel, that will update the given data array accoring to a predefined pseudo- random access scheme. The overall data array might be equally split between @@ -39,7 +42,7 @@ to the kernel. */ __attribute__((max_global_work_dim(0))) __kernel -void accessMemory_KERNEL_NUMBER(__global DEVICE_DATA_TYPE_UNSIGNED volatile * restrict data, +void accessMemory_/*PY_CODE_GEN i*/(__global DEVICE_DATA_TYPE_UNSIGNED volatile * restrict data, const DEVICE_DATA_TYPE_UNSIGNED m, const DEVICE_DATA_TYPE_UNSIGNED data_chunk, const uint kernel_number) { @@ -109,3 +112,5 @@ void accessMemory_KERNEL_NUMBER(__global DEVICE_DATA_TYPE_UNSIGNED volatile * r } } } + +// PY_CODE_GEN block_end diff --git a/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py b/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py new file mode 100644 index 00000000..5ae4c0a6 --- /dev/null +++ b/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py @@ -0,0 +1,7 @@ + +global_memory_names = [ "HBM%d" % i for i in range(4) ] + +def generate_attributes(num_replications): + return [ "__attribute__((buffer_location(\"%s\")))" + % (global_memory_names[i % len(global_memory_names)]) + for i in range(num_replications)] \ No newline at end of file diff --git a/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini b/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini index 30617e7a..bf25ebb0 100644 --- a/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini +++ b/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini @@ -1,17 +1,29 @@ + +# Code generation specifications to detect inline code +# PY_CODE_GEN ml_comment_symbol_start = "$" +# PY_CODE_GEN ml_comment_symbol_end = "$" + +# Set number of available SLRs +# PY_CODE_GEN num_slrs = 3 + [connectivity] -nk=copy_0:{TOTAL_KERNEL_NUMBER} -nk=scale_0:{TOTAL_KERNEL_NUMBER} -nk=add_0:{TOTAL_KERNEL_NUMBER} -nk=triad_0:{TOTAL_KERNEL_NUMBER} +nk=copy_0:$PY_CODE_GEN num_replications$ +nk=scale_0:$PY_CODE_GEN num_replications$ +nk=add_0:$PY_CODE_GEN num_replications$ +nk=triad_0:$PY_CODE_GEN num_replications$ -# slrs -slr=copy_0_{KERNEL_NUMBER}:SLR{KERNEL_NUMBER_DEC} -slr=scale_0_{KERNEL_NUMBER}:SLR{KERNEL_NUMBER_DEC} -slr=add_0_{KERNEL_NUMBER}:SLR{KERNEL_NUMBER_DEC} -slr=triad_0_{KERNEL_NUMBER}:SLR{KERNEL_NUMBER_DEC} +# Assign kernels to the SLRs +# PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] +slr=copy_0_$PY_CODE_GEN i+1$:SLR$PY_CODE_GEN i % num_slrs$ +slr=scale_0_$PY_CODE_GEN i+1$:SLR$PY_CODE_GEN i % num_slrs$ +slr=add_0_$PY_CODE_GEN i+1$:SLR$PY_CODE_GEN i % num_slrs$ +slr=triad_0_$PY_CODE_GEN i+1$:SLR$PY_CODE_GEN i % num_slrs$ +# PY_CODE_GEN block_end -# matrix ports -sp=copy_0_{KERNEL_NUMBER}.m_axi_gmem:HBM[0:2] -sp=scale_0_{KERNEL_NUMBER}.m_axi_gmem:HBM[0:2] -sp=add_0_{KERNEL_NUMBER}.m_axi_gmem:HBM[0:2] -sp=triad_0_{KERNEL_NUMBER}.m_axi_gmem:HBM[0:2] +# Assign the kernels to the memory ports +# PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] +sp=copy_0_$PY_CODE_GEN i+1$.m_axi_gmem:HBM[$PY_CODE_GEN 2*i$:$PY_CODE_GEN 2*i+1$] +sp=scale_0_$PY_CODE_GEN i+1$.m_axi_gmem:HBM[$PY_CODE_GEN 2*i$:$PY_CODE_GEN 2*i+1$] +sp=add_0_$PY_CODE_GEN i+1$.m_axi_gmem:HBM[$PY_CODE_GEN 2*i$:$PY_CODE_GEN 2*i+1$] +sp=triad_0_$PY_CODE_GEN i+1$.m_axi_gmem:HBM[$PY_CODE_GEN 2*i$:$PY_CODE_GEN 2*i+1$] +# PY_CODE_GEN block_end diff --git a/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini b/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini index f64070f3..b95c2d4b 100644 --- a/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini +++ b/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini @@ -1,8 +1,20 @@ + +# Code generation specifications to detect inline code +# PY_CODE_GEN ml_comment_symbol_start = "$" +# PY_CODE_GEN ml_comment_symbol_end = "$" + +# Set number of available SLRs +# PY_CODE_GEN num_slrs = 3 + [connectivity] -nk=calc_0:{TOTAL_KERNEL_NUMBER} +nk=calc_0:$PY_CODE_GEN num_replications$ -# slrs -slr=calc_0_{KERNEL_NUMBER}:SLR{KERNEL_NUMBER_DEC} +# Assign kernels to the SLRs +# PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] +slr=calc_0_$PY_CODE_GEN i+1$:SLR$PY_CODE_GEN i % num_slrs$ +# PY_CODE_GEN block_end -# matrix ports -sp=calc_0_{KERNEL_NUMBER}.m_axi_gmem:HBM[{KERNEL_NUMBER_DEC}] +# Assign the kernels to the memory ports +# PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] +sp=calc_0_$PY_CODE_GEN i+1$.m_axi_gmem:HBM[$PY_CODE_GEN i$] +# PY_CODE_GEN block_end diff --git a/STREAM/src/device/stream_kernels.cl b/STREAM/src/device/stream_kernels.cl index b266127f..cd569727 100644 --- a/STREAM/src/device/stream_kernels.cl +++ b/STREAM/src/device/stream_kernels.cl @@ -6,9 +6,11 @@ KERNEL_NUMBER will be replaced by the build script with the ID of the current re */ #include "parameters.h" +// PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] + __kernel __attribute__((uses_global_work_offset(0))) -void copy_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in, +void copy_/*PY_CODE_GEN i*/(__global const DEVICE_ARRAY_DATA_TYPE * restrict in, __global DEVICE_ARRAY_DATA_TYPE * restrict out, const uint array_size) { uint number_elements = array_size / VECTOR_COUNT; @@ -20,7 +22,7 @@ void copy_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in, __kernel __attribute__((uses_global_work_offset(0))) -void add_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in1, +void add_/*PY_CODE_GEN i*/(__global const DEVICE_ARRAY_DATA_TYPE * restrict in1, __global const DEVICE_ARRAY_DATA_TYPE * restrict in2, __global DEVICE_ARRAY_DATA_TYPE * restrict out, const uint array_size) { @@ -33,7 +35,7 @@ void add_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in1, __kernel __attribute__((uses_global_work_offset(0))) -void scale_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in, +void scale_/*PY_CODE_GEN i*/(__global const DEVICE_ARRAY_DATA_TYPE * restrict in, __global DEVICE_ARRAY_DATA_TYPE * restrict out, const DEVICE_SCALAR_DATA_TYPE scalar, const uint array_size) { @@ -46,7 +48,7 @@ void scale_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in, __kernel __attribute__((uses_global_work_offset(0))) -void triad_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in1, +void triad_/*PY_CODE_GEN i*/(__global const DEVICE_ARRAY_DATA_TYPE * restrict in1, __global const DEVICE_ARRAY_DATA_TYPE * restrict in2, __global DEVICE_ARRAY_DATA_TYPE * restrict out, const DEVICE_SCALAR_DATA_TYPE scalar, @@ -57,3 +59,5 @@ void triad_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE * restrict in1, out[i] = in1[i] + scalar * in2[i]; } } + +// PY_CODE_GEN block_end diff --git a/STREAM/src/device/stream_kernels_single.cl b/STREAM/src/device/stream_kernels_single.cl index 48e1aa30..6f4a461b 100644 --- a/STREAM/src/device/stream_kernels_single.cl +++ b/STREAM/src/device/stream_kernels_single.cl @@ -7,11 +7,18 @@ KERNEL_NUMBER will be replaced by the build script with the ID of the current re */ #include "parameters.h" +/* PY_CODE_GEN +try: + kernel_param_attributes = generate_attributes(num_replications) +except: + kernel_param_attributes = ["" for i in range(num_replications)] +*/ +// PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] __kernel __attribute__((uses_global_work_offset(0))) -void calc_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE *restrict in1, - __global const DEVICE_ARRAY_DATA_TYPE *restrict in2, - __global DEVICE_ARRAY_DATA_TYPE *restrict out, +void calc_/*PY_CODE_GEN i*/(__global /*PY_CODE_GEN kernel_param_attributes[i]*/ const DEVICE_ARRAY_DATA_TYPE *restrict in1, + __global /*PY_CODE_GEN kernel_param_attributes[i]*/ const DEVICE_ARRAY_DATA_TYPE *restrict in2, + __global /*PY_CODE_GEN kernel_param_attributes[i]*/ DEVICE_ARRAY_DATA_TYPE *restrict out, const DEVICE_SCALAR_DATA_TYPE scalar, const uint array_size, const uint operation_type) { @@ -38,8 +45,9 @@ void calc_KERNEL_NUMBER(__global const DEVICE_ARRAY_DATA_TYPE *restrict in1, // Calculate result and write back to output array depending on chosen operation type __attribute__((opencl_unroll_hint(UNROLL_COUNT))) for (uint k = 0;k Date: Fri, 8 May 2020 19:25:02 +0200 Subject: [PATCH 4/8] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bf40c4b..aa23e249 100755 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ All benchmarks come with the following build dependencies: - CMake >= 3.1 - C++ compiler with C++11 support - Intel OpenCL FPGA SDK or Xilinx Vitis -- Python 3 with [pandas](https://pandas.pydata.org) installed (for the evaluation scripts) +- Python 3 for code generation and with [pandas](https://pandas.pydata.org) installed for the evaluation scripts Moreover the host code and the build system use additional libraries included as git submodules: From 69ce56ec31d1d5db9458b267ea2e981d248e9f7c Mon Sep 17 00:00:00 2001 From: Marius Meyer Date: Fri, 8 May 2020 20:15:46 +0200 Subject: [PATCH 5/8] Fix python code generation for Xilinx --- ...dom_access_kernels_single.hbm.generator.ini | 18 +++++++++++++----- ...ink.xilinx.stream_kernels.hbm.generator.ini | 4 ---- ...inx.stream_kernels_single.hbm.generator.ini | 3 --- cmake/kernelTargets.cmake | 11 ++++++++--- scripts/code_generator/generator.py | 11 ++++++----- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/RandomAccess/settings/settings.link.xilinx.random_access_kernels_single.hbm.generator.ini b/RandomAccess/settings/settings.link.xilinx.random_access_kernels_single.hbm.generator.ini index b4a1a4b4..986bab03 100644 --- a/RandomAccess/settings/settings.link.xilinx.random_access_kernels_single.hbm.generator.ini +++ b/RandomAccess/settings/settings.link.xilinx.random_access_kernels_single.hbm.generator.ini @@ -1,8 +1,16 @@ + +# Set number of available SLRs +# PY_CODE_GEN num_slrs = 3 + [connectivity] -nk=accessMemory_0:{TOTAL_KERNEL_NUMBER} +nk=accessMemory_0:$PY_CODE_GEN num_replications$ -# slrs -slr=accessMemory_0_{KERNEL_NUMBER}:SLR{KERNEL_NUMBER_DEC} +# Assign kernels to the SLRs +# PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] +slr=accessMemory_0_$PY_CODE_GEN i+1$:SLR$PY_CODE_GEN i % num_slrs$ +# PY_CODE_GEN block_end -# matrix ports -sp=accessMemory_0_{KERNEL_NUMBER}.m_axi_gmem:HBM[{KERNEL_NUMBER_DEC}] +# Assign the kernels to the memory ports +# PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] +sp=accessMemory_0_$PY_CODE_GEN i+1$.m_axi_gmem:HBM[$PY_CODE_GEN i$] +# PY_CODE_GEN block_end diff --git a/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini b/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini index bf25ebb0..bf914f10 100644 --- a/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini +++ b/STREAM/settings/settings.link.xilinx.stream_kernels.hbm.generator.ini @@ -1,8 +1,4 @@ -# Code generation specifications to detect inline code -# PY_CODE_GEN ml_comment_symbol_start = "$" -# PY_CODE_GEN ml_comment_symbol_end = "$" - # Set number of available SLRs # PY_CODE_GEN num_slrs = 3 diff --git a/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini b/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini index b95c2d4b..eca40fa3 100644 --- a/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini +++ b/STREAM/settings/settings.link.xilinx.stream_kernels_single.hbm.generator.ini @@ -1,7 +1,4 @@ -# Code generation specifications to detect inline code -# PY_CODE_GEN ml_comment_symbol_start = "$" -# PY_CODE_GEN ml_comment_symbol_end = "$" # Set number of available SLRs # PY_CODE_GEN num_slrs = 3 diff --git a/cmake/kernelTargets.cmake b/cmake/kernelTargets.cmake index be35f940..9efde38a 100644 --- a/cmake/kernelTargets.cmake +++ b/cmake/kernelTargets.cmake @@ -20,12 +20,13 @@ function(generate_kernel_targets_xilinx) set(bitstream_emulate_f ${EXECUTABLE_OUTPUT_PATH}/${kernel_file_name}_emulate.xclbin) set(bitstream_f ${EXECUTABLE_OUTPUT_PATH}/${kernel_file_name}.xclbin) + file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/settings) if (XILINX_GENERATE_LINK_SETTINGS) set(gen_xilinx_link_settings ${XILINX_LINK_SETTINGS_FILE}) set(xilinx_link_settings ${CMAKE_BINARY_DIR}/settings/settings.link.xilinx.${kernel_file_name}.ini) else() set(gen_xilinx_link_settings ${XILINX_LINK_SETTINGS_FILE}) - set(xilinx_link_settings ${XILINX_LINK_SETTINGS_FILE}) + set(xilinx_link_settings ${CMAKE_BINARY_DIR}/settings/settings.link.xilinx.${kernel_file_name}.ini) endif() set(xilinx_report_folder "--report_dir=${EXECUTABLE_OUTPUT_PATH}/xilinx_reports") file(MAKE_DIRECTORY ${EXECUTABLE_OUTPUT_PATH}/${kernel_file_name}_reports) @@ -38,10 +39,14 @@ function(generate_kernel_targets_xilinx) ) if (XILINX_GENERATE_LINK_SETTINGS) add_custom_command(OUTPUT ${xilinx_link_settings} - COMMAND ${CODE_GENERATOR} -o ${xilinx_link_settings} -p num_replications=${NUM_REPLICATIONS} --comment "#" --comment-ml-start "$" --comment-ml-end "$" ${gen_xilinx_link_settings} - COMMAND ${CMAKE_COMMAND} -Dsettings_f=${xilinx_link_settings} -Dbase_file=${gen_xilinx_link_settings} -DNUM_REPLICATIONS=${NUM_REPLICATIONS} -P "${CMAKE_SOURCE_DIR}/../cmake/generateXilinxSettings.cmake" + COMMAND ${CODE_GENERATOR} -o ${xilinx_link_settings} -p num_replications=${NUM_REPLICATIONS} --comment "\"#\"" --comment-ml-start "\"$$\"" --comment-ml-end "\"$$\"" ${gen_xilinx_link_settings} MAIN_DEPENDENCY ${gen_xilinx_link_settings} ) + else() + add_custom_command(OUTPUT ${xilinx_link_settings} + COMMAND cp ${gen_xilinx_link_settings} ${xilinx_link_settings} + MAIN_DEPENDENCY ${gen_xilinx_link_settings} + ) endif() if (KERNEL_REPLICATION_ENABLED) diff --git a/scripts/code_generator/generator.py b/scripts/code_generator/generator.py index 374b24d4..7b27ee93 100755 --- a/scripts/code_generator/generator.py +++ b/scripts/code_generator/generator.py @@ -85,19 +85,20 @@ def replace(code_block=None, local_variables=None): else: variables = globals() matches = itertools.chain(re.finditer("%s\\s*%s\\s+(?P(.|\n)+?)%s" % (ml_comment_symbol_start, pycodegen_cmd, ml_comment_symbol_end), code_block, flags=0), - re.finditer("%s\\s+((?!block_start)|(?!block_end))\\s+(?P(.)+?)\n" % (pragma_cmd), code_block, flags=0)) + re.finditer("%s\\s+(?!block_start\\s+)(?!block_end\\s+)(?P(.)+?)\n" % (pragma_cmd), code_block, flags=0)) for res_ml in matches: - logging.debug("Found inline code!") res_ml_code = res_ml.group(0) try: - code_block = code_block.replace(res_ml_code, str(eval(res_ml.groupdict()["code"], variables))) + evaluated = str(eval(res_ml.groupdict()["code"], variables)) + code_block = code_block.replace(res_ml_code, evaluated) + logging.debug("Evaluated '%s' to '%s'" % (res_ml.groupdict()["code"], evaluated)) continue except Exception as e: logging.debug("Failed to evaluate inline code") try: - logging.debug("Try execution in global space") exec(res_ml.groupdict()["code"], globals()) code_block = code_block.replace(res_ml_code, "") + logging.debug("Executed in global space: '%s'" % res_ml.groupdict()["code"]) except Exception as e: logging.warning("Could not execute inline code:\n\tCommand: '''\n%s\n'''\n\tError: %s" % (res_ml.groupdict()["code"], e)) return code_block @@ -131,7 +132,7 @@ def modify_block(code_block, cmd_str, out): def parse_string(code_string, out): try: code_string = replace(code_string) - for res in re.finditer("%s\\s*block_start\\s+(?P.*)\n(?P(.|\n)+?)%s\\s*block_end\\s*\n" % (pragma_cmd, pragma_cmd), code_string, flags=0): + for res in re.finditer("%s\\s+block_start\\s+(?P.*)\n(?P(.|\n)+?)%s\\s+block_end\\s*\n" % (pragma_cmd, pragma_cmd), code_string, flags=0): logging.debug("Found block match!") d = res.groupdict() code_block = d["code"] From 8c9ea5a8fae6ccb51b7401567c702fe07360c05f Mon Sep 17 00:00:00 2001 From: Marius Meyer Date: Mon, 11 May 2020 11:42:25 +0200 Subject: [PATCH 6/8] Prepare for synthesis --- README.md | 1 + STREAM/scripts/build_s10xm_hbm.sh | 39 +++++++++++++++++++ ...en.intel.stream_kernels_single.s10mxhbm.py | 18 +++++++-- STREAM/src/device/stream_kernels_single.cl | 3 ++ 4 files changed, 58 insertions(+), 3 deletions(-) create mode 100755 STREAM/scripts/build_s10xm_hbm.sh diff --git a/README.md b/README.md index aa23e249..405ac454 100755 --- a/README.md +++ b/README.md @@ -86,6 +86,7 @@ For the Intel compiler these are: Name | Default | Description | ---------------- |-------------|--------------------------------------| `AOC_FLAGS`| `-fpc -fp-relaxed -no-interleaving=default` | Additional Intel AOC compiler flags that are used for kernel compilation | +`INTEL_CODE_GENERATION_SETTINGS` | "" | Path to the settings file that will be used as input for the code generator script. It may contain additional variables or functions. | For the Xilinx compiler it is also necessary to set settings files for the compile and link step of the compiler. The available options are given in the following table: diff --git a/STREAM/scripts/build_s10xm_hbm.sh b/STREAM/scripts/build_s10xm_hbm.sh new file mode 100755 index 00000000..de4962b3 --- /dev/null +++ b/STREAM/scripts/build_s10xm_hbm.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# +# Synthesize the STREAM single kernel for the Stratix 10 MX HBM board on Noctua. +# Submit this script to sbatch in this folder! +# +#SBATCH -p fpgasyn +#SBATCH --exclusive + +module load intelFPGA_pro/19.4.0 +module load intel_s10mx/19.3.0 +module load lang/Python/3.7.0-foss-2018b +module load devel/CMake/3.15.3-GCCcore-8.3.0 + +SCRIPT_PATH=${SLURM_SUBMIT_DIR} + +BENCHMARK_DIR=${SCRIPT_PATH}/../ + +BUILD_DIR_4K=${SCRIPT_PATH}/../../build/synth/STREAM-s10xm_hbm-4k +BUILD_DIR_8K=${SCRIPT_PATH}/../../build/synth/STREAM-s10xm_hbm-8k + +mkdir -p ${BUILD_DIR_4K} +cd ${BUILD_DIR_4K} + +cmake ${BENCHMARK_DIR} -DDEVICE_BUFFER_SIZE=4096 -DVECTOR_COUNT=8 -DNUM_REPLICATIONS=32 \ + -DAOC_FLAGS="-fpc -fp-relaxed -global-ring" \ + -DINTEL_CODE_GENERATION_SETTINGS=${BENCHMARK_DIR}/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py + +make stream_kernels_single_intel& + +mkdir -p ${BUILD_DIR_8K} +cd ${BUILD_DIR_8K} + +cmake ${BENCHMARK_DIR} -DDEVICE_BUFFER_SIZE=8192 -DVECTOR_COUNT=8 -DNUM_REPLICATIONS=32 \ + -DAOC_FLAGS="-fpc -fp-relaxed -global-ring" \ + -DINTEL_CODE_GENERATION_SETTINGS=${BENCHMARK_DIR}/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py + +make stream_kernels_single_intel& + +wait diff --git a/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py b/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py index 5ae4c0a6..030a9d1e 100644 --- a/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py +++ b/STREAM/settings/settings.gen.intel.stream_kernels_single.s10mxhbm.py @@ -1,7 +1,19 @@ -global_memory_names = [ "HBM%d" % i for i in range(4) ] +global_memory_name = "HBM" -def generate_attributes(num_replications): +def generate_attributes(num_replications, num_global_memory_banks=32): + """ + Generates the kernel attributes for the global memory. They specify in which + global memory the buffer is located. The buffers will be placed using a + round robin scheme using the available global memory banks and the number of + replications that should be generated (e.g. if a global memory contains multiple banks) + + @param num_replications Number okernel replications + @param num_global_memory_banks Number of global memory banks that should be used for generation + + @return Array of strings that contain the attributes for every kernel + """ + global_memory_names = [ "%s%d" % (global_memory_name, i) for i in range(num_global_memory_banks)] return [ "__attribute__((buffer_location(\"%s\")))" - % (global_memory_names[i % len(global_memory_names)]) + % (global_memory_names[i % num_global_memory_banks]) for i in range(num_replications)] \ No newline at end of file diff --git a/STREAM/src/device/stream_kernels_single.cl b/STREAM/src/device/stream_kernels_single.cl index 6f4a461b..80754015 100644 --- a/STREAM/src/device/stream_kernels_single.cl +++ b/STREAM/src/device/stream_kernels_single.cl @@ -26,6 +26,9 @@ void calc_/*PY_CODE_GEN i*/(__global /*PY_CODE_GEN kernel_param_attributes[i]*/ DEVICE_ARRAY_DATA_TYPE buffer1[BUFFER_SIZE]; #endif uint number_elements = array_size / VECTOR_COUNT; +#ifdef INTEL_FPGA +#pragma disable_loop_pipelining +#endif for(uint i = 0;i Date: Mon, 11 May 2020 12:08:16 +0200 Subject: [PATCH 7/8] Update README.md --- scripts/code_generator/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/code_generator/README.md b/scripts/code_generator/README.md index 1c6397ce..20730682 100644 --- a/scripts/code_generator/README.md +++ b/scripts/code_generator/README.md @@ -108,10 +108,9 @@ This will read the file and make all functions and global variables available wi `replace()` makes it easier to replace global variables within the code: - // PY_CODE_GEN i=2 - // PY_CODE_GEN block_start + // PY_CODE_GEN block_start replace(local_variables={"test": 2}) int var = /*PY_CODE_GEN test*/ - // PY_CODE_GEN block_end replace(local_variables={"test": 2}) + // PY_CODE_GEN block_end will generate the code `int var = 2`. From 8881ee1b0ddeab122bc236616051800351fcac00 Mon Sep 17 00:00:00 2001 From: Marius Meyer Date: Wed, 13 May 2020 16:42:15 +0200 Subject: [PATCH 8/8] Add attribute settings to random access --- ...l.random_access_kernels_single.s10mxhbm.py | 19 +++++++++++++++++++ .../device/random_access_kernels_single.cl | 8 +++++++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 RandomAccess/settings/settings.gen.intel.random_access_kernels_single.s10mxhbm.py diff --git a/RandomAccess/settings/settings.gen.intel.random_access_kernels_single.s10mxhbm.py b/RandomAccess/settings/settings.gen.intel.random_access_kernels_single.s10mxhbm.py new file mode 100644 index 00000000..030a9d1e --- /dev/null +++ b/RandomAccess/settings/settings.gen.intel.random_access_kernels_single.s10mxhbm.py @@ -0,0 +1,19 @@ + +global_memory_name = "HBM" + +def generate_attributes(num_replications, num_global_memory_banks=32): + """ + Generates the kernel attributes for the global memory. They specify in which + global memory the buffer is located. The buffers will be placed using a + round robin scheme using the available global memory banks and the number of + replications that should be generated (e.g. if a global memory contains multiple banks) + + @param num_replications Number okernel replications + @param num_global_memory_banks Number of global memory banks that should be used for generation + + @return Array of strings that contain the attributes for every kernel + """ + global_memory_names = [ "%s%d" % (global_memory_name, i) for i in range(num_global_memory_banks)] + return [ "__attribute__((buffer_location(\"%s\")))" + % (global_memory_names[i % num_global_memory_banks]) + for i in range(num_replications)] \ No newline at end of file diff --git a/RandomAccess/src/device/random_access_kernels_single.cl b/RandomAccess/src/device/random_access_kernels_single.cl index 30304051..341616de 100644 --- a/RandomAccess/src/device/random_access_kernels_single.cl +++ b/RandomAccess/src/device/random_access_kernels_single.cl @@ -27,6 +27,12 @@ Constant used to update the pseudo random number */ #define POLY 7 +/* PY_CODE_GEN +try: + kernel_param_attributes = generate_attributes(num_replications) +except: + kernel_param_attributes = ["" for i in range(num_replications)] +*/ // PY_CODE_GEN block_start [replace(local_variables=locals()) for i in range(num_replications)] @@ -42,7 +48,7 @@ to the kernel. */ __attribute__((max_global_work_dim(0))) __kernel -void accessMemory_/*PY_CODE_GEN i*/(__global DEVICE_DATA_TYPE_UNSIGNED volatile * restrict data, +void accessMemory_/*PY_CODE_GEN i*/(__global /*PY_CODE_GEN kernel_param_attributes[i]*/ DEVICE_DATA_TYPE_UNSIGNED volatile * restrict data, const DEVICE_DATA_TYPE_UNSIGNED m, const DEVICE_DATA_TYPE_UNSIGNED data_chunk, const uint kernel_number) {