def test_number_of_input_stmts_different_with_output(self): args = {**self.blur.__dict__, **{'replication_factor': 1}} input_stmt = copy.copy(self.input_stmt) input_stmt.name = 'bar' args['input_stmts'] = [self.input_stmt, input_stmt] with self.assertRaises(util.SemanticError) as context: core.Stencil(**args) self.assertEqual(str(context.exception), 'number of input tensors must be the same as output if iterate > 1 times,' ' currently there are 2 input(s) but 1 output(s)')
def test_haoda_type_of_input_stmts_different_with_output(self): args = {**self.blur.__dict__, **{'replication_factor': 1}} input_stmt = copy.copy(self.input_stmt) input_stmt.haoda_type = ir.Type('half') args['input_stmts'] = [input_stmt] with self.assertRaises(util.SemanticError) as context: core.Stencil(**args) self.assertEqual(str(context.exception), 'input must have the same type(s) as output if iterate > 1 times, ' 'current input has type [half] but output has type [uint16]')
def setUp(self): self.tile_size = [233, 0] self.haoda_type = ir.Type('uint16') self.unroll_factor = 1 self.expr_ref = ir.Ref(name='foo', idx=(233, 42), lat=None) self.expr = ir.Expr(operand=(self.expr_ref,), operator=()) self.input_stmt = grammar.InputStmt( haoda_type=self.haoda_type, name='foo_i', tile_size=self.tile_size, dram=()) self.param_stmt = grammar.ParamStmt( haoda_type=self.haoda_type, name='foo_p', attr=(), size=(), dram=()) self.local_ref = ir.Ref(name='foo_l', idx=(0, 0), lat=None) self.local_stmt = grammar.LocalStmt( haoda_type=self.haoda_type, let=(), ref=self.local_ref, expr=self.expr) self.output_ref = ir.Ref(name='foo_o', idx=(0, 0), lat=None) self.output_stmt = grammar.OutputStmt( haoda_type=self.haoda_type, let=(), ref=self.output_ref, expr=self.expr, dram=()) self.args = { 'burst_width': 512, 'border': 'ignore', 'iterate': 2, 'cluster': 'none', 'app_name': 'foo_bar', 'input_stmts': [self.input_stmt], 'param_stmts': [self.param_stmt], 'local_stmts': [self.local_stmt], 'output_stmts': [self.output_stmt], 'dim': len(self.tile_size), 'tile_size': self.tile_size, 'unroll_factor': self.unroll_factor, 'replication_factor': self.unroll_factor} self.soda_mm = textx.metamodel_from_str( grammar.GRAMMAR, classes=grammar.CLASSES) self.blur = self.soda_mm.model_from_str( r''' kernel: blur burst width: 512 unroll factor: 16 input uint16: input(2000, *) local uint16: tmp(0,0)=(input(-1,0)+input(0,0)+input(1,0))/3 output uint16: output(0,0)=(tmp(0,-1)+tmp(0,0)+tmp(0,1))/3 iterate: 2 border: preserve cluster: none ''') args = {**self.blur.__dict__, **{'replication_factor': 1}} self.stencil = core.Stencil(**args)
def test_simple_inlining(self): program = self.soda_mm.model_from_str( r''' kernel: blur burst width: 512 unroll factor: 16 input float: t0(233, *) local float: t1(-1, -2) = t0(0, 1) output float: t2(4, 2) = t1(2, 3) iterate: 1 border: preserve cluster: none ''') args = {**program.__dict__, **{'replication_factor': 1}} stencil = core.Stencil(**args) inline.inline(stencil) self.assertEqual(len(stencil.local_stmts), 0) self.assertEqual(len(stencil.output_stmts), 1) self.assertEqual(str(stencil.output_stmts[0]), 'output float: t2(4, 2) = t0(3, 6)')
def main(): parser = argparse.ArgumentParser( prog='sodac', description='Stencil with Optimized Dataflow Architecture ' '(SODA) compiler') parser.add_argument('--verbose', '-v', action='count', dest='verbose', help='increase verbosity') parser.add_argument('--quiet', '-q', action='count', dest='quiet', help='decrease verbosity') parser.add_argument('--recursion-limit', type=int, dest='recursion_limit', help='override Python recursion limit') parser.add_argument('--burst-width', type=int, dest='burst_width', help='override burst width') parser.add_argument('--unroll-factor', type=int, metavar='UNROLL_FACTOR', dest='unroll_factor', help='override unroll factor') parser.add_argument('--replication-factor', type=int, metavar='REPLICATION_FACTOR', dest='replication_factor', help='override replication factor') parser.add_argument('--tile-size', type=int, nargs='+', metavar='TILE_SIZE', dest='tile_size', help='override tile size; ' '0 means no overriding on that dimension') parser.add_argument('--dram-in', type=str, dest='dram_in', help='override DRAM configuration for input') parser.add_argument('--dram-out', type=str, dest='dram_out', help='override DRAM configuration for output') parser.add_argument('--iterate', type=int, metavar='#ITERATION', dest='iterate', help='override iterate directive; ' 'repeat execution multiple times iteratively') parser.add_argument('--border', type=str, metavar='(ignore|preserve)', dest='border', help='override border handling strategy') parser.add_argument('--cluster', type=str, metavar='(none|fine|coarse|full)', dest='cluster', help='module clustering level, `none` generates ' 'standalone compute / forward modules, `fine` ' 'fuses forwarders into compute modules, `coarse` ' 'fuses each stage together, `full` fuses ' 'everything together') parser.add_argument(type=str, dest='soda_src', metavar='file', help='soda source code') xocl.add_arguments(parser.add_argument_group('Xilinx OpenCL backend')) iocl.add_arguments(parser.add_argument_group('Intel OpenCL backend')) frt.add_arguments(parser.add_argument_group('FPGA runtime backend')) opt_args.add_arguments(parser.add_argument_group('SODA optimizations')) parser.add_argument('--model-file', type=str, dest='model_file', metavar='file', help='resource model specified as json file') parser.add_argument('--estimation-file', type=str, dest='estimation_file', metavar='file', help='report resource and performance estimation as ' 'json file') args = parser.parse_args() verbose = 0 if args.verbose is None else args.verbose quiet = 0 if args.quiet is None else args.quiet logging_level = (quiet - verbose) * 10 + logging.getLogger().getEffectiveLevel() if logging_level > logging.CRITICAL: logging_level = logging.CRITICAL if logging_level < logging.DEBUG: logging_level = logging.DEBUG logging.getLogger().setLevel(logging_level) logger.info('set log level to %s', logging.getLevelName(logging_level)) # TODO: check tile size if args.recursion_limit is not None: sys_recursion_limit = sys.getrecursionlimit() if sys_recursion_limit > args.recursion_limit: logger.warning( 'Python system recursion limit (%d) > specified value (%d); ' 'the latter will be ignored', sys_recursion_limit, args.recursion_limit) else: sys.setrecursionlimit(args.recursion_limit) logger.warning('Python recursion limit is set to %d', sys.getrecursionlimit()) soda_mm = textx.metamodel_from_str(grammar.GRAMMAR, classes=grammar.CLASSES) logger.info('build metamodel') try: if args.soda_src == '-': soda_file_name = sys.stdin.name soda_model = soda_mm.model_from_str(sys.stdin.read()) else: with open(args.soda_src, 'r') as soda_file: soda_model = soda_mm.model_from_str(soda_file.read()) soda_file_name = soda_file.name logger.info('%s parsed as soda file', soda_file_name) logger.debug('soda program parsed:\n %s', str(soda_model).replace('\n', '\n ')) tile_size = [] for dim in range(soda_model.dim - 1): if (args.tile_size is not None and dim < len(args.tile_size) and args.tile_size[dim] > 0): tile_size.append(args.tile_size[dim]) else: tile_size.append(soda_model.tile_size[dim]) tile_size.append(0) if args.replication_factor is None: if args.unroll_factor is not None: unroll_factor = args.unroll_factor else: unroll_factor = soda_model.unroll_factor replication_factor = 1 else: unroll_factor = args.replication_factor replication_factor = args.replication_factor stencil = core.Stencil( burst_width=args.burst_width if args.burst_width is not None else soda_model.burst_width, border=args.border if args.border is not None else soda_model.border, iterate=args.iterate if args.iterate is not None else soda_model.iterate, cluster=args.cluster if args.cluster is not None else soda_model.cluster, dram_in=args.dram_in, dram_out=args.dram_out, app_name=soda_model.app_name, input_stmts=soda_model.input_stmts, param_stmts=soda_model.param_stmts, local_stmts=soda_model.local_stmts, output_stmts=soda_model.output_stmts, dim=soda_model.dim, tile_size=tile_size, unroll_factor=unroll_factor, replication_factor=replication_factor, optimizations=opt_args.get_kwargs(args), ) logger.debug('stencil obtained: %s', stencil) xocl.print_code(stencil, args, parser) iocl.print_code(stencil, args) frt.print_code(stencil, args) if args.estimation_file is not None: if args.model_file is None: if args.soda_src.endswith('.soda'): model_file = args.soda_src[:-len('.soda')] + '_model.json' else: logger.fatal('cannot find resource model file') sys.exit(1) else: model_file = args.model_file def print_estimation(): def print_estimation(): model.print_estimation(stencil, model_file, estimation_file) if args.estimation_file == '-': estimation_file = sys.stdout print_estimation() else: with open(args.estimation_file, 'w') as estimation_file: print_estimation() if model_file == '-': model_file = sys.stdin print_estimation() else: with open(model_file) as model_file: print_estimation() except textx.exceptions.TextXSyntaxError as e: logger.error(e) sys.exit(1) except util.SemanticError as e: logger.error(e) sys.exit(1) except util.SemanticWarn as w: logger.warning(w)