Skip to content

Commit 063753e

Browse files
committed
fix pykokkos to be able to run ExaMiniMD under Debug mode in new repo
1 parent bbd05a1 commit 063753e

8 files changed

Lines changed: 153 additions & 50 deletions

File tree

pykokkos/pykokkos/core/run_debug.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def run_workunit_debug(
122122

123123
elif isinstance(policy, TeamThreadRange) or isinstance(policy, ThreadVectorRange):
124124
for i in range(policy.count):
125-
call_workunit(operation, workunit, TeamMember(i, 0), acc, **kwargs)
125+
call_workunit(operation, workunit, i, acc, **kwargs)
126126

127127
else:
128128
if isinstance(policy, MDRangePolicy):

pykokkos/pykokkos/core/runtime.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,9 @@ def is_debug(self, space: ExecutionSpace) -> bool:
418418
:returns: True or False
419419
"""
420420

421+
if km.get_default_space() is ExecutionSpace.Debug:
422+
return True
423+
421424
return space is ExecutionSpace.Debug or (
422425
space is ExecutionSpace.Default
423426
and km.get_default_space() is ExecutionSpace.Debug

pykokkos/pykokkos/interface/accumulator.py

Lines changed: 39 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -5,56 +5,70 @@ class Acc(Generic[TypeVar("T")]):
55
def __init__(self, val):
66
self.val = val
77

8+
# Non-augmented arithmetic (`n + 1`, `n * 2`, ...) must not mutate `n`,
9+
# matching normal Python operator semantics.
810
def __add__(self, other):
9-
self.val = self.val + other
10-
return self
11+
return self.val + other
1112

1213
def __radd__(self, other):
13-
self.val = self.val + other
14-
return self
14+
return other + self.val
1515

1616
def __sub__(self, other):
17-
self.val = self.val - other
18-
return self
17+
return self.val - other
1918

2019
def __rsub__(self, other):
21-
self.val = other - self.val
22-
return self
20+
return other - self.val
2321

2422
def __mul__(self, other):
25-
self.val = self.val * other
26-
return self
23+
return self.val * other
2724

2825
def __rmul__(self, other):
29-
self.val = self.val * other
30-
return self
26+
return other * self.val
3127

3228
def __truediv__(self, other):
33-
self.val = self.val / other
34-
return self
29+
return self.val / other
3530

3631
def __rtruediv__(self, other):
37-
self.val = other / self.val
38-
return self
32+
return other / self.val
3933

4034
def __floordiv__(self, other):
41-
self.val = self.val // other
42-
return self
35+
return self.val // other
4336

4437
def __rfloordiv__(self, other):
45-
self.val = other // self.val
46-
return self
38+
return other // self.val
4739

4840
def __mod__(self, other):
49-
self.val = self.val % other
41+
return self.val % other
42+
43+
def __rmod__(self, other):
44+
return other % self.val
45+
46+
def __neg__(self):
47+
return -self.val
48+
49+
# Augmented assignment (`n += 1`, ...) is where mutation belongs.
50+
def __iadd__(self, other):
51+
self.val = self.val + other
5052
return self
5153

52-
def __rmov__(self, other):
53-
self.val = other % self.val
54+
def __isub__(self, other):
55+
self.val = self.val - other
5456
return self
5557

56-
def __neg__(self):
57-
self.val = -self.val
58+
def __imul__(self, other):
59+
self.val = self.val * other
60+
return self
61+
62+
def __itruediv__(self, other):
63+
self.val = self.val / other
64+
return self
65+
66+
def __ifloordiv__(self, other):
67+
self.val = self.val // other
68+
return self
69+
70+
def __imod__(self, other):
71+
self.val = self.val % other
5872
return self
5973

6074
def __index__(self):

pykokkos/pykokkos/interface/atomic/atomic_fetch_op.py

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,32 @@ def atomic_fetch_add(
1111
view: View, indices: List[int], value: Union[int, float]
1212
) -> Union[int, float]:
1313
inner = reduce(operator.getitem, indices[:-1], view)
14+
old_result = inner[indices[-1]]
1415
inner[indices[-1]] += value
15-
return inner[indices[-1]]
16+
return old_result
1617

1718

1819
def atomic_fetch_and(view: View, indices: List[int], value: int) -> int:
1920
inner = reduce(operator.getitem, indices[:-1], view)
21+
old_result = inner[indices[-1]]
2022
inner[indices[-1]] &= value
21-
return inner[indices[-1]]
23+
return old_result
2224

2325

2426
def atomic_fetch_div(
2527
view: View, indices: List[int], value: Union[int, float]
2628
) -> Union[int, float]:
2729
inner = reduce(operator.getitem, indices[:-1], view)
30+
old_result = inner[indices[-1]]
2831
inner[indices[-1]] /= value
29-
return inner[indices[-1]]
32+
return old_result
3033

3134

3235
def atomic_fetch_lshift(view: View, indices: List[int], value: int) -> int:
3336
inner = reduce(operator.getitem, indices[:-1], view)
37+
old_result = inner[indices[-1]]
3438
inner[indices[-1]] <<= value
35-
return inner[indices[-1]]
39+
return old_result
3640

3741

3842
def atomic_fetch_max(
@@ -55,42 +59,48 @@ def atomic_fetch_min(
5559

5660
def atomic_fetch_mod(view: View, indices: List[int], value: int) -> int:
5761
inner = reduce(operator.getitem, indices[:-1], view)
62+
old_result = inner[indices[-1]]
5863
inner[indices[-1]] %= value
59-
return inner[indices[-1]]
64+
return old_result
6065

6166

6267
def atomic_fetch_mul(
6368
view: View, indices: List[int], value: Union[int, float]
6469
) -> Union[int, float]:
6570
inner = reduce(operator.getitem, indices[:-1], view)
71+
old_result = inner[indices[-1]]
6672
inner[indices[-1]] *= value
67-
return inner[indices[-1]]
73+
return old_result
6874

6975

7076
def atomic_fetch_or(view: View, indices: List[int], value: int) -> int:
7177
inner = reduce(operator.getitem, indices[:-1], view)
78+
old_result = inner[indices[-1]]
7279
inner[indices[-1]] |= value
73-
return inner[indices[-1]]
80+
return old_result
7481

7582

7683
def atomic_fetch_rshift(view: View, indices: List[int], value: int) -> int:
7784
inner = reduce(operator.getitem, indices[:-1], view)
85+
old_result = inner[indices[-1]]
7886
inner[indices[-1]] >>= value
79-
return inner[indices[-1]]
87+
return old_result
8088

8189

8290
def atomic_fetch_sub(
8391
view: View, indices: List[int], value: Union[int, float]
8492
) -> Union[int, float]:
8593
inner = reduce(operator.getitem, indices[:-1], view)
94+
old_result = inner[indices[-1]]
8695
inner[indices[-1]] -= value
87-
return inner[indices[-1]]
96+
return old_result
8897

8998

9099
def atomic_fetch_xor(view: View, indices: List[int], value: int) -> int:
91100
inner = reduce(operator.getitem, indices[:-1], view)
101+
old_result = inner[indices[-1]]
92102
inner[indices[-1]] ^= value
93-
return inner[indices[-1]]
103+
return old_result
94104

95105

96106
def atomic_compare_exchange(

pykokkos/pykokkos/interface/bin_sort.py

Lines changed: 67 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
from typing import List, Union
1+
from typing import List, Optional, Union
22

3-
from .views import View
3+
import numpy as np
4+
5+
from .views import View, ViewType, array
46

57

68
class BinOp:
@@ -20,11 +22,31 @@ def __init__(
2022
def get_type(dim: int, key_view_type: str) -> str:
2123
return f"Kokkos::BinOp{dim}D<{key_view_type}>"
2224

25+
def _keys_array(self) -> np.ndarray:
26+
return self.keys.data if isinstance(self.keys, ViewType) else np.asarray(self.keys)
27+
28+
def num_bins(self) -> int:
29+
raise NotImplementedError
30+
31+
def bin_indices(self) -> np.ndarray:
32+
"""Flat bin index per key, used by the interpreted (Debug) execution path."""
33+
raise NotImplementedError
34+
2335

2436
class BinOp1D(BinOp):
2537
def __init__(self, keys: View, max_bins: int, min_value: float, max_value: float):
2638
super().__init__(keys, max_bins, min_value, max_value)
2739

40+
def num_bins(self) -> int:
41+
return self.max_bins
42+
43+
def bin_indices(self) -> np.ndarray:
44+
keys_arr = self._keys_array()
45+
span = self.max_value - self.min_value
46+
scale = self.max_bins / span if span > 0 else 0.0
47+
idx = np.floor((keys_arr - self.min_value) * scale).astype(np.int64)
48+
return np.clip(idx, 0, self.max_bins - 1)
49+
2850

2951
class BinOp3D(BinOp):
3052
def __init__(
@@ -36,28 +58,66 @@ def __init__(
3658
):
3759
super().__init__(keys, max_bins, min_value, max_value)
3860

61+
def num_bins(self) -> int:
62+
nbx, nby, nbz = self.max_bins
63+
return nbx * nby * nbz
64+
65+
def bin_indices(self) -> np.ndarray:
66+
"""Row-major flat index: ix * nby * nbz + iy * nbz + iz."""
67+
keys_arr = self._keys_array()
68+
nbx, nby, nbz = self.max_bins
69+
idx3 = np.empty((keys_arr.shape[0], 3), dtype=np.int64)
70+
for d, n in enumerate((nbx, nby, nbz)):
71+
span = self.max_value[d] - self.min_value[d]
72+
scale = n / span if span > 0 else 0.0
73+
col = np.floor((keys_arr[:, d] - self.min_value[d]) * scale).astype(np.int64)
74+
idx3[:, d] = np.clip(col, 0, n - 1)
75+
return idx3[:, 0] * (nby * nbz) + idx3[:, 1] * nbz + idx3[:, 2]
76+
3977

4078
class BinSort:
4179
def __init__(self, keys: View, bin_op: BinOp, sort_within_bins: bool = False):
4280
self.keys = keys
4381
self.bin_op = bin_op
4482
self.sort_within_bins = sort_within_bins
83+
self._permute_vector: Optional[np.ndarray] = None
84+
self._bin_count: Optional[np.ndarray] = None
85+
self._bin_offsets: Optional[np.ndarray] = None
4586

4687
@staticmethod
4788
def get_type(key_view_type: str, bin_op_type: str, space: str) -> str:
4889
return f"Kokkos::BinSort<{key_view_type},{bin_op_type},{space},int>"
4990

5091
def sort(self, values: View) -> None:
51-
pass
92+
if self._permute_vector is None:
93+
raise RuntimeError("create_permute_vector() must be called before sort()")
94+
data = values.data if isinstance(values, ViewType) else values
95+
n = len(self._permute_vector)
96+
data[:n] = data[:n][self._permute_vector]
5297

5398
def get_bin_count(self) -> View:
54-
pass
99+
return array(self._bin_count)
55100

56101
def get_bin_offsets(self) -> View:
57-
pass
102+
return array(self._bin_offsets)
58103

59104
def get_permute_vector(self) -> View:
60-
pass
105+
return array(self._permute_vector)
61106

62107
def create_permute_vector(self) -> None:
63-
pass
108+
"""Counting sort by bin index (interpreted-execution fallback for Kokkos::BinSort)."""
109+
bin_ids = self.bin_op.bin_indices()
110+
n_bins = self.bin_op.num_bins()
111+
112+
counts = np.bincount(bin_ids, minlength=n_bins).astype(np.int32)
113+
offsets = np.zeros(n_bins, dtype=np.int32)
114+
if n_bins > 1:
115+
offsets[1:] = np.cumsum(counts)[:-1]
116+
117+
# Stable sort so ties (same bin) keep their original relative order,
118+
# matching sort_within_bins=False semantics.
119+
order = np.argsort(bin_ids, kind="stable").astype(np.int32)
120+
121+
self._bin_count = counts
122+
self._bin_offsets = offsets
123+
self._permute_vector = order

pykokkos/pykokkos/interface/execution_policy.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,12 @@ def __init__(self, *args):
145145
unpacked: Tuple = tuple(args)
146146

147147
if len(unpacked) == 2:
148-
space = km.get_execution_space_instance(km.get_default_space())
148+
default_space = km.get_default_space()
149+
space = (
150+
default_space
151+
if default_space is ExecutionSpace.Debug
152+
else km.get_execution_space_instance(default_space)
153+
)
149154
league_size = unpacked[0]
150155
team_size = unpacked[1]
151156
vector_length = -1
@@ -163,7 +168,12 @@ def __init__(self, *args):
163168
team_size = third
164169
vector_length = -1
165170
else:
166-
space = km.get_execution_space_instance(km.get_default_space())
171+
default_space = km.get_default_space()
172+
space = (
173+
default_space
174+
if default_space is ExecutionSpace.Debug
175+
else km.get_execution_space_instance(default_space)
176+
)
167177
league_size = first
168178
team_size = second
169179
vector_length = third
@@ -189,7 +199,8 @@ def __init__(self, *args):
189199
if isinstance(space, ExecutionSpace):
190200
if space is ExecutionSpace.Default:
191201
space = km.get_default_space()
192-
space = ExecutionSpaceInstance(space)
202+
if space is not ExecutionSpace.Debug:
203+
space = ExecutionSpaceInstance(space)
193204

194205
elif not isinstance(space, ExecutionSpaceInstance):
195206
raise TypeError(f"Invalid space argument {space}")

pykokkos/pykokkos/interface/parallel_dispatch.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from pykokkos.core.cppast import BuiltinType
99

1010
from .execution_policy import ExecutionPolicy, RangePolicy
11-
from .execution_space import ExecutionSpace, DeviceExecutionSpace
11+
from .execution_space import ExecutionSpace, ExecutionSpaceInstance, DeviceExecutionSpace
1212
from .views import ViewType, array
1313

1414
from .interface_util import generic_error, get_filename, get_lineno
@@ -195,6 +195,11 @@ def check_workunit(workunit: Any) -> None:
195195
raise TypeError(f"ERROR: {workunit} is not a valid workunit")
196196

197197

198+
def policy_execution_space(policy: ExecutionPolicy) -> ExecutionSpace:
199+
space = policy.space
200+
return space.space if isinstance(space, ExecutionSpaceInstance) else space
201+
202+
198203
def convert_arrays(kwargs: Dict[str, Any], workunit: Callable, execution_space) -> None:
199204
"""
200205
Convert all numpy, cupy and pytorch ndarray objects into pk Views
@@ -303,7 +308,7 @@ def parallel_for(*args, **kwargs) -> None:
303308

304309
kwargs = dict(kwargs)
305310
handled_args: HandledArgs = handle_args(True, args)
306-
convert_arrays(kwargs, handled_args.workunit, handled_args.policy.space.space)
311+
convert_arrays(kwargs, handled_args.workunit, policy_execution_space(handled_args.policy))
307312

308313
runtime_singleton.runtime.run_workunit(
309314
handled_args.name, handled_args.policy, handled_args.workunit, "for", **kwargs
@@ -320,7 +325,7 @@ def reduce_body(operation: str, *args, **kwargs) -> Union[float, int]:
320325

321326
kwargs = dict(kwargs)
322327
handled_args: HandledArgs = handle_args(True, args)
323-
convert_arrays(kwargs, handled_args.workunit, handled_args.policy.space.space)
328+
convert_arrays(kwargs, handled_args.workunit, policy_execution_space(handled_args.policy))
324329

325330
args_to_hash: List = []
326331
args_not_to_hash: Dict = {}

0 commit comments

Comments
 (0)