Skip to content

Commit 1ec795b

Browse files
Move some macros that should be in xobjects to it; black
1 parent 5b0d747 commit 1ec795b

File tree

11 files changed

+266
-11
lines changed

11 files changed

+266
-11
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ cov_html
88
.vscode
99
.pytest_cache
1010
.coverage
11+
.idea
1112
*.c

Architecture.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,19 @@ Buffer:
4040

4141
Types can be composed of:
4242
- scalar: numbers, String
43-
- compound: Struct, Array, Ref, UnionRef
43+
- compound: Struct, Array, Ref, UnionRef
4444

4545
### Scalars
4646
- examples: Float64, Int64, ...
4747
- create: Float64(3.14)
4848
- memory layout
49-
- data
49+
- data
5050

5151
### String:
5252
- create: String(string_or_int)
5353
- memory layout
5454
- size
55-
- data
55+
- data
5656

5757

5858
### Struct

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,4 @@
198198
distributed under the License is distributed on an "AS IS" BASIS,
199199
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200200
See the License for the specific language governing permissions and
201-
limitations under the License.
201+
limitations under the License.

pyproject.toml

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,43 @@
1+
[build-system]
2+
requires = ["setuptools>=61.0"]
3+
build-backend = "setuptools.build_meta"
4+
5+
[project]
6+
name = "xobjects"
7+
dynamic = ["version"]
8+
description = "In-memory serialization and code generator for CPU and GPU"
9+
readme = ""
10+
authors = [
11+
{ name = "Riccardo De Maria", email = "[email protected]" }
12+
]
13+
license = { text = "Apache 2.0" }
14+
requires-python = ">=3.7"
15+
dependencies = [
16+
"numpy",
17+
"cffi",
18+
"scipy"
19+
]
20+
[project.urls]
21+
Homepage = "https://xsuite.readthedocs.io/"
22+
"Bug Tracker" = "https://github.com/xsuite/xsuite/issues"
23+
Documentation = "https://xsuite.readthedocs.io/"
24+
"Source Code" = "https://github.com/xsuite/xobjects"
25+
"Download" = "https://pypi.python.org/pypi/xobjects"
26+
27+
[project.optional-dependencies]
28+
tests = ["pytest", "pytest-mock"]
29+
30+
[tool.setuptools.packages.find]
31+
where = ["."]
32+
include = ["xobjects"]
33+
34+
[tool.setuptools.dynamic]
35+
version = {attr = "xobjects._version.__version__"}
36+
137
[tool.black]
238
line-length = 79
3-
target-version = ['py36', 'py37', 'py38']
39+
target-version = ['py310', 'py311', 'py312']
440
include = '\.pyi?$'
41+
42+
[project.entry-points.xobjects]
43+
include = "xobjects"

tests/test_common.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# copyright ################################# #
2+
# This file is part of the Xobjects Package. #
3+
# Copyright (c) CERN, 2025. #
4+
# ########################################### #
5+
6+
import xobjects as xo
7+
from xobjects.test_helpers import for_all_test_contexts
8+
9+
10+
@for_all_test_contexts
11+
def test_common_atomicadd(test_context):
12+
src = r"""
13+
#include <xobjects/headers/common.h>
14+
15+
GPUKERN
16+
double test_atomic_add()
17+
{
18+
int iterations = 1000;
19+
double sum = 0;
20+
VECTORIZE_OVER(i, iterations);
21+
// If on CPU do some work to avoid the loop being optimized out
22+
#if defined(XO_CONTEXT_CPU_OPENMP)
23+
usleep(10);
24+
#endif
25+
atomicAdd(&sum, 1.0);
26+
END_VECTORIZE;
27+
return sum;
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+
args=[],
45+
n_threads=n_threads,
46+
ret=xo.Arg(xo.Float64),
47+
)
48+
},
49+
)
50+
51+
expected = 1000
52+
result = test_context.kernels.test_atomic_add()
53+
54+
assert result == expected

tests/test_shared_memory.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class TestElement(xo.HybridClass):
5353
5454
// sum s[0] += s[1]
5555
if (tid == 0){
56-
sdata[tid] += sdata[tid + 1];
56+
sdata[tid] += sdata[tid + 1];
5757
5858
// write sum from shared to global mem
5959
atomicAdd(&result[tid], sdata[tid]);

update_cprght_statement.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
import os
77

88
copyright_statement = """copyright #################################
9-
This file is part of the Xobjects Package.
10-
Copyright (c) CERN, 2021.
9+
This file is part of the Xobjects Package.
10+
Copyright (c) CERN, 2021.
1111
###########################################"""
1212

1313
config = [

xobjects/context_cupy.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,11 @@ def build_kernels(
457457

458458
extra_include_paths = self.get_installed_c_source_paths()
459459
include_flags = [f"-I{path}" for path in extra_include_paths]
460-
extra_compile_args = (*extra_compile_args, *include_flags, "-DXO_CONTEXT_CUDA")
460+
extra_compile_args = (
461+
*extra_compile_args,
462+
*include_flags,
463+
"-DXO_CONTEXT_CUDA",
464+
)
461465

462466
module = cupy.RawModule(
463467
code=specialized_source, options=extra_compile_args

xobjects/headers/atomicadd.h

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// copyright ################################# //
2+
// This file is part of the Xfields Package. //
3+
// Copyright (c) CERN, 2021. //
4+
// ########################################### //
5+
6+
#ifndef _ATOMICADD_H_
7+
#define _ATOMICADD_H_
8+
9+
/*
10+
Atomic add function (double type) for different contexts.
11+
Following the blueprint of CUDA's atomicAdd function, the return
12+
value is the old value of the address before the addition.
13+
*/
14+
15+
#if defined(XO_CONTEXT_CPU_SERIAL)
16+
inline double atomicAdd(double *addr, double val)
17+
{
18+
double old_val = *addr;
19+
*addr = *addr + val;
20+
return old_val;
21+
}
22+
#elif defined(XO_CONTEXT_CPU_OPENMP)
23+
inline double atomicAdd(double *addr, double val)
24+
{
25+
double old_val = *addr;
26+
#pragma omp atomic
27+
*addr += val;
28+
return old_val;
29+
}
30+
#elif defined(XO_CONTEXT_CL)
31+
#pragma OPENCL EXTENSION cl_khr_int64_base_atomics : enable
32+
inline double atomicAdd(volatile __global double *addr, double val)
33+
{
34+
union {
35+
long u64;
36+
double f64;
37+
} next, expected, current;
38+
current.f64 = *addr;
39+
do {
40+
expected.f64 = current.f64;
41+
next.f64 = expected.f64 + val;
42+
current.u64 = atom_cmpxchg(
43+
(volatile __global long *)addr,
44+
(long) expected.u64,
45+
(long) next.u64);
46+
} while( current.u64 != expected.u64 );
47+
return current.f64;
48+
}
49+
#elif defined(XO_CONTEXT_CUDA)
50+
// CUDA already provides this
51+
#else
52+
#error "Atomic add not implemented for this context"
53+
#endif
54+
55+
#endif // _ATOMICADD_H_

xobjects/headers/common.h

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#ifndef XOBJECTS_COMMON_H
2+
#define XOBJECTS_COMMON_H
3+
4+
#include "xobjects/headers/atomicadd.h"
5+
6+
/*
7+
Common macros for vectorization and parallelization, as well as common
8+
arithmetic operations.
9+
*/
10+
11+
#ifdef XO_CONTEXT_CPU_SERIAL
12+
// We are on CPU, without OpenMP
13+
14+
#define VECTORIZE_OVER(INDEX_NAME, COUNT) \
15+
for (int64_t INDEX_NAME = 0; INDEX_NAME < (COUNT); INDEX_NAME++) {
16+
17+
#define END_VECTORIZE \
18+
}
19+
#endif // XO_CONTEXT_CPU_SERIAL
20+
21+
#ifdef XO_CONTEXT_CPU_OPENMP
22+
// We are on CPU with the OpenMP context switched on
23+
24+
#define VECTORIZE_OVER(INDEX_NAME, COUNT) \
25+
_Pragma("omp parallel for") \
26+
for (int64_t INDEX_NAME = 0; INDEX_NAME < (COUNT); INDEX_NAME++) {
27+
28+
#define END_VECTORIZE \
29+
}
30+
31+
#endif // XO_CONTEXT_CPU_OPENMP
32+
33+
34+
#ifdef XO_CONTEXT_CUDA
35+
// We are on a CUDA GPU
36+
37+
#define VECTORIZE_OVER(INDEX_NAME, COUNT) { \
38+
int64_t INDEX_NAME = blockDim.x * blockIdx.x + threadIdx.x; \
39+
if (INDEX_NAME < (COUNT)) {
40+
41+
#define END_VECTORIZE \
42+
} \
43+
}
44+
#endif // XO_CONTEXT_CUDA
45+
46+
47+
#ifdef XO_CONTEXT_CL
48+
// We are on an OpenCL GPU
49+
50+
#define VECTORIZE_OVER(INDEX_NAME, COUNT) \
51+
{ \
52+
int64_t INDEX_NAME = get_global_id(0);
53+
if (INDEX_NAME < (COUNT)) { \
54+
55+
#define END_VECTORIZE \
56+
} \
57+
}
58+
#endif // XO_CONTEXT_CL
59+
60+
61+
/*
62+
Qualifier keywords for GPU and optimisation
63+
*/
64+
65+
#ifdef XO_CONTEXT_CPU // for both serial and OpenMP
66+
#define GPUKERN
67+
#define GPUFUN static inline
68+
#define GPUGLMEM
69+
#define RESTRICT restrict
70+
#endif
71+
72+
73+
#ifdef XO_CONTEXT_CUDA
74+
#define GPUKERN __global__
75+
#define GPUFUN __device__
76+
#define GPUGLMEM
77+
#define RESTRICT
78+
#endif // XO_CONTEXT_CUDA
79+
80+
81+
#ifdef XO_CONTEXT_CL
82+
#define GPUKERN __kernel
83+
#define GPUFUN
84+
#define GPUGLMEM __global
85+
#define RESTRICT
86+
#endif // XO_CONTEXT_CL
87+
88+
89+
/*
90+
Common maths-related macros
91+
*/
92+
93+
#define POW2(X) ((X)*(X))
94+
#define POW3(X) ((X)*(X)*(X))
95+
#define POW4(X) ((X)*(X)*(X)*(X))
96+
#define NONZERO(X) ((X) != 0.0)
97+
#define NONZERO_TOL(X, TOL) (fabs((X)) > (TOL))
98+
99+
100+
#ifndef VECTORIZE_OVER
101+
#error "Unknown context, or the expected context (XO_CONTEXT_*) flag undefined. Try updating Xobjects?"
102+
#endif
103+
104+
#endif // XOBJECTS_COMMON_H

0 commit comments

Comments
 (0)