def test_determine_alloc_sdfg(): sdfg, scopes = _test_determine_alloc(dace.AllocationLifetime.SDFG) codegen = framecode.DaCeCodeGenerator() codegen.determine_allocation_lifetime(sdfg) assert _check_alloc(1, 'tmp', codegen, scopes[-3]) assert _check_alloc(1, 'tmp2', codegen, scopes[-3])
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. @param sdfg: The SDFG to use @return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() frame = framecode.DaCeCodeGenerator() # Instantiate all targets (who register themselves with framecodegen) targets = { name: STRING_TO_TARGET[name](frame, sdfg) for name in _TARGET_REGISTER_ORDER } # Generate frame code (and the rest of the code) global_code, frame_code, used_targets = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame', meta_info=PerfMetaInfoStatic.info if PerfSettings.perf_enable_vectorization_analysis() else PerfMetaInfo()) ] PerfMetaInfoStatic.info = PerfMetaInfo() # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) return target_objects
def test_determine_alloc_scope(): sdfg, scopes = _test_determine_alloc(dace.AllocationLifetime.Scope) codegen = framecode.DaCeCodeGenerator() codegen.determine_allocation_lifetime(sdfg) # tmp cannot be allocated within the inner scope because it is GPU_Global assert _check_alloc(1, 'tmp', codegen, scopes[-2]) assert _check_alloc(1, 'tmp2', codegen, scopes[-1])
def test_determine_alloc_global(): sdfg, scopes = _test_determine_alloc(dace.AllocationLifetime.Global) codegen = framecode.DaCeCodeGenerator() codegen.determine_allocation_lifetime(sdfg) assert any('__1_tmp' in field for field in codegen.statestruct) assert any('__1_tmp2' in field for field in codegen.statestruct) assert _check_alloc(1, 'tmp', codegen, sdfg) assert _check_alloc(1, 'tmp2', codegen, sdfg)
def test_determine_alloc_state(): sdfg, scopes = _test_determine_alloc(dace.AllocationLifetime.State, unused=True) codegen = framecode.DaCeCodeGenerator(sdfg) codegen.determine_allocation_lifetime(sdfg) # Ensure that unused transients are not allocated assert not any('__0_unused' in field for field in codegen.statestruct) assert _check_alloc(1, 'tmp', codegen, scopes[-2]) assert _check_alloc(1, 'tmp2', codegen, scopes[-2])
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. :param sdfg: The SDFG to use :return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() if Config.get_bool('testing', 'serialization'): from dace.sdfg import SDFG import filecmp import shutil import tempfile with tempfile.TemporaryDirectory() as tmp_dir: sdfg.save(f'{tmp_dir}/test.sdfg') sdfg2 = SDFG.from_file(f'{tmp_dir}/test.sdfg') sdfg2.save(f'{tmp_dir}/test2.sdfg') print('Testing SDFG serialization...') if not filecmp.cmp(f'{tmp_dir}/test.sdfg', f'{tmp_dir}/test2.sdfg'): shutil.move(f"{tmp_dir}/test.sdfg", "test.sdfg") shutil.move(f"{tmp_dir}/test2.sdfg", "test2.sdfg") raise RuntimeError( 'SDFG serialization failed - files do not match') # Run with the deserialized version # NOTE: This means that all subsequent modifications to `sdfg` # are not reflected outside of this function (e.g., library # node expansion). sdfg = sdfg2 # Before generating the code, run type inference on the SDFG connectors infer_types.infer_connector_types(sdfg) # Set default storage/schedule types in SDFG infer_types.set_default_schedule_and_storage_types(sdfg, None) # Recursively expand library nodes that have not yet been expanded sdfg.expand_library_nodes() # After expansion, run another pass of connector/type inference infer_types.infer_connector_types(sdfg) infer_types.set_default_schedule_and_storage_types(sdfg, None) frame = framecode.DaCeCodeGenerator() # Instantiate CPU first (as it is used by the other code generators) # TODO: Refactor the parts used by other code generators out of CPU default_target = cpu.CPUCodeGen for k, v in target.TargetCodeGenerator.extensions().items(): # If another target has already been registered as CPU, use it instead if v['name'] == 'cpu': default_target = k targets = {'cpu': default_target(frame, sdfg)} # Instantiate the rest of the targets targets.update({ v['name']: k(frame, sdfg) for k, v in target.TargetCodeGenerator.extensions().items() if v['name'] not in targets }) # Instantiate all instrumentation providers in SDFG provider_mapping = InstrumentationProvider.get_provider_mapping() frame._dispatcher.instrumentation[ dtypes.InstrumentationType.No_Instrumentation] = None for node, _ in sdfg.all_nodes_recursive(): if hasattr(node, 'instrument'): frame._dispatcher.instrumentation[node.instrument] = \ provider_mapping[node.instrument] elif hasattr(node, 'consume'): frame._dispatcher.instrumentation[node.consume.instrument] = \ provider_mapping[node.consume.instrument] elif hasattr(node, 'map'): frame._dispatcher.instrumentation[node.map.instrument] = \ provider_mapping[node.map.instrument] if sdfg.instrument != dtypes.InstrumentationType.No_Instrumentation: frame._dispatcher.instrumentation[sdfg.instrument] = \ provider_mapping[sdfg.instrument] frame._dispatcher.instrumentation = { k: v() if v is not None else None for k, v in frame._dispatcher.instrumentation.items() } # Generate frame code (and the rest of the code) (global_code, frame_code, used_targets, used_environments) = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame', environments=used_environments, sdfg=sdfg) ] # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) # add a header file for calling the SDFG dummy = CodeObject(sdfg.name, generate_headers(sdfg), 'h', cpu.CPUCodeGen, 'CallHeader', target_type='../../include', linkable=False) target_objects.append(dummy) for env in dace.library.get_environments_and_dependencies( used_environments): if hasattr(env, "codeobjects"): target_objects.extend(env.codeobjects) # add a dummy main function to show how to call the SDFG dummy = CodeObject(sdfg.name + "_main", generate_dummy(sdfg), 'cpp', cpu.CPUCodeGen, 'SampleMain', target_type='../../sample', linkable=False) target_objects.append(dummy) return target_objects
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. :param sdfg: The SDFG to use :return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() if Config.get_bool('testing', 'serialization'): from dace.sdfg import SDFG import filecmp sdfg.save('test.sdfg') sdfg2 = SDFG.from_file('test.sdfg') sdfg2.save('test2.sdfg') print('Testing SDFG serialization...') if not filecmp.cmp('test.sdfg', 'test2.sdfg'): raise RuntimeError( 'SDFG serialization failed - files do not match') os.remove('test.sdfg') os.remove('test2.sdfg') # Run with the deserialized version sdfg = sdfg2 frame = framecode.DaCeCodeGenerator() # Instantiate CPU first (as it is used by the other code generators) # TODO: Refactor the parts used by other code generators out of CPU default_target = cpu.CPUCodeGen for k, v in target.TargetCodeGenerator.extensions().items(): # If another target has already been registered as CPU, use it instead if v['name'] == 'cpu': default_target = k targets = {'cpu': default_target(frame, sdfg)} # Instantiate the rest of the targets targets.update({ v['name']: k(frame, sdfg) for k, v in target.TargetCodeGenerator.extensions().items() if v['name'] not in targets }) # Instantiate all instrumentation providers in SDFG provider_mapping = InstrumentationProvider.get_provider_mapping() frame._dispatcher.instrumentation[ dtypes.InstrumentationType.No_Instrumentation] = None for node, _ in sdfg.all_nodes_recursive(): if hasattr(node, 'instrument'): frame._dispatcher.instrumentation[node.instrument] = \ provider_mapping[node.instrument] elif hasattr(node, 'consume'): frame._dispatcher.instrumentation[node.consume.instrument] = \ provider_mapping[node.consume.instrument] elif hasattr(node, 'map'): frame._dispatcher.instrumentation[node.map.instrument] = \ provider_mapping[node.map.instrument] frame._dispatcher.instrumentation = { k: v() if v is not None else None for k, v in frame._dispatcher.instrumentation.items() } # Generate frame code (and the rest of the code) (global_code, frame_code, used_targets, used_environments) = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame', environments=used_environments) ] # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) # add a header file for calling the SDFG dummy = CodeObject(sdfg.name, generate_headers(sdfg), 'h', cpu.CPUCodeGen, 'CallHeader', linkable=False) target_objects.append(dummy) # add a dummy main function to show how to call the SDFG dummy = CodeObject(sdfg.name + "_main", generate_dummy(sdfg), 'cpp', cpu.CPUCodeGen, 'DummyMain', linkable=False) target_objects.append(dummy) return target_objects
def generate_code(sdfg) -> List[CodeObject]: """ Generates code as a list of code objects for a given SDFG. @param sdfg: The SDFG to use @return: List of code objects that correspond to files to compile. """ # Before compiling, validate SDFG correctness sdfg.validate() if Config.get_bool('experimental', 'test_serialization'): from dace.sdfg import SDFG import filecmp sdfg.save('test.sdfg') sdfg2 = SDFG.from_file('test.sdfg') sdfg2.save('test2.sdfg') print('Testing SDFG serialization...') if not filecmp.cmp('test.sdfg', 'test2.sdfg'): raise RuntimeError( 'SDFG serialization failed - files do not match') os.remove('test.sdfg') os.remove('test2.sdfg') # Run with the deserialized version sdfg = sdfg2 frame = framecode.DaCeCodeGenerator() # Instantiate all targets (who register themselves with framecodegen) targets = { name: STRING_TO_TARGET[name](frame, sdfg) for name in _TARGET_REGISTER_ORDER } # Instantiate all instrumentation providers in SDFG frame._dispatcher.instrumentation[ dtypes.InstrumentationType.No_Instrumentation] = None for node, _ in sdfg.all_nodes_recursive(): if hasattr(node, 'instrument'): frame._dispatcher.instrumentation[node.instrument] = \ INSTRUMENTATION_PROVIDERS[node.instrument] elif hasattr(node, 'consume'): frame._dispatcher.instrumentation[node.consume.instrument] = \ INSTRUMENTATION_PROVIDERS[node.consume.instrument] elif hasattr(node, 'map'): frame._dispatcher.instrumentation[node.map.instrument] = \ INSTRUMENTATION_PROVIDERS[node.map.instrument] frame._dispatcher.instrumentation = { k: v() if v is not None else None for k, v in frame._dispatcher.instrumentation.items() } # Generate frame code (and the rest of the code) global_code, frame_code, used_targets = frame.generate_code(sdfg, None) target_objects = [ CodeObject(sdfg.name, global_code + frame_code, 'cpp', cpu.CPUCodeGen, 'Frame') ] # Create code objects for each target for tgt in used_targets: target_objects.extend(tgt.get_generated_codeobjects()) return target_objects