Skip to content

Commit 2247707

Browse files
authored
Merge pull request #2375 from devitocodes/complex
api: Introduce complex numbers support (np.complex64/128)
2 parents f67f2b0 + be87c17 commit 2247707

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+3442
-744
lines changed

.github/workflows/docker-bases.yml

+2
Original file line numberDiff line numberDiff line change
@@ -255,4 +255,6 @@ jobs:
255255
file: './docker/Dockerfile.amd'
256256
push: true
257257
target: 'hip'
258+
build-args: |
259+
ROCM_VERSION=6.3.4
258260
tags: devitocodes/bases:amd-hip

devito/__init__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ def reinit_compiler(val):
5656
"""
5757
Re-initialize the Compiler.
5858
"""
59-
configuration['compiler'].__init__(suffix=configuration['compiler'].suffix,
59+
configuration['compiler'].__init__(name=configuration['compiler'].name,
60+
suffix=configuration['compiler'].suffix,
6061
mpi=configuration['mpi'])
6162
return val
6263

@@ -65,7 +66,7 @@ def reinit_compiler(val):
6566
configuration.add('platform', 'cpu64', list(platform_registry),
6667
callback=lambda i: platform_registry[i]())
6768
configuration.add('compiler', 'custom', compiler_registry,
68-
callback=lambda i: compiler_registry[i]())
69+
callback=lambda i: compiler_registry[i](name=i))
6970

7071
# Setup language for shared-memory parallelism
7172
preprocessor = lambda i: {0: 'C', 1: 'openmp'}.get(i, i) # Handles DEVITO_OPENMP deprec

devito/arch/archinfo.py

+64-1
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,69 @@ def cbk(deviceid=0):
330330
except OSError:
331331
pass
332332

333+
# *** Third try: `sycl-ls`, clearly only works with Intel cards
334+
try:
335+
gpu_infos = {}
336+
337+
# sycl-ls sometimes finds gpu twice with opencl and without so
338+
# we need to make sure we don't get duplicates
339+
selected_platform = None
340+
platform_block = ""
341+
342+
proc = Popen(["sycl-ls", "--verbose"], stdout=PIPE, stderr=DEVNULL, text=True)
343+
sycl_output, _ = proc.communicate()
344+
345+
# Extract platform blocks
346+
platforms = re.findall(r"Platform \[#(\d+)\]:([\s\S]*?)(?=Platform \[#\d+\]:|$)",
347+
sycl_output)
348+
349+
# Select Level-Zero if available, otherwise use OpenCL
350+
for platform_id, platform_content in platforms:
351+
if "Intel(R) Level-Zero" in platform_content:
352+
selected_platform = platform_id
353+
platform_block = platform_content
354+
break
355+
elif "Intel(R) OpenCL Graphics" in platform_content and \
356+
selected_platform is None:
357+
selected_platform = platform_id
358+
platform_block = platform_content
359+
360+
# Extract GPU devices from the selected platform
361+
devices = re.findall(r"Device \[#(\d+)\]:([\s\S]*?)(?=Device \[#\d+\]:|$)",
362+
platform_block)
363+
364+
for device_id, device_block in devices:
365+
if re.search(r"^\s*Type\s*:\s*gpu", device_block, re.MULTILINE):
366+
name_match = re.search(r"^\s*Name\s*:\s*(.+)", device_block, re.MULTILINE)
367+
368+
if name_match:
369+
name = name_match.group(1).strip()
370+
371+
# Store GPU info with correct physical ID
372+
gpu_infos[device_id] = {
373+
"physicalid": device_id,
374+
"product": name
375+
}
376+
377+
gpu_info = homogenise_gpus(list(gpu_infos.values()))
378+
379+
# Also attach callbacks to retrieve instantaneous memory info
380+
# Now this should be done using xpu-smi but for some reason
381+
# it throws a lot of weird errors in docker so skipping for now
382+
for i in ['total', 'free', 'used']:
383+
def make_cbk(i):
384+
def cbk(deviceid=0):
385+
return None
386+
return cbk
387+
388+
gpu_info['mem.%s' % i] = make_cbk(i)
389+
390+
gpu_infos['architecture'] = 'Intel'
391+
return gpu_info
392+
393+
except OSError:
394+
pass
395+
333396
# *** Second try: `lshw`
334397
try:
335398
info_cmd = ['lshw', '-C', 'video']
@@ -391,7 +454,7 @@ def parse_product_arch():
391454
gpu_infos = []
392455
for line in lines:
393456
# Graphics cards are listed as VGA or 3D controllers in lspci
394-
if 'VGA' in line or '3D' in line:
457+
if any(i in line for i in ('VGA', '3D', 'Display')):
395458
gpu_info = {}
396459
# Lines produced by lspci command are of the form:
397460
# xxxx:xx:xx.x Device Type: Name

devito/arch/compiler.py

+43-31
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,21 @@ def __init__(self):
180180
"""
181181

182182
fields = {'cc', 'ld'}
183-
_cpp = False
183+
_default_cpp = False
184+
_cxxstd = 'c++14'
185+
_cstd = 'c99'
184186

185187
def __init__(self, **kwargs):
188+
maybe_name = kwargs.pop('name', self.__class__.__name__)
189+
if isinstance(maybe_name, Compiler):
190+
self._name = maybe_name.name
191+
else:
192+
self._name = maybe_name
193+
186194
super().__init__(**kwargs)
187195

188196
self.__lookup_cmds__()
197+
self._cpp = kwargs.get('cpp', self._default_cpp)
189198

190199
self.suffix = kwargs.get('suffix')
191200
if not kwargs.get('mpi'):
@@ -195,7 +204,7 @@ def __init__(self, **kwargs):
195204
self.cc = self.MPICC if self._cpp is False else self.MPICXX
196205
self.ld = self.cc # Wanted by the superclass
197206

198-
self.cflags = ['-O3', '-g', '-fPIC', '-Wall', '-std=c99']
207+
self.cflags = ['-O3', '-g', '-fPIC', '-Wall', f'-std={self.std}']
199208
self.ldflags = ['-shared']
200209

201210
self.include_dirs = []
@@ -225,13 +234,13 @@ def __new_with__(self, **kwargs):
225234
Create a new Compiler from an existing one, inherenting from it
226235
the flags that are not specified via ``kwargs``.
227236
"""
228-
return self.__class__(suffix=kwargs.pop('suffix', self.suffix),
237+
return self.__class__(name=self.name, suffix=kwargs.pop('suffix', self.suffix),
229238
mpi=kwargs.pop('mpi', configuration['mpi']),
230239
**kwargs)
231240

232241
@property
233242
def name(self):
234-
return self.__class__.__name__
243+
return self._name
235244

236245
@property
237246
def version(self):
@@ -247,6 +256,10 @@ def version(self):
247256

248257
return version
249258

259+
@property
260+
def std(self):
261+
return self._cxxstd if self._cpp else self._cstd
262+
250263
def get_version(self):
251264
result, stdout, stderr = call_capture_output((self.cc, "--version"))
252265
if result != 0:
@@ -482,15 +495,15 @@ def __init_finalize__(self, **kwargs):
482495
platform = kwargs.pop('platform', configuration['platform'])
483496

484497
if isinstance(platform, NvidiaDevice):
485-
self.cflags.remove('-std=c99')
498+
self.cflags.remove(f'-std={self.std}')
486499
# Add flags for OpenMP offloading
487500
if language in ['C', 'openmp']:
488501
cc = get_nvidia_cc()
489502
if cc:
490503
self.cflags += ['-Xopenmp-target', f'-march=sm_{cc}']
491504
self.ldflags += ['-fopenmp', '-fopenmp-targets=nvptx64-nvidia-cuda']
492505
elif platform is AMDGPUX:
493-
self.cflags.remove('-std=c99')
506+
self.cflags.remove(f'-std={self.std}')
494507
# Add flags for OpenMP offloading
495508
if language in ['C', 'openmp']:
496509
self.ldflags += ['-target', 'x86_64-pc-linux-gnu']
@@ -553,9 +566,9 @@ def __init_finalize__(self, **kwargs):
553566
self.ldflags += ['-fopenmp']
554567

555568
if isinstance(platform, NvidiaDevice):
556-
self.cflags.remove('-std=c99')
569+
self.cflags.remove(f'-std={self.std}')
557570
elif platform is AMDGPUX:
558-
self.cflags.remove('-std=c99')
571+
self.cflags.remove(f'-std={self.std}')
559572
# Add flags for OpenMP offloading
560573
if language in ['C', 'openmp']:
561574
self.ldflags += ['-target', 'x86_64-pc-linux-gnu']
@@ -590,16 +603,13 @@ def __lookup_cmds__(self):
590603

591604
class PGICompiler(Compiler):
592605

593-
_cpp = True
606+
_default_cpp = True
594607

595608
def __init_finalize__(self, **kwargs):
596609

597-
self.cflags.remove('-std=c99')
598610
self.cflags.remove('-O3')
599611
self.cflags.remove('-Wall')
600612

601-
self.cflags.append('-std=c++11')
602-
603613
language = kwargs.pop('language', configuration['language'])
604614
platform = kwargs.pop('platform', configuration['platform'])
605615

@@ -643,14 +653,13 @@ def __lookup_cmds__(self):
643653

644654
class CudaCompiler(Compiler):
645655

646-
_cpp = True
656+
_default_cpp = True
647657

648658
def __init_finalize__(self, **kwargs):
649659

650-
self.cflags.remove('-std=c99')
651660
self.cflags.remove('-Wall')
652661
self.cflags.remove('-fPIC')
653-
self.cflags.extend(['-std=c++14', '-Xcompiler', '-fPIC'])
662+
self.cflags.extend(['-Xcompiler', '-fPIC'])
654663

655664
if configuration['mpi']:
656665
# We rather use `nvcc` to compile MPI, but for this we have to
@@ -717,15 +726,10 @@ def __lookup_cmds__(self):
717726

718727
class HipCompiler(Compiler):
719728

720-
_cpp = True
729+
_default_cpp = True
721730

722731
def __init_finalize__(self, **kwargs):
723732

724-
self.cflags.remove('-std=c99')
725-
self.cflags.remove('-Wall')
726-
self.cflags.remove('-fPIC')
727-
self.cflags.extend(['-std=c++14', '-fPIC'])
728-
729733
if configuration['mpi']:
730734
# We rather use `hipcc` to compile MPI, but for this we have to
731735
# explicitly pass the flags that an `mpicc` would implicitly use
@@ -831,7 +835,7 @@ def __init_finalize__(self, **kwargs):
831835
language = kwargs.pop('language', configuration['language'])
832836

833837
if language == 'sycl':
834-
raise ValueError("Use SyclCompiler to jit-compile sycl")
838+
warning(f"Use SyclCompiler (`sycl`) to jit-compile sycl, not {self.name}")
835839

836840
elif language == 'openmp':
837841
# Earlier versions to OneAPI 2023.2.0 (clang17 underneath), have an
@@ -878,7 +882,7 @@ def __lookup_cmds__(self):
878882

879883
class SyclCompiler(OneapiCompiler):
880884

881-
_cpp = True
885+
_default_cpp = True
882886

883887
def __init_finalize__(self, **kwargs):
884888
IntelCompiler.__init_finalize__(self, **kwargs)
@@ -887,9 +891,9 @@ def __init_finalize__(self, **kwargs):
887891
language = kwargs.pop('language', configuration['language'])
888892

889893
if language != 'sycl':
890-
raise ValueError("Expected language sycl with SyclCompiler")
894+
warning(f"Expected language sycl with SyclCompiler, not {language}")
891895

892-
self.cflags.remove('-std=c99')
896+
self.cflags.remove(f'-std={self.std}')
893897
self.cflags.append('-fsycl')
894898

895899
self.cflags.remove('-g') # -g disables some optimizations in IGC
@@ -903,7 +907,7 @@ def __init_finalize__(self, **kwargs):
903907
elif isinstance(platform, IntelDevice):
904908
self.cflags.append('-fsycl-targets=spir64')
905909
else:
906-
raise NotImplementedError(f"Unsupported platform {platform}")
910+
warning(f"Unsupported platform {platform}")
907911

908912

909913
class CustomCompiler(Compiler):
@@ -945,7 +949,6 @@ def __new__(cls, *args, **kwargs):
945949
obj = super().__new__(cls)
946950
# Keep base to initialize accordingly
947951
obj._base = kwargs.pop('base', _base)
948-
obj._cpp = obj._base._cpp
949952

950953
return obj
951954

@@ -976,6 +979,10 @@ def __lookup_cmds__(self):
976979
def __new_with__(self, **kwargs):
977980
return super().__new_with__(base=self._base, **kwargs)
978981

982+
@property
983+
def _default_cpp(self):
984+
return self._base._default_cpp
985+
979986

980987
class CompilerRegistry(dict):
981988
"""
@@ -984,15 +991,19 @@ class CompilerRegistry(dict):
984991
"""
985992

986993
def __getitem__(self, key):
994+
if isinstance(key, Compiler):
995+
key = key.name
996+
987997
if key.startswith('gcc-'):
988998
i = key.split('-')[1]
989999
return partial(GNUCompiler, suffix=i)
1000+
9901001
return super().__getitem__(key)
9911002

992-
def __contains__(self, k):
993-
if isinstance(k, Compiler):
994-
k = k.name
995-
return k in self.keys() or k.startswith('gcc-')
1003+
def __contains__(self, key):
1004+
if isinstance(key, Compiler):
1005+
key = key.name
1006+
return key in self.keys() or key.startswith('gcc-')
9961007

9971008

9981009
_compiler_registry = {
@@ -1011,6 +1022,7 @@ def __contains__(self, k):
10111022
'nvc++': NvidiaCompiler,
10121023
'nvidia': NvidiaCompiler,
10131024
'cuda': CudaCompiler,
1025+
'nvcc': CudaCompiler,
10141026
'osx': ClangCompiler,
10151027
'intel': OneapiCompiler,
10161028
'icx': OneapiCompiler,

devito/builtins/arithmetic.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ def norm(f, order=2):
3232
s = dv.types.Symbol(name='sum', dtype=n.dtype)
3333

3434
op = dv.Operator([dv.Eq(s, 0.0)] + eqns +
35-
[dv.Inc(s, dv.Abs(Pow(p, order))), dv.Eq(n[0], s)],
35+
[dv.Inc(s, Pow(dv.Abs(p), order)), dv.Eq(n[0], s)],
3636
name='norm%d' % order)
3737
op.apply(**kwargs)
3838

3939
v = np.power(n.data[0], 1/order)
4040

41-
return f.dtype(v)
41+
return np.real(f.dtype(v))
4242

4343

4444
@dv.switchconfig(log_level='ERROR')

devito/builtins/utils.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@
2323
# NOTE: np.float128 isn't really a thing, see for example
2424
# https://github.com/numpy/numpy/issues/10288
2525
# https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html#1070
26-
np.float64: np.float64
26+
np.float64: np.float64,
27+
# ComplexX accumulates on Complex2X
28+
np.complex64: np.complex128,
29+
np.complex128: np.complex128,
2730
}
2831

2932

0 commit comments

Comments
 (0)