xobjects 0.5.7__tar.gz → 0.5.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {xobjects-0.5.7 → xobjects-0.5.9}/LICENSE +1 -1
- xobjects-0.5.9/PKG-INFO +39 -0
- xobjects-0.5.9/README.md +10 -0
- xobjects-0.5.9/pyproject.toml +50 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_capi.py +248 -39
- xobjects-0.5.9/tests/test_common.py +179 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_shared_memory.py +1 -1
- xobjects-0.5.9/xobjects/_version.py +1 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/capi.py +80 -17
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/context.py +30 -11
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/context_cpu.py +11 -8
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/context_cupy.py +7 -4
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/context_pyopencl.py +24 -11
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/general.py +1 -2
- xobjects-0.5.9/xobjects.egg-info/PKG-INFO +39 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects.egg-info/SOURCES.txt +3 -0
- xobjects-0.5.9/xobjects.egg-info/entry_points.txt +2 -0
- xobjects-0.5.7/PKG-INFO +0 -22
- xobjects-0.5.7/pyproject.toml +0 -4
- xobjects-0.5.7/xobjects/_version.py +0 -1
- xobjects-0.5.7/xobjects.egg-info/PKG-INFO +0 -22
- {xobjects-0.5.7 → xobjects-0.5.9}/setup.cfg +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/setup.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_align.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_array.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_buffer.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_chunk.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_context_opencl.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_hybrid_class.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_kernel.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_linked_array.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_nplike_arrays.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_ref.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_scalars.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_strides.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_string.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_struct.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_to_dict.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_typeutils.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/tests/test_unionref.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/__init__.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/_patch_pyopencl_array.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/array.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/hybrid_class.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/linkedarray.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/ref.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/scalar.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/specialize_source.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/string.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/struct.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/test_helpers.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/typeutils.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects/union.py +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects.egg-info/dependency_links.txt +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects.egg-info/requires.txt +0 -0
- {xobjects-0.5.7 → xobjects-0.5.9}/xobjects.egg-info/top_level.txt +0 -0
|
@@ -198,4 +198,4 @@
|
|
|
198
198
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
199
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
200
|
See the License for the specific language governing permissions and
|
|
201
|
-
limitations under the License.
|
|
201
|
+
limitations under the License.
|
xobjects-0.5.9/PKG-INFO
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xobjects
|
|
3
|
+
Version: 0.5.9
|
|
4
|
+
Summary: In-memory serialization and code generator for CPU and GPU
|
|
5
|
+
Home-page: https://xsuite.readthedocs.io/
|
|
6
|
+
Download-URL: https://pypi.python.org/pypi/xobjects
|
|
7
|
+
Author: Riccardo De Maria
|
|
8
|
+
Author-email: Riccardo De Maria <riccardo.de.maria@cern.ch>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Project-URL: Homepage, https://xsuite.readthedocs.io/
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/xsuite/xsuite/issues
|
|
12
|
+
Project-URL: Documentation, https://xsuite.readthedocs.io/
|
|
13
|
+
Project-URL: Source Code, https://github.com/xsuite/xobjects
|
|
14
|
+
Project-URL: Download, https://pypi.python.org/pypi/xobjects
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
Requires-Dist: cffi
|
|
20
|
+
Requires-Dist: scipy
|
|
21
|
+
Provides-Extra: tests
|
|
22
|
+
Requires-Dist: pytest; extra == "tests"
|
|
23
|
+
Requires-Dist: pytest-mock; extra == "tests"
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: download-url
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
|
|
30
|
+
# XObjects
|
|
31
|
+
|
|
32
|
+
Library to create and manipulate serialized object in CPU and GPU memory efficiently.
|
|
33
|
+
|
|
34
|
+
The library defines:
|
|
35
|
+
- Contexts: create buffers and manage computations e.g. BytearrayContext, CLContext, ...
|
|
36
|
+
- Buffers: reference to internal memory buffer with an allocator e.g.
|
|
37
|
+
BytearrayContext, CLBuffer, ...
|
|
38
|
+
- Data types: define users define types to create and manipulate objects on
|
|
39
|
+
buffers and generate C api, e.g. Float64, Int64, String, Struct, Array, Union
|
xobjects-0.5.9/README.md
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# XObjects
|
|
2
|
+
|
|
3
|
+
Library to create and manipulate serialized object in CPU and GPU memory efficiently.
|
|
4
|
+
|
|
5
|
+
The library defines:
|
|
6
|
+
- Contexts: create buffers and manage computations e.g. BytearrayContext, CLContext, ...
|
|
7
|
+
- Buffers: reference to internal memory buffer with an allocator e.g.
|
|
8
|
+
BytearrayContext, CLBuffer, ...
|
|
9
|
+
- Data types: define users define types to create and manipulate objects on
|
|
10
|
+
buffers and generate C api, e.g. Float64, Int64, String, Struct, Array, Union
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = [
|
|
3
|
+
"setuptools>=77.0"
|
|
4
|
+
]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "xobjects"
|
|
9
|
+
dynamic = ["version"]
|
|
10
|
+
description = "In-memory serialization and code generator for CPU and GPU"
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Riccardo De Maria", email = "riccardo.de.maria@cern.ch" }
|
|
14
|
+
]
|
|
15
|
+
license = "Apache-2.0"
|
|
16
|
+
requires-python = ">=3.9"
|
|
17
|
+
dependencies = [
|
|
18
|
+
"numpy",
|
|
19
|
+
"cffi",
|
|
20
|
+
"scipy"
|
|
21
|
+
]
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://xsuite.readthedocs.io/"
|
|
24
|
+
"Bug Tracker" = "https://github.com/xsuite/xsuite/issues"
|
|
25
|
+
Documentation = "https://xsuite.readthedocs.io/"
|
|
26
|
+
"Source Code" = "https://github.com/xsuite/xobjects"
|
|
27
|
+
"Download" = "https://pypi.python.org/pypi/xobjects"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
tests = ["pytest", "pytest-mock"]
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["."]
|
|
34
|
+
include = ["xobjects*"]
|
|
35
|
+
|
|
36
|
+
[tool.setuptools.dynamic]
|
|
37
|
+
version = {attr = "xobjects._version.__version__"}
|
|
38
|
+
|
|
39
|
+
[tool.black]
|
|
40
|
+
line-length = 79
|
|
41
|
+
target-version = ['py310', 'py311', 'py312']
|
|
42
|
+
include = '\.pyi?$'
|
|
43
|
+
|
|
44
|
+
[project.entry-points.xobjects]
|
|
45
|
+
include = "xobjects"
|
|
46
|
+
|
|
47
|
+
[pytest]
|
|
48
|
+
markers = [
|
|
49
|
+
"context_dependent: marks test as one that depends on the execution context",
|
|
50
|
+
]
|
|
@@ -11,7 +11,7 @@ import numpy as np
|
|
|
11
11
|
import cffi
|
|
12
12
|
|
|
13
13
|
import xobjects as xo
|
|
14
|
-
|
|
14
|
+
from xobjects.test_helpers import for_all_test_contexts
|
|
15
15
|
|
|
16
16
|
ffi = cffi.FFI()
|
|
17
17
|
|
|
@@ -158,6 +158,70 @@ def test_array_dynamic_type_init_get_set(array_cls, example_shape):
|
|
|
158
158
|
assert arr[ii].field1[idx_in_field] == 13 * vv
|
|
159
159
|
|
|
160
160
|
|
|
161
|
+
@for_all_test_contexts
|
|
162
|
+
@pytest.mark.parametrize(
|
|
163
|
+
"array_type",
|
|
164
|
+
[
|
|
165
|
+
xo.UInt64[3, 5, 7],
|
|
166
|
+
xo.UInt64[:, :, :],
|
|
167
|
+
xo.UInt64[:, 5, :],
|
|
168
|
+
],
|
|
169
|
+
)
|
|
170
|
+
def test_array_get_shape(test_context, array_type):
|
|
171
|
+
source = """
|
|
172
|
+
#include "xobjects/headers/common.h"
|
|
173
|
+
|
|
174
|
+
GPUKERN void get_nd_and_shape(
|
|
175
|
+
ARRAY_TYPE arr,
|
|
176
|
+
GPUGLMEM int64_t* out_nd,
|
|
177
|
+
GPUGLMEM int64_t* out_shape
|
|
178
|
+
) {
|
|
179
|
+
*out_nd = ARRAY_TYPE_nd(arr);
|
|
180
|
+
ARRAY_TYPE_shape(arr, out_shape);
|
|
181
|
+
}
|
|
182
|
+
""".replace(
|
|
183
|
+
"ARRAY_TYPE", array_type.__name__
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
kernels = {
|
|
187
|
+
"get_nd_and_shape": xo.Kernel(
|
|
188
|
+
c_name="get_nd_and_shape",
|
|
189
|
+
args=[
|
|
190
|
+
xo.Arg(array_type, name="arr"),
|
|
191
|
+
xo.Arg(xo.Int64, pointer=True, name="out_nd"),
|
|
192
|
+
xo.Arg(xo.Int64, pointer=True, name="out_shape"),
|
|
193
|
+
],
|
|
194
|
+
),
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
test_context.add_kernels(
|
|
198
|
+
sources=[source],
|
|
199
|
+
kernels=kernels,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
instance = array_type(
|
|
203
|
+
np.array(range(3 * 5 * 7)).reshape((3, 5, 7)),
|
|
204
|
+
_context=test_context,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
expected_nd = 3
|
|
208
|
+
result_nd = test_context.zeros((1,), dtype=np.int64)
|
|
209
|
+
|
|
210
|
+
expected_shape = [3, 5, 7]
|
|
211
|
+
result_shape = test_context.zeros((expected_nd,), dtype=np.int64)
|
|
212
|
+
|
|
213
|
+
test_context.kernels.get_nd_and_shape(
|
|
214
|
+
arr=instance,
|
|
215
|
+
out_nd=result_nd,
|
|
216
|
+
out_shape=result_shape,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
assert result_nd[0] == expected_nd
|
|
220
|
+
assert result_shape[0] == expected_shape[0]
|
|
221
|
+
assert result_shape[1] == expected_shape[1]
|
|
222
|
+
assert result_shape[2] == expected_shape[2]
|
|
223
|
+
|
|
224
|
+
|
|
161
225
|
def test_struct1():
|
|
162
226
|
kernels = Struct1._gen_kernels()
|
|
163
227
|
ctx = xo.ContextCpu()
|
|
@@ -539,45 +603,190 @@ def test_getp1_dyn_length_dyn_type_string_array():
|
|
|
539
603
|
assert ord(ffi.cast("char *", s2)[8 + ii]) == ch
|
|
540
604
|
|
|
541
605
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
606
|
+
@for_all_test_contexts
|
|
607
|
+
def test_gpu_api(test_context):
|
|
608
|
+
src_code = """
|
|
609
|
+
/*gpufun*/
|
|
610
|
+
void myfun(double x, double y,
|
|
611
|
+
double* z){
|
|
612
|
+
z[0] = x * y;
|
|
613
|
+
}
|
|
550
614
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
615
|
+
/*gpukern*/
|
|
616
|
+
void my_mul(const int n,
|
|
617
|
+
/*gpuglmem*/ const double* x1,
|
|
618
|
+
/*gpuglmem*/ const double* x2,
|
|
619
|
+
/*gpuglmem*/ double* y) {
|
|
620
|
+
int tid = 0 //vectorize_over tid n
|
|
621
|
+
double z;
|
|
622
|
+
myfun(x1[tid], x2[tid], &z);
|
|
623
|
+
y[tid] = z;
|
|
624
|
+
//end_vectorize
|
|
625
|
+
}
|
|
626
|
+
"""
|
|
627
|
+
|
|
628
|
+
kernel_descriptions = {
|
|
629
|
+
"my_mul": xo.Kernel(
|
|
630
|
+
args=[
|
|
631
|
+
xo.Arg(xo.Int32, name="n"),
|
|
632
|
+
xo.Arg(xo.Float64, pointer=True, const=True, name="x1"),
|
|
633
|
+
xo.Arg(xo.Float64, pointer=True, const=True, name="x2"),
|
|
634
|
+
xo.Arg(xo.Float64, pointer=True, const=False, name="y"),
|
|
635
|
+
],
|
|
636
|
+
n_threads="n",
|
|
637
|
+
),
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
test_context.add_kernels(
|
|
641
|
+
sources=[src_code],
|
|
642
|
+
kernels=kernel_descriptions,
|
|
643
|
+
save_source_as=None,
|
|
644
|
+
compile=True,
|
|
645
|
+
extra_classes=[xo.String[:]],
|
|
646
|
+
)
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
@for_all_test_contexts
|
|
650
|
+
def test_array_of_arrays(test_context):
|
|
651
|
+
cell_ids = [3, 5, 7]
|
|
652
|
+
particle_per_cell = [
|
|
653
|
+
[1, 8],
|
|
654
|
+
[9, 3, 2],
|
|
655
|
+
[4, 5, 6, 7],
|
|
656
|
+
]
|
|
657
|
+
|
|
658
|
+
class Cells(xo.Struct):
|
|
659
|
+
ids = xo.Int64[:]
|
|
660
|
+
particles = xo.Int64[:][:]
|
|
661
|
+
|
|
662
|
+
cells = Cells(
|
|
663
|
+
ids=cell_ids, particles=particle_per_cell, _context=test_context
|
|
664
|
+
)
|
|
665
|
+
|
|
666
|
+
# Data layout (displayed as uint64):
|
|
667
|
+
#
|
|
668
|
+
# [0] 216 (cells size)
|
|
669
|
+
# [8] 56 (offset field 2 -- particles field)
|
|
670
|
+
# [16] cell_ids data:
|
|
671
|
+
# [0] 40 (cell_ids size)
|
|
672
|
+
# [8] 3 (cell_ids length)
|
|
673
|
+
# [16] {3, 5, 7} (cell_ids elements)
|
|
674
|
+
# [56] particles data:
|
|
675
|
+
# [0] 160 (particles size)
|
|
676
|
+
# [8] 3 (particles length)
|
|
677
|
+
# [16] 40 (offset particles[0])
|
|
678
|
+
# [24] 72 (offset particles[1])
|
|
679
|
+
# [32] 112 (offset particles[2])
|
|
680
|
+
# [40] particles[0] data:
|
|
681
|
+
# [0] 32 (particles[0] size)
|
|
682
|
+
# [8] 2 (particles[0] length)
|
|
683
|
+
# [16] {1, 8} (particles[0] elements)
|
|
684
|
+
# [72] particles[1] data:
|
|
685
|
+
# [0] 40 (particles[1] size)
|
|
686
|
+
# [8] 3 (particles[1] length)
|
|
687
|
+
# [16] {9, 3, 2} (particles[1
|
|
688
|
+
# [112] particles[2] data:
|
|
689
|
+
# [0] 48 (particles[2] size)
|
|
690
|
+
# [8] 4 (particles[2] length)
|
|
691
|
+
# [16] {4, 5, 6, 7} (particles[2] elements)
|
|
692
|
+
|
|
693
|
+
src = r"""
|
|
694
|
+
#include "xobjects/headers/common.h"
|
|
695
|
+
|
|
696
|
+
static const int MAX_PARTICLES = 4;
|
|
697
|
+
static const int MAX_CELLS = 3;
|
|
698
|
+
|
|
699
|
+
GPUKERN void loop_over(
|
|
700
|
+
Cells cells,
|
|
701
|
+
GPUGLMEM uint64_t* out_counts,
|
|
702
|
+
GPUGLMEM uint64_t* out_vals,
|
|
703
|
+
GPUGLMEM uint8_t* success
|
|
704
|
+
)
|
|
705
|
+
{
|
|
706
|
+
int64_t num_cells = Cells_len_ids(cells);
|
|
707
|
+
|
|
708
|
+
for (int64_t i = 0; i < num_cells; i++) {
|
|
709
|
+
int64_t id = Cells_get_ids(cells, i);
|
|
710
|
+
int64_t count = Cells_len1_particles(cells, i);
|
|
711
|
+
|
|
712
|
+
if (i >= MAX_CELLS) {
|
|
713
|
+
*success = 0;
|
|
714
|
+
continue;
|
|
561
715
|
}
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
716
|
+
|
|
717
|
+
out_counts[i] = count;
|
|
718
|
+
|
|
719
|
+
ArrNInt64 particles = Cells_getp1_particles(cells, i);
|
|
720
|
+
uint32_t num_particles = ArrNInt64_len(particles);
|
|
721
|
+
|
|
722
|
+
VECTORIZE_OVER(j, num_particles);
|
|
723
|
+
int64_t val = ArrNInt64_get(particles, j);
|
|
724
|
+
|
|
725
|
+
if (j >= MAX_PARTICLES) {
|
|
726
|
+
*success = 0;
|
|
727
|
+
} else {
|
|
728
|
+
out_vals[i * MAX_PARTICLES + j] = val;
|
|
729
|
+
}
|
|
730
|
+
END_VECTORIZE;
|
|
574
731
|
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
GPUKERN void kernel_Cells_get_particles(
|
|
735
|
+
Cells obj,
|
|
736
|
+
int64_t i0,
|
|
737
|
+
int64_t i1,
|
|
738
|
+
GPUGLMEM int64_t* out
|
|
739
|
+
) {
|
|
740
|
+
*out = Cells_get_particles(obj, i0, i1);
|
|
741
|
+
}
|
|
742
|
+
"""
|
|
743
|
+
|
|
744
|
+
kernels = {
|
|
745
|
+
"loop_over": xo.Kernel(
|
|
746
|
+
args=[
|
|
747
|
+
xo.Arg(Cells, name="cells"),
|
|
748
|
+
xo.Arg(xo.UInt64, pointer=True, name="out_counts"),
|
|
749
|
+
xo.Arg(xo.UInt64, pointer=True, name="out_vals"),
|
|
750
|
+
xo.Arg(xo.UInt8, pointer=True, name="success"),
|
|
751
|
+
],
|
|
752
|
+
n_threads=4,
|
|
753
|
+
),
|
|
754
|
+
"kernel_Cells_get_particles": xo.Kernel(
|
|
755
|
+
args=[
|
|
756
|
+
xo.Arg(Cells, name="obj"),
|
|
757
|
+
xo.Arg(xo.Int64, name="i0"),
|
|
758
|
+
xo.Arg(xo.Int64, name="i1"),
|
|
759
|
+
xo.Arg(xo.Int64, pointer=True, name="out"),
|
|
760
|
+
],
|
|
761
|
+
),
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
test_context.add_kernels(
|
|
765
|
+
sources=[src],
|
|
766
|
+
kernels=kernels,
|
|
767
|
+
)
|
|
575
768
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
769
|
+
counts = test_context.zeros(len(cell_ids), dtype=np.uint64)
|
|
770
|
+
vals = test_context.zeros(12, dtype=np.uint64)
|
|
771
|
+
success = test_context.zeros((1,), dtype=np.uint8) + 1
|
|
772
|
+
|
|
773
|
+
for i, _ in enumerate(particle_per_cell):
|
|
774
|
+
for j, expected in enumerate(particle_per_cell[i]):
|
|
775
|
+
result = test_context.zeros(shape=(1,), dtype=np.int64)
|
|
776
|
+
test_context.kernels.kernel_Cells_get_particles(
|
|
777
|
+
obj=cells, i0=i, i1=j, out=result
|
|
778
|
+
)
|
|
779
|
+
assert result[0] == expected
|
|
780
|
+
|
|
781
|
+
test_context.kernels.loop_over(
|
|
782
|
+
cells=cells,
|
|
783
|
+
out_counts=counts,
|
|
784
|
+
out_vals=vals,
|
|
785
|
+
success=success,
|
|
786
|
+
)
|
|
787
|
+
counts = test_context.nparray_from_context_array(counts)
|
|
788
|
+
vals = test_context.nparray_from_context_array(vals)
|
|
789
|
+
|
|
790
|
+
assert success[0] == 1
|
|
791
|
+
assert np.all(counts == [2, 3, 4])
|
|
792
|
+
assert np.all(vals == [1, 8, 0, 0, 9, 3, 2, 0, 4, 5, 6, 7])
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# copyright ################################# #
|
|
2
|
+
# This file is part of the Xobjects Package. #
|
|
3
|
+
# Copyright (c) CERN, 2025. #
|
|
4
|
+
# ########################################### #
|
|
5
|
+
|
|
6
|
+
import xobjects as xo
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
from xobjects.test_helpers import for_all_test_contexts
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@for_all_test_contexts
|
|
14
|
+
def test_common_atomicadd(test_context):
|
|
15
|
+
src = r"""
|
|
16
|
+
#include "xobjects/headers/common.h"
|
|
17
|
+
#include "xobjects/headers/atomicadd.h"
|
|
18
|
+
|
|
19
|
+
GPUKERN void test_atomic_add(GPUGLMEM double* out, int32_t iterations)
|
|
20
|
+
{
|
|
21
|
+
VECTORIZE_OVER(i, iterations);
|
|
22
|
+
// If on CPU do some work to avoid the loop being optimized out
|
|
23
|
+
#if defined(XO_CONTEXT_CPU_OPENMP)
|
|
24
|
+
usleep(10);
|
|
25
|
+
#endif
|
|
26
|
+
atomicAdd(out, 1.0);
|
|
27
|
+
END_VECTORIZE;
|
|
28
|
+
}
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
n_threads = 1
|
|
32
|
+
if type(test_context).__name__ in {"ContextCupy", "ContextPyopencl"}:
|
|
33
|
+
n_threads = 1000
|
|
34
|
+
elif (
|
|
35
|
+
test_context.omp_num_threads == "auto"
|
|
36
|
+
or test_context.omp_num_threads > 1
|
|
37
|
+
):
|
|
38
|
+
n_threads = 8
|
|
39
|
+
|
|
40
|
+
test_context.add_kernels(
|
|
41
|
+
sources=[src],
|
|
42
|
+
kernels={
|
|
43
|
+
"test_atomic_add": xo.Kernel(
|
|
44
|
+
c_name="test_atomic_add",
|
|
45
|
+
args=[
|
|
46
|
+
xo.Arg(xo.Float64, pointer=True, name="out"),
|
|
47
|
+
xo.Arg(xo.Int32, name="iterations"),
|
|
48
|
+
],
|
|
49
|
+
n_threads=n_threads,
|
|
50
|
+
)
|
|
51
|
+
},
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
expected = 1000
|
|
55
|
+
result = np.array([0], dtype=np.float64)
|
|
56
|
+
result_ctx = test_context.nparray_to_context_array(result)
|
|
57
|
+
test_context.kernels.test_atomic_add(out=result_ctx, iterations=expected)
|
|
58
|
+
result = test_context.nparray_from_context_array(result_ctx)
|
|
59
|
+
|
|
60
|
+
assert result == expected
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@for_all_test_contexts
|
|
64
|
+
@pytest.mark.parametrize(
|
|
65
|
+
"overload", [True, False], ids=["overload", "no_overload"]
|
|
66
|
+
)
|
|
67
|
+
@pytest.mark.parametrize(
|
|
68
|
+
"ctype",
|
|
69
|
+
[
|
|
70
|
+
xo.Int8,
|
|
71
|
+
xo.Int16,
|
|
72
|
+
xo.Int32,
|
|
73
|
+
xo.Int64,
|
|
74
|
+
xo.UInt8,
|
|
75
|
+
xo.UInt16,
|
|
76
|
+
xo.UInt32,
|
|
77
|
+
xo.UInt64,
|
|
78
|
+
xo.Float32,
|
|
79
|
+
xo.Float64,
|
|
80
|
+
],
|
|
81
|
+
)
|
|
82
|
+
def test_atomic(overload, ctype, test_context):
|
|
83
|
+
if overload:
|
|
84
|
+
func_name = "atomicAdd"
|
|
85
|
+
else:
|
|
86
|
+
func_name = f'atomicAdd_{ctype.__name__.lower()[0]}{ctype.__name__.split("t")[1]}'
|
|
87
|
+
|
|
88
|
+
class TestAtomic(xo.Struct):
|
|
89
|
+
val = ctype
|
|
90
|
+
_extra_c_sources = [
|
|
91
|
+
f"""
|
|
92
|
+
#include "xobjects/headers/common.h"
|
|
93
|
+
#include "xobjects/headers/atomicadd.h"
|
|
94
|
+
|
|
95
|
+
GPUKERN
|
|
96
|
+
void run_atomic_test(TestAtomic el, GPUGLMEM {ctype._c_type}* increments,
|
|
97
|
+
GPUGLMEM {ctype._c_type}* retvals, int length) {{
|
|
98
|
+
VECTORIZE_OVER(ii, length);
|
|
99
|
+
GPUGLMEM {ctype._c_type}* val = TestAtomic_getp_val(el);
|
|
100
|
+
{ctype._c_type} ret = {func_name}(val, increments[ii]);
|
|
101
|
+
retvals[ii] = ret;
|
|
102
|
+
END_VECTORIZE;
|
|
103
|
+
}}
|
|
104
|
+
"""
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
kernels = {
|
|
108
|
+
"run_atomic_test": xo.Kernel(
|
|
109
|
+
c_name="run_atomic_test",
|
|
110
|
+
args=[
|
|
111
|
+
xo.Arg(TestAtomic, name="el"),
|
|
112
|
+
xo.Arg(ctype, pointer=True, name="increments"),
|
|
113
|
+
xo.Arg(ctype, pointer=True, name="retvals"),
|
|
114
|
+
xo.Arg(xo.Int32, name="length"),
|
|
115
|
+
],
|
|
116
|
+
n_threads="length",
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
atomic = TestAtomic(_context=test_context, val=0)
|
|
121
|
+
assert atomic.val == 0
|
|
122
|
+
|
|
123
|
+
test_context.add_kernels(kernels=kernels)
|
|
124
|
+
|
|
125
|
+
# Test with all increments = 1, so we can check the return values easily.
|
|
126
|
+
num_steps = 10000
|
|
127
|
+
if ctype.__name__.startswith("Int") or ctype.__name__.startswith("Uint"):
|
|
128
|
+
# Less steps to avoid overflow
|
|
129
|
+
num_steps = min(num_steps, 2 ** (8 * ctype._size - 1) - 1)
|
|
130
|
+
increments = test_context.zeros(shape=(num_steps,), dtype=ctype._dtype) + 1
|
|
131
|
+
retvals = test_context.zeros(shape=(num_steps,), dtype=ctype._dtype)
|
|
132
|
+
test_context.kernels.run_atomic_test(
|
|
133
|
+
el=atomic, increments=increments, retvals=retvals, length=num_steps
|
|
134
|
+
)
|
|
135
|
+
assert atomic.val == num_steps
|
|
136
|
+
retvals = np.sort(test_context.nparray_from_context_array(retvals))
|
|
137
|
+
assert np.allclose(
|
|
138
|
+
retvals,
|
|
139
|
+
np.arange(num_steps, dtype=ctype._dtype),
|
|
140
|
+
atol=1.0e-15,
|
|
141
|
+
rtol=1.0e-15,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
# Test with random increments, where we now only can check the total sum
|
|
145
|
+
# (retvals can be anything). Watch out: overflow is undefined behaviour,
|
|
146
|
+
# except for unsigned integers, so we skip this test for signed integers.
|
|
147
|
+
atomic.val = 0
|
|
148
|
+
retvals = test_context.zeros(shape=(num_steps,), dtype=ctype._dtype)
|
|
149
|
+
if ctype.__name__.startswith("Uint"):
|
|
150
|
+
low = 0
|
|
151
|
+
high = 2 ** (8 * ctype._size) - 1
|
|
152
|
+
increments = np.random.randint(
|
|
153
|
+
low, high + 1, size=num_steps, dtype=ctype._dtype
|
|
154
|
+
)
|
|
155
|
+
increments = test_context.nparray_to_context_array(increments)
|
|
156
|
+
test_context.kernels.run_atomic_test(
|
|
157
|
+
el=atomic, increments=increments, retvals=retvals, length=num_steps
|
|
158
|
+
)
|
|
159
|
+
increments = test_context.nparray_from_context_array(increments)
|
|
160
|
+
assert atomic.val == (
|
|
161
|
+
np.sum(increments).item() % (2 ** (8 * ctype._size))
|
|
162
|
+
)
|
|
163
|
+
|
|
164
|
+
elif ctype.__name__.startswith("Float"):
|
|
165
|
+
increments = np.zeros(shape=(num_steps,), dtype=ctype._dtype)
|
|
166
|
+
increments += np.random.uniform(0, 10, size=num_steps)
|
|
167
|
+
increments = test_context.nparray_to_context_array(increments)
|
|
168
|
+
test_context.kernels.run_atomic_test(
|
|
169
|
+
el=atomic, increments=increments, retvals=retvals, length=num_steps
|
|
170
|
+
)
|
|
171
|
+
increments = test_context.nparray_from_context_array(increments)
|
|
172
|
+
if ctype == xo.Float32:
|
|
173
|
+
assert np.isclose(
|
|
174
|
+
atomic.val, np.sum(increments), atol=10.0, rtol=1.0e-4
|
|
175
|
+
)
|
|
176
|
+
else:
|
|
177
|
+
assert np.isclose(
|
|
178
|
+
atomic.val, np.sum(increments), atol=1.0e-6, rtol=1.0e-12
|
|
179
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.5.9"
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
from .context import Kernel, Arg
|
|
7
7
|
|
|
8
|
-
from .scalar import Int64, Void,
|
|
8
|
+
from .scalar import UInt32, Int64, Void, is_scalar
|
|
9
9
|
from .struct import is_field, is_struct
|
|
10
10
|
from .array import is_index, is_array
|
|
11
11
|
from .ref import is_unionref, is_ref
|
|
@@ -103,9 +103,10 @@ def get_layers(parts):
|
|
|
103
103
|
|
|
104
104
|
|
|
105
105
|
def int_from_obj(offset, conf):
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
"""Generate code to read the integer at location obj + offset (bytes)."""
|
|
107
|
+
int_pointer_type = gen_pointer(conf.get("inttype", "int64_t") + "*", conf)
|
|
108
|
+
char_pointer_type = gen_pointer(conf.get("chartype", "char") + "*", conf)
|
|
109
|
+
return f"*({int_pointer_type})(({char_pointer_type}) obj+{offset})"
|
|
109
110
|
|
|
110
111
|
|
|
111
112
|
def Field_get_c_offset(self, conf):
|
|
@@ -146,7 +147,7 @@ def Index_get_c_offset(part, conf, icount):
|
|
|
146
147
|
out.append(f" offset+={soffset};")
|
|
147
148
|
else:
|
|
148
149
|
lookup_field_offset = f"offset+{soffset}"
|
|
149
|
-
out.append(f" offset
|
|
150
|
+
out.append(f" offset+={int_from_obj(lookup_field_offset, conf)};")
|
|
150
151
|
return out
|
|
151
152
|
|
|
152
153
|
|
|
@@ -206,16 +207,17 @@ def gen_fun_kernel(cls, path, action, const, extra, ret, add_nindex=False):
|
|
|
206
207
|
def gen_c_pointed(target: Arg, conf):
|
|
207
208
|
size = gen_c_size_from_arg(target, conf)
|
|
208
209
|
ret = gen_c_type_from_arg(target, conf)
|
|
210
|
+
|
|
209
211
|
if target.pointer or is_compound(target.atype) or is_string(target.atype):
|
|
210
212
|
chartype = gen_pointer(conf.get("chartype", "char") + "*", conf)
|
|
211
213
|
return f"({ret})(({chartype}) obj+offset)"
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
214
|
+
|
|
215
|
+
rettype = gen_pointer(ret + "*", conf)
|
|
216
|
+
if size == 1:
|
|
217
|
+
return f"*(({rettype}) obj+offset)"
|
|
218
|
+
|
|
219
|
+
chartype = gen_pointer(conf.get("chartype", "char") + "*", conf)
|
|
220
|
+
return f"*({rettype})(({chartype}) obj+offset)"
|
|
219
221
|
|
|
220
222
|
|
|
221
223
|
def gen_method_get(cls, path, conf):
|
|
@@ -364,13 +366,74 @@ def gen_method_size(cls, path, conf):
|
|
|
364
366
|
|
|
365
367
|
|
|
366
368
|
def gen_method_shape(cls, path, conf):
|
|
367
|
-
|
|
368
|
-
|
|
369
|
+
array_type = path[-1]
|
|
370
|
+
|
|
371
|
+
out_shape_arg = Arg(Int64, name="out_shape", pointer=True)
|
|
372
|
+
|
|
373
|
+
kernel = gen_fun_kernel(
|
|
374
|
+
cls,
|
|
375
|
+
path,
|
|
376
|
+
const=False,
|
|
377
|
+
action="shape",
|
|
378
|
+
extra=[out_shape_arg],
|
|
379
|
+
ret=None,
|
|
380
|
+
add_nindex=True,
|
|
381
|
+
)
|
|
382
|
+
decl = gen_c_decl_from_kernel(kernel, conf)
|
|
383
|
+
|
|
384
|
+
lst = [decl + "{"]
|
|
385
|
+
|
|
386
|
+
nd = len(array_type._shape)
|
|
387
|
+
|
|
388
|
+
if array_type._is_static_shape:
|
|
389
|
+
terms = [str(dim) for dim in array_type._shape]
|
|
390
|
+
else:
|
|
391
|
+
lst.append(gen_method_offset(path, conf))
|
|
392
|
+
arrarg = Arg(Int64, pointer=True)
|
|
393
|
+
pointed = gen_c_pointed(arrarg, conf)
|
|
394
|
+
typearr = gen_pointer("int64_t*", conf)
|
|
395
|
+
lst.append(f" {typearr} arr = {pointed};")
|
|
396
|
+
dim_len_idx = 1
|
|
397
|
+
terms = []
|
|
398
|
+
for dim_len in array_type._shape:
|
|
399
|
+
if dim_len:
|
|
400
|
+
terms.append(str(dim_len))
|
|
401
|
+
else:
|
|
402
|
+
terms.append(f"arr[{dim_len_idx}]")
|
|
403
|
+
dim_len_idx += 1
|
|
404
|
+
|
|
405
|
+
for dim_idx in range(nd):
|
|
406
|
+
lst.append(f" out_shape[{dim_idx}] = {terms[dim_idx]};")
|
|
407
|
+
|
|
408
|
+
lst.append("}")
|
|
409
|
+
|
|
410
|
+
return "\n".join(lst), kernel
|
|
369
411
|
|
|
370
412
|
|
|
371
413
|
def gen_method_nd(cls, path, conf):
|
|
372
414
|
"return length of shape"
|
|
373
|
-
|
|
415
|
+
array_type = path[-1]
|
|
416
|
+
|
|
417
|
+
retarg = Arg(UInt32)
|
|
418
|
+
|
|
419
|
+
kernel = gen_fun_kernel(
|
|
420
|
+
cls,
|
|
421
|
+
path,
|
|
422
|
+
const=False,
|
|
423
|
+
action="nd",
|
|
424
|
+
extra=[],
|
|
425
|
+
ret=retarg,
|
|
426
|
+
add_nindex=True,
|
|
427
|
+
)
|
|
428
|
+
decl = gen_c_decl_from_kernel(kernel, conf)
|
|
429
|
+
|
|
430
|
+
lst = [decl + "{"]
|
|
431
|
+
|
|
432
|
+
nd = len(array_type._shape)
|
|
433
|
+
lst.append(f" return {nd};")
|
|
434
|
+
lst.append("}")
|
|
435
|
+
|
|
436
|
+
return "\n".join(lst), kernel
|
|
374
437
|
|
|
375
438
|
|
|
376
439
|
def gen_method_strides(cls, path, conf):
|
|
@@ -507,8 +570,8 @@ def methods_from_path(cls, path, conf):
|
|
|
507
570
|
|
|
508
571
|
if is_array(lasttype):
|
|
509
572
|
out.append(gen_method_len(cls, path, conf))
|
|
510
|
-
|
|
511
|
-
|
|
573
|
+
out.append(gen_method_shape(cls, path, conf))
|
|
574
|
+
out.append(gen_method_nd(cls, path, conf))
|
|
512
575
|
# out.append(gen_method_strides(cls, path, conf))
|
|
513
576
|
# out.append(gen_method_getpos(cls, path, conf))
|
|
514
577
|
|
|
@@ -375,12 +375,30 @@ class XContext(ABC):
|
|
|
375
375
|
return sources
|
|
376
376
|
|
|
377
377
|
@abstractmethod
|
|
378
|
-
def nparray_to_context_array(self, arr):
|
|
379
|
-
|
|
378
|
+
def nparray_to_context_array(self, arr, copy=False):
|
|
379
|
+
"""Obtain an array on the context, given a numpy array.
|
|
380
|
+
|
|
381
|
+
Args:
|
|
382
|
+
arr: numpy array
|
|
383
|
+
copy: if True, always create a copy in the context. If False,
|
|
384
|
+
try to avoid copy if possible (not guaranteed).
|
|
385
|
+
|
|
386
|
+
Returns:
|
|
387
|
+
array on the context
|
|
388
|
+
"""
|
|
380
389
|
|
|
381
390
|
@abstractmethod
|
|
382
|
-
def nparray_from_context_array(self, dev_arr):
|
|
383
|
-
|
|
391
|
+
def nparray_from_context_array(self, dev_arr, copy=False):
|
|
392
|
+
"""Obtain a numpy array, given an array on the context.
|
|
393
|
+
|
|
394
|
+
Args:
|
|
395
|
+
arr: array on the context
|
|
396
|
+
copy: if True, always create a copy in the context. If False,
|
|
397
|
+
try to avoid copy if possible (not guaranteed).
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
Numpy array
|
|
401
|
+
"""
|
|
384
402
|
|
|
385
403
|
@property
|
|
386
404
|
@abstractmethod
|
|
@@ -650,14 +668,15 @@ def get_context_from_string(ctxstr):
|
|
|
650
668
|
|
|
651
669
|
if ctxstr is None:
|
|
652
670
|
return xo.ContextCpu()
|
|
671
|
+
|
|
672
|
+
ll = ctxstr.split(":")
|
|
673
|
+
if len(ll) <= 1:
|
|
674
|
+
ctxtype = ll[0]
|
|
675
|
+
option = []
|
|
653
676
|
else:
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
option = []
|
|
658
|
-
else:
|
|
659
|
-
ctxtype, options = ctxstr.split(":")
|
|
660
|
-
option = options.split(",")
|
|
677
|
+
ctxtype, options = ctxstr.split(":")
|
|
678
|
+
option = options.split(",")
|
|
679
|
+
|
|
661
680
|
if ctxtype == "ContextCpu":
|
|
662
681
|
if len(option) == 0:
|
|
663
682
|
return xo.ContextCpu()
|
|
@@ -543,7 +543,7 @@ class ContextCpu(XContext):
|
|
|
543
543
|
|
|
544
544
|
return None
|
|
545
545
|
|
|
546
|
-
def nparray_to_context_array(self, arr):
|
|
546
|
+
def nparray_to_context_array(self, arr, copy=False):
|
|
547
547
|
"""
|
|
548
548
|
Moves a numpy array to the device memory. No action is performed by
|
|
549
549
|
this function in the CPU context. The method is provided
|
|
@@ -551,14 +551,16 @@ class ContextCpu(XContext):
|
|
|
551
551
|
|
|
552
552
|
Args:
|
|
553
553
|
arr (numpy.ndarray): Array to be transferred
|
|
554
|
+
copy (bool): If True, a copy of the array is made.
|
|
554
555
|
|
|
555
556
|
Returns:
|
|
556
|
-
numpy.ndarray:
|
|
557
|
-
|
|
557
|
+
numpy.ndarray: Numpy array with the same data, original or a copy.
|
|
558
558
|
"""
|
|
559
|
+
if copy:
|
|
560
|
+
arr = np.copy(arr)
|
|
559
561
|
return arr
|
|
560
562
|
|
|
561
|
-
def nparray_from_context_array(self, dev_arr):
|
|
563
|
+
def nparray_from_context_array(self, dev_arr, copy=False):
|
|
562
564
|
"""
|
|
563
565
|
Moves an array to the device to a numpy array. No action is performed by
|
|
564
566
|
this function in the CPU context. The method is provided so that the CPU
|
|
@@ -566,10 +568,13 @@ class ContextCpu(XContext):
|
|
|
566
568
|
|
|
567
569
|
Args:
|
|
568
570
|
dev_arr (numpy.ndarray): Array to be transferred
|
|
569
|
-
|
|
570
|
-
numpy.ndarray: The same array (no copy!)
|
|
571
|
+
copy (bool): If True, a copy of the array is made.
|
|
571
572
|
|
|
573
|
+
Returns:
|
|
574
|
+
numpy.ndarray: Numpy array with the same data, original or a copy.
|
|
572
575
|
"""
|
|
576
|
+
if copy:
|
|
577
|
+
dev_arr = np.copy(dev_arr)
|
|
573
578
|
return dev_arr
|
|
574
579
|
|
|
575
580
|
@property
|
|
@@ -579,7 +584,6 @@ class ContextCpu(XContext):
|
|
|
579
584
|
through ``nplike_lib`` to keep compatibility with the other contexts.
|
|
580
585
|
|
|
581
586
|
"""
|
|
582
|
-
|
|
583
587
|
return np
|
|
584
588
|
|
|
585
589
|
@property
|
|
@@ -589,7 +593,6 @@ class ContextCpu(XContext):
|
|
|
589
593
|
through ``splike_lib`` to keep compatibility with the other contexts.
|
|
590
594
|
|
|
591
595
|
"""
|
|
592
|
-
|
|
593
596
|
return sp
|
|
594
597
|
|
|
595
598
|
def synchronize(self):
|
|
@@ -487,29 +487,32 @@ class ContextCupy(XContext):
|
|
|
487
487
|
def __str__(self):
|
|
488
488
|
return f"{type(self).__name__}:{cupy.cuda.get_device_id()}"
|
|
489
489
|
|
|
490
|
-
def nparray_to_context_array(self, arr):
|
|
490
|
+
def nparray_to_context_array(self, arr, copy=False):
|
|
491
491
|
"""
|
|
492
492
|
Copies a numpy array to the device memory.
|
|
493
493
|
|
|
494
494
|
Args:
|
|
495
495
|
arr (numpy.ndarray): Array to be transferred
|
|
496
|
+
copy (bool): This parameter is ignored for CUDA, as the data lives
|
|
497
|
+
on a different device.
|
|
496
498
|
|
|
497
499
|
Returns:
|
|
498
500
|
cupy.ndarray:The same array copied to the device.
|
|
499
|
-
|
|
500
501
|
"""
|
|
501
502
|
dev_arr = cupy.array(arr)
|
|
502
503
|
return dev_arr
|
|
503
504
|
|
|
504
|
-
def nparray_from_context_array(self, dev_arr):
|
|
505
|
+
def nparray_from_context_array(self, dev_arr, copy=False):
|
|
505
506
|
"""
|
|
506
507
|
Copies an array to the device to a numpy array.
|
|
507
508
|
|
|
508
509
|
Args:
|
|
509
510
|
dev_arr (cupy.ndarray): Array to be transferred.
|
|
511
|
+
copy (bool): This parameter is ignored for CUDA, as the data lives
|
|
512
|
+
on a different device.
|
|
513
|
+
|
|
510
514
|
Returns:
|
|
511
515
|
numpy.ndarray: The same data copied to a numpy array.
|
|
512
|
-
|
|
513
516
|
"""
|
|
514
517
|
return dev_arr.get()
|
|
515
518
|
|
|
@@ -81,6 +81,8 @@ if _enabled:
|
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
class ContextPyopencl(XContext):
|
|
84
|
+
context_cache = {}
|
|
85
|
+
|
|
84
86
|
@property
|
|
85
87
|
def nplike_array_type(self):
|
|
86
88
|
return cla.Array
|
|
@@ -128,20 +130,29 @@ class ContextPyopencl(XContext):
|
|
|
128
130
|
super().__init__()
|
|
129
131
|
|
|
130
132
|
# TODO assume one device only
|
|
131
|
-
if device
|
|
133
|
+
if device in self.context_cache:
|
|
134
|
+
self.platform, self.device, self.context = self.context_cache[
|
|
135
|
+
device
|
|
136
|
+
]
|
|
137
|
+
elif device is None:
|
|
132
138
|
self.context = cl.create_some_context(interactive=False)
|
|
133
139
|
self.device = self.context.devices[0]
|
|
134
140
|
self.platform = self.device.platform
|
|
135
141
|
else:
|
|
136
142
|
if isinstance(device, str):
|
|
137
|
-
platform,
|
|
143
|
+
platform, device_ = map(int, device.split("."))
|
|
138
144
|
self.platform = cl.get_platforms()[platform]
|
|
139
|
-
self.device = self.platform.get_devices()[
|
|
145
|
+
self.device = self.platform.get_devices()[device_]
|
|
140
146
|
else:
|
|
141
147
|
self.device = device
|
|
142
148
|
self.platform = device.platform
|
|
143
149
|
|
|
144
150
|
self.context = cl.Context([self.device])
|
|
151
|
+
self.context_cache[device] = (
|
|
152
|
+
self.platform,
|
|
153
|
+
self.device,
|
|
154
|
+
self.context,
|
|
155
|
+
)
|
|
145
156
|
|
|
146
157
|
self.queue = cl.CommandQueue(self.context)
|
|
147
158
|
|
|
@@ -253,28 +264,30 @@ class ContextPyopencl(XContext):
|
|
|
253
264
|
device_id = self.platform.get_devices().index(self.device)
|
|
254
265
|
return f"{type(self).__name__}:{platform_id}.{device_id}"
|
|
255
266
|
|
|
256
|
-
def nparray_to_context_array(self, arr):
|
|
257
|
-
"""
|
|
258
|
-
|
|
267
|
+
def nparray_to_context_array(self, arr, copy=False):
|
|
268
|
+
"""Copies a numpy array to the device memory.
|
|
269
|
+
|
|
259
270
|
Args:
|
|
260
271
|
arr (numpy.ndarray): Array to be transferred
|
|
272
|
+
copy (bool): This parameter is ignored for OpenCL, as the data lives
|
|
273
|
+
on a different device.
|
|
261
274
|
|
|
262
275
|
Returns:
|
|
263
276
|
pyopencl.array.Array:The same array copied to the device.
|
|
264
|
-
|
|
265
277
|
"""
|
|
266
278
|
dev_arr = cla.to_device(self.queue, arr)
|
|
267
279
|
return dev_arr
|
|
268
280
|
|
|
269
|
-
def nparray_from_context_array(self, dev_arr):
|
|
270
|
-
"""
|
|
271
|
-
Copies an array to the device to a numpy array.
|
|
281
|
+
def nparray_from_context_array(self, dev_arr, copy=False):
|
|
282
|
+
"""Copies an array to the device to a numpy array.
|
|
272
283
|
|
|
273
284
|
Args:
|
|
274
285
|
dev_arr (pyopencl.array.Array): Array to be transferred.
|
|
286
|
+
copy (bool): This parameter is ignored for OpenCL, as the data lives
|
|
287
|
+
on a different device.
|
|
288
|
+
|
|
275
289
|
Returns:
|
|
276
290
|
numpy.ndarray: The same data copied to a numpy array.
|
|
277
|
-
|
|
278
291
|
"""
|
|
279
292
|
return dev_arr.get()
|
|
280
293
|
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: xobjects
|
|
3
|
+
Version: 0.5.9
|
|
4
|
+
Summary: In-memory serialization and code generator for CPU and GPU
|
|
5
|
+
Home-page: https://xsuite.readthedocs.io/
|
|
6
|
+
Download-URL: https://pypi.python.org/pypi/xobjects
|
|
7
|
+
Author: Riccardo De Maria
|
|
8
|
+
Author-email: Riccardo De Maria <riccardo.de.maria@cern.ch>
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Project-URL: Homepage, https://xsuite.readthedocs.io/
|
|
11
|
+
Project-URL: Bug Tracker, https://github.com/xsuite/xsuite/issues
|
|
12
|
+
Project-URL: Documentation, https://xsuite.readthedocs.io/
|
|
13
|
+
Project-URL: Source Code, https://github.com/xsuite/xobjects
|
|
14
|
+
Project-URL: Download, https://pypi.python.org/pypi/xobjects
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: numpy
|
|
19
|
+
Requires-Dist: cffi
|
|
20
|
+
Requires-Dist: scipy
|
|
21
|
+
Provides-Extra: tests
|
|
22
|
+
Requires-Dist: pytest; extra == "tests"
|
|
23
|
+
Requires-Dist: pytest-mock; extra == "tests"
|
|
24
|
+
Dynamic: author
|
|
25
|
+
Dynamic: download-url
|
|
26
|
+
Dynamic: home-page
|
|
27
|
+
Dynamic: license-file
|
|
28
|
+
Dynamic: requires-python
|
|
29
|
+
|
|
30
|
+
# XObjects
|
|
31
|
+
|
|
32
|
+
Library to create and manipulate serialized object in CPU and GPU memory efficiently.
|
|
33
|
+
|
|
34
|
+
The library defines:
|
|
35
|
+
- Contexts: create buffers and manage computations e.g. BytearrayContext, CLContext, ...
|
|
36
|
+
- Buffers: reference to internal memory buffer with an allocator e.g.
|
|
37
|
+
BytearrayContext, CLBuffer, ...
|
|
38
|
+
- Data types: define users define types to create and manipulate objects on
|
|
39
|
+
buffers and generate C api, e.g. Float64, Int64, String, Struct, Array, Union
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
LICENSE
|
|
2
|
+
README.md
|
|
2
3
|
pyproject.toml
|
|
3
4
|
setup.cfg
|
|
4
5
|
setup.py
|
|
@@ -7,6 +8,7 @@ tests/test_array.py
|
|
|
7
8
|
tests/test_buffer.py
|
|
8
9
|
tests/test_capi.py
|
|
9
10
|
tests/test_chunk.py
|
|
11
|
+
tests/test_common.py
|
|
10
12
|
tests/test_context_opencl.py
|
|
11
13
|
tests/test_hybrid_class.py
|
|
12
14
|
tests/test_kernel.py
|
|
@@ -44,5 +46,6 @@ xobjects/union.py
|
|
|
44
46
|
xobjects.egg-info/PKG-INFO
|
|
45
47
|
xobjects.egg-info/SOURCES.txt
|
|
46
48
|
xobjects.egg-info/dependency_links.txt
|
|
49
|
+
xobjects.egg-info/entry_points.txt
|
|
47
50
|
xobjects.egg-info/requires.txt
|
|
48
51
|
xobjects.egg-info/top_level.txt
|
xobjects-0.5.7/PKG-INFO
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: xobjects
|
|
3
|
-
Version: 0.5.7
|
|
4
|
-
Summary: In-memory serialization and code generator for CPU and GPU
|
|
5
|
-
Home-page: https://xsuite.readthedocs.io/
|
|
6
|
-
Download-URL: https://pypi.python.org/pypi/xobjects
|
|
7
|
-
Author: Riccardo De Maria
|
|
8
|
-
Author-email: riccardo.de.maria@cern.ch
|
|
9
|
-
License: Apache 2.0
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/xsuite/xsuite/issues
|
|
11
|
-
Project-URL: Documentation, https://xsuite.readthedocs.io/
|
|
12
|
-
Project-URL: Source Code, https://github.com/xsuite/xobjects
|
|
13
|
-
Requires-Python: >=3.7
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist: cffi
|
|
17
|
-
Requires-Dist: scipy
|
|
18
|
-
Provides-Extra: tests
|
|
19
|
-
Requires-Dist: pytest; extra == "tests"
|
|
20
|
-
Requires-Dist: pytest-mock; extra == "tests"
|
|
21
|
-
|
|
22
|
-
In-memory serialization and code generator for CPU and GPU
|
xobjects-0.5.7/pyproject.toml
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.5.7"
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: xobjects
|
|
3
|
-
Version: 0.5.7
|
|
4
|
-
Summary: In-memory serialization and code generator for CPU and GPU
|
|
5
|
-
Home-page: https://xsuite.readthedocs.io/
|
|
6
|
-
Download-URL: https://pypi.python.org/pypi/xobjects
|
|
7
|
-
Author: Riccardo De Maria
|
|
8
|
-
Author-email: riccardo.de.maria@cern.ch
|
|
9
|
-
License: Apache 2.0
|
|
10
|
-
Project-URL: Bug Tracker, https://github.com/xsuite/xsuite/issues
|
|
11
|
-
Project-URL: Documentation, https://xsuite.readthedocs.io/
|
|
12
|
-
Project-URL: Source Code, https://github.com/xsuite/xobjects
|
|
13
|
-
Requires-Python: >=3.7
|
|
14
|
-
License-File: LICENSE
|
|
15
|
-
Requires-Dist: numpy
|
|
16
|
-
Requires-Dist: cffi
|
|
17
|
-
Requires-Dist: scipy
|
|
18
|
-
Provides-Extra: tests
|
|
19
|
-
Requires-Dist: pytest; extra == "tests"
|
|
20
|
-
Requires-Dist: pytest-mock; extra == "tests"
|
|
21
|
-
|
|
22
|
-
In-memory serialization and code generator for CPU and GPU
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|