Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dace/codegen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ if(DACE_ENABLE_CUDA)

set(CMAKE_CUDA_ARCHITECTURES "${LOCAL_CUDA_ARCHITECTURES}")
enable_language(CUDA)
list(APPEND DACE_LIBS CUDA::cudart)
list(APPEND DACE_LIBS CUDA::cudart CUDA::nvtx3)
add_definitions(-DWITH_CUDA)

if (MSVC_IDE)
Expand Down
2 changes: 1 addition & 1 deletion dace/codegen/targets/cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ def ptr(name: str, desc: data.Data, sdfg: SDFG = None, framecode=None) -> str:

if desc.storage == dtypes.StorageType.CPU_ThreadLocal: # Use unambiguous name for thread-local arrays
return f'__{sdfg.cfg_id}_{name}'
elif not CUDACodeGen._in_device_code: # GPU kernels cannot access state
elif not CUDACodeGen._in_device_code.get(): # GPU kernels cannot access state
return f'__state->__{sdfg.cfg_id}_{name}'
elif (sdfg, name) in framecode.where_allocated and framecode.where_allocated[(sdfg, name)] is not sdfg:
return f'__{sdfg.cfg_id}_{name}'
Expand Down
186 changes: 114 additions & 72 deletions dace/codegen/targets/cuda.py

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions dace/codegen/targets/framecode.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ def generate_fileheader(self, sdfg: SDFG, global_stream: CodeIOStream, backend:
if backend == 'frame':
global_stream.write('#include "../../include/hash.h"\n', sdfg)

global_stream.write('#ifdef WITH_CUDA\n#include <nvtx3/nvToolsExt.h>\n#endif\n', sdfg)

#########################################################
# Environment-based includes
for env in self.environments:
Expand Down Expand Up @@ -266,7 +268,13 @@ def generate_footer(self, sdfg: SDFG, global_stream: CodeIOStream, callsite_stre
f'''
DACE_EXPORTED void __program_{fname}({mangle_dace_state_struct_name(fname)} *__state{params_comma})
{{
#ifdef WITH_CUDA
nvtxRangePushA("{fname}");
#endif
__program_{fname}_internal(__state{paramnames_comma});
#ifdef WITH_CUDA
nvtxRangePop();
#endif
}}''', sdfg)

for target in self._dispatcher.used_targets:
Expand Down
2 changes: 1 addition & 1 deletion dace/config_schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ required:
type: str
title: nvcc Arguments
description: Compiler argument flags for CUDA
default: '-Xcompiler -march=native --use_fast_math -Xcompiler -Wno-unused-parameter'
default: '--generate-line-info -Xcompiler -march=native -Xcompiler -Wno-unused-parameter'
default_Windows: '-O3 --use_fast_math'

hip_args:
Expand Down
16 changes: 13 additions & 3 deletions dace/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ def _validate(self):
if any(not isinstance(s, (int, symbolic.SymExpr, symbolic.symbol, symbolic.sympy.Basic)) for s in self.shape):
raise TypeError('Shape must be a list or tuple of integer values '
'or symbols')
if any((shp < 0) == True for shp in self.shape):
raise TypeError(f'Found negative shape in Data, its shape was {self.shape}')
return True

def to_json(self):
Expand Down Expand Up @@ -1471,12 +1473,20 @@ def validate(self):
super(Array, self).validate()
if len(self.strides) != len(self.shape):
raise TypeError('Strides must be the same size as shape')
if len(self.offset) != len(self.shape):
raise TypeError('Offset must be the same size as shape')

if any(not isinstance(s, (int, symbolic.SymExpr, symbolic.symbol, symbolic.sympy.Basic)) for s in self.strides):
raise TypeError('Strides must be a list or tuple of integer values or symbols')

if len(self.offset) != len(self.shape):
raise TypeError('Offset must be the same size as shape')
if any(not isinstance(off, (int, symbolic.SymExpr, symbolic.symbol, symbolic.sympy.Basic))
for off in self.offset):
raise TypeError('Offset must be a list or tuple of integer values or symbols')

# Actually it would be enough to only enforce the non negativity only if the shape is larger than one.
if any((stride < 0) == True for stride in self.strides):
raise TypeError(f'Found negative strides in array, they were {self.strides}')
if (self.total_size < 0) == True:
raise TypeError(f'The total size of an array must be positive but it was negative {self.total_size}')

def covers_range(self, rng):
if len(rng) != len(self.shape):
Expand Down
3 changes: 3 additions & 0 deletions dace/memlet.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,9 @@ def dst_subset(self, new_dst_subset):
def validate(self, sdfg, state):
if self.data is not None and self.data not in sdfg.arrays:
raise KeyError('Array "%s" not found in SDFG' % self.data)
# NOTE: We do not check here is the subsets have a negative size, because such as subset
# is valid, in certain cases, for example if an AccessNode is connected to a MapEntry,
# because the Map is not executed. Thus we do the check in the `validate_state()` function.

def used_symbols(self, all_symbols: bool, edge=None) -> Set[str]:
"""
Expand Down
24 changes: 22 additions & 2 deletions dace/sdfg/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import networkx as nx

from dace import dtypes, subsets, symbolic
from dace import dtypes, subsets, symbolic, data
from dace.dtypes import DebugInfo

if TYPE_CHECKING:
Expand Down Expand Up @@ -656,7 +656,6 @@ def validate_state(state: 'dace.sdfg.SDFGState',
)
########################################

# Memlet checks
for eid, e in enumerate(state.edges()):
# Reference check
if id(e) in references:
Expand All @@ -680,6 +679,27 @@ def validate_state(state: 'dace.sdfg.SDFGState',
except Exception as ex:
raise InvalidSDFGEdgeError("Edge validation failed: " + str(ex), sdfg, state_id, eid)

# If the edge is a connection between two AccessNodes check if the subset has negative size.
# NOTE: We _should_ do this check in `Memlet.validate()` however, this is not possible,
# because the connection between am AccessNode and a MapEntry, with a negative size, is
# legal because, the Map will not run in that case. However, this constellation can not
# be tested for in the Memlet's validation function, so we have to do it here.
# NOTE: Zero size is explicitly allowed because it is essentially `memcpy(dst, src, 0)`
# which is save.
# TODO: The AN to AN connection is the most obvious one, but it should be extended.
if isinstance(e.src, nd.AccessNode) and isinstance(e.dst, nd.AccessNode):
e_memlet: dace.Memlet = e.data
if e_memlet.subset is not None:
if any((ss < 0) == True for ss in e_memlet.subset.size()):
raise InvalidSDFGEdgeError(
f'`subset` of an AccessNode to AccessNode Memlet contains a negative size; the size was {e_memlet.subset.size()}',
sdfg, state_id, eid)
if e_memlet.other_subset is not None:
if any((ss < 0) == True for ss in e_memlet.other_subset.size()):
raise InvalidSDFGEdgeError(
f'`other_subset` of an AccessNode to AccessNode Memlet contains a negative size; the size was {e_memlet.other_subset.size()}',
sdfg, state_id, eid)

# For every memlet, obtain its full path in the DFG
path = state.memlet_path(e)
src_node = path[0].src
Expand Down
Loading