Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Warn on potential data races #1541

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
46b4813
Write tests with mapped tasklets
luca-patrignani Mar 3, 2024
922d5ef
Add config flag
luca-patrignani Mar 3, 2024
bf1b814
Check if there are intersecting memlet subsets for a given access node
luca-patrignani Mar 4, 2024
b928aa4
Filter only UserWarning in test_memlet_range_not_overlap_ranges
luca-patrignani Mar 4, 2024
19b4a03
Update dace/config_schema.yml
luca-patrignani Mar 11, 2024
653b0de
Move check_race_conditions flag into experimental category and add test
luca-patrignani Mar 11, 2024
8534fb3
Create test with overlapping ranges with two different access nodes
luca-patrignani Mar 12, 2024
3469315
Create test for symbolic overlap
luca-patrignani Mar 12, 2024
87cf81e
Create tests for constant memlet overlap and almost overlap
luca-patrignani Mar 12, 2024
8cbf45f
Revert changes to submodule
luca-patrignani Mar 12, 2024
8120d39
Fix constant_memlet_almost_overlap_test
luca-patrignani Mar 14, 2024
7f7f863
Fix constant_memlet_almost_overlap_test for real
luca-patrignani Mar 14, 2024
ff497ea
Check write-write data races and read-write data races
luca-patrignani Mar 14, 2024
4b5ac97
Remove are_intesecting function
luca-patrignani Mar 15, 2024
1c8d803
Validate sdfgs instead of running the programs
luca-patrignani Mar 16, 2024
655fb90
Use is True instead of first checking if it's null and then check if …
luca-patrignani Mar 16, 2024
a849a84
Add test_elementwise_map
luca-patrignani Mar 16, 2024
2f8f60c
Add test for wcr
luca-patrignani Mar 17, 2024
7293fa9
Check if there are paths between the two nodes when looking for
luca-patrignani Mar 18, 2024
322b256
Remove unused numpy import
luca-patrignani Mar 18, 2024
bacca88
Merge branch 'master' into master
phschaad May 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions dace/config_schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,12 @@ required:
be called before every compiled SDFG's generated code is invoked. Used
for functionality such as low-level profiling.

check_race_conditions:
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved
type: bool
default: false
title: Check race conditions
description: Check for probable race conditions during the program's execution.
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved

#############################################
# Experimental features

Expand Down
8 changes: 8 additions & 0 deletions dace/sdfg/validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import warnings
from dace import dtypes, subsets
from dace import symbolic
from dace.sdfg.nodes import AccessNode

if TYPE_CHECKING:
import dace
Expand Down Expand Up @@ -790,6 +791,13 @@ def validate_state(state: 'dace.sdfg.SDFGState',
continue
raise error

if Config.get_bool("check_race_conditions"):
for node in state.nodes():
if isinstance(node, AccessNode):
in_memlet_ranges = [e.data.dst_subset for e in state.in_edges(node)]
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved
if subsets.Range.are_intersecting(in_memlet_ranges):
warnings.warn(f'Memlet range overlap while writing to "{node}" in state "{state.label}"')

########################################


Expand Down
11 changes: 11 additions & 0 deletions dace/subsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,17 @@ def intersects(self, other: 'Range'):

return True

@staticmethod
def are_intersecting(ranges: List['Range']) -> bool:
""" Check if any of the given ranges are intersecting
:param ranges: the ranges to be checked.
"""
for i in range(len(ranges)):
for j in range(i+1, len(ranges)):
if ranges[i].intersects(ranges[j]):
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved
return True
return False


@dace.serialize.serializable
class Indices(Subset):
Expand Down
2 changes: 1 addition & 1 deletion dace/viewer/webclient
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved
Submodule webclient updated 100 files
86 changes: 86 additions & 0 deletions tests/warn_on_potential_data_race_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Copyright 2019-2024 ETH Zurich and the DaCe authors. All rights reserved.

import warnings
import dace
import numpy as np
import pytest

luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved

def test_memlet_range_not_overlap_ranges():
sdfg = dace.SDFG('memlet_range_not_overlap_ranges')
state = sdfg.add_state()
N = dace.symbol("N", dtype=dace.int32)
sdfg.add_array("A", (N//2,), dace.int32)
A = state.add_access("A")
sdfg.add_array("B", (N,), dace.int32)
B = state.add_access("B")
state.add_mapped_tasklet(
name="first_tasklet",
code="b = a + 10",
inputs={"a": dace.Memlet(data="A", subset="k")},
outputs={"b": dace.Memlet(data="B", subset="k")},
map_ranges={"k": "0:N//2"},
external_edges=True,
input_nodes={"A": A},
output_nodes={"B": B}
)
state.add_mapped_tasklet(
name="second_tasklet",
code="b = a - 20",
inputs={"a": dace.Memlet(data="A", subset="k")},
outputs={"b": dace.Memlet(data="B", subset="k+N//2")},
map_ranges={"k": "0:N//2"},
external_edges=True,
input_nodes={"A": A},
output_nodes={"B": B}
)

N = 6
A = np.arange(N//2, dtype=np.int32)
B = np.zeros((N,), dtype=np.int32)
with warnings.catch_warnings():
warnings.simplefilter("error", UserWarning)
with dace.config.set_temporary("check_race_conditions", value=True):
sdfg(N=N, A=A, B=B)
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved


def test_memlet_range_overlap_ranges():
sdfg = dace.SDFG('memlet_range_overlap_ranges')
state = sdfg.add_state()
N = dace.symbol("N", dtype=dace.int32)
sdfg.add_array("A", (N,), dace.int32)
A = state.add_access("A")
sdfg.add_array("B", (N,), dace.int32)
B = state.add_access("B")
state.add_mapped_tasklet(
name="first_tasklet",
code="b = a + 10",
inputs={"a": dace.Memlet(data="A", subset="k")},
outputs={"b": dace.Memlet(data="B", subset="k")},
map_ranges={"k": "0:N"},
external_edges=True,
input_nodes={"A": A},
output_nodes={"B": B}
)
state.add_mapped_tasklet(
name="second_tasklet",
code="b = a - 20",
inputs={"a": dace.Memlet(data="A", subset="k")},
outputs={"b": dace.Memlet(data="B", subset="k")},
map_ranges={"k": "0:N"},
external_edges=True,
input_nodes={"A": A},
output_nodes={"B": B}
)

N = 6
A = np.arange(N, dtype=np.int32)
B = np.zeros((N,), dtype=np.int32)
with pytest.warns(UserWarning):
with dace.config.set_temporary("check_race_conditions", value=True):
sdfg(N=N, A=A, B=B)
luca-patrignani marked this conversation as resolved.
Show resolved Hide resolved


if __name__ == '__main__':
test_memlet_range_not_overlap_ranges()
test_memlet_range_overlap_ranges()