Skip to content

Commit

Permalink
Merge branch 'master' into 85-ensure-all-keywords-in-check_-are-case-…
Browse files Browse the repository at this point in the history
…insensitive
  • Loading branch information
Wesley Kwiecinski committed Aug 5, 2024
2 parents 6a649e6 + d7e7339 commit 83df7e8
Show file tree
Hide file tree
Showing 22 changed files with 162 additions and 179 deletions.
7 changes: 2 additions & 5 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,10 @@ test_gnu:
- pip install seaborn
- pip install yt
- cd $MILHOJA_CODE_REPO/tools/sedov_pypkg
- python setup.py test
- python setup.py sdist && cd dist
- pip install $(ls sedov-*.tar.gz)
- pip install .
- python -c 'import sedov ; sedov.print_versions()'
- cd $MILHOJA_CODE_REPO/tools/milhoja_pypkg
- python setup.py sdist && cd dist
- pip install $(ls milhoja-*.tar.gz)
- pip install .
##-- Check python virtual environment
- pip list
- $MILHOJA_CODE_REPO/tools/test_milhoja_installation.py -v 2
Expand Down
36 changes: 34 additions & 2 deletions tools/milhoja_pypkg/docs/source/developers_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,35 @@ name of the item, followed by the suffix '_d'.

Code Generation Interface
-------------------------
.. autoclass:: milhoja.TileWrapperGenerator_cpp

Code Generation classes contained inside of the code generation interface follow
a loose naming pattern that determines what language and device the code is generated
for. The general format is as follows:

`[object][_device][_language]`

Where the `[object]` is the type of object being generated, either `DataPacket`
or `TileWrapper`. The `[_device]` is the device that the generated code will run
on, either `cpu` for running on the cpu, or the tpye of offloading to use if the
gpu is being used. Finally, the `[_language]` is the language that the code is
generated for. For example, `TaskFunctionC2FGenerator_OpenACC_F` is a class
for generating the C2F layer for TaskFunctions, with code that runs on the GPU
with OpenACC offloading, generated for fortran code.

Since this is just a 'loose' rule, there are a few exceptions to this. The
TileWrapperGenerator class and the DataPacketGenerator class hide any language specific
generation rules inside of themselves, so there are no separate generators for language
or device specific data items. Generally, TileWrappers are only used on CPUs, so
there is no need to specify the device. TileWrappers are also compatible with both
Fortran & C++ Task Functions without extra modifications. DataPackets are designed
in a similar way, however, the generated code is not necessarily compatible with
both C++ and Fortran Task Functions (this will likely change in the future), and
DataPackets are primarily used for offloading purposes. The last exceptions are the
`DataPacketModGenerator` and the `TileWrapperModGenerator`, which exist to generate
fortran module interface files for use with the TaskFunction, therefore there is
no need to specify the language or device/offloading inside of the file name.

.. autoclass:: milhoja.TileWrapperGenerator
:members:
.. autoclass:: milhoja.TileWrapperModGenerator
:members:
Expand All @@ -392,5 +420,9 @@ Code Generation Interface
:members:
.. autoclass:: milhoja.TaskFunctionC2FGenerator_cpu_F
:members:
.. autoclass:: milhoja.TaskFunctionC2FGenerator_OpenACC_F
:members:
.. autoclass:: milhoja.TaskFunctionCpp2CGenerator_cpu_F
:members:
:members:
.. autoclass:: milhoja.TaskFunctionCpp2CGenerator_OpenACC_F
:members:
28 changes: 0 additions & 28 deletions tools/milhoja_pypkg/src/milhoja/DataPacketGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@

from .parse_helpers import parse_extents
from .generate_packet_file import generate_packet_file
from .Cpp2CLayerGenerator import Cpp2CLayerGenerator
from .C2FortranLayerGenerator import C2FortranLayerGenerator
from .DataPacketC2FModuleGenerator import DataPacketC2FModuleGenerator
from .FortranTemplateUtility import FortranTemplateUtility
from .CppTemplateUtility import CppTemplateUtility
from .AbcCodeGenerator import AbcCodeGenerator
Expand All @@ -35,9 +32,6 @@ def __init__(
self, tf_spec: TaskFunction, indent: int, logger: BasicLogger,
sizes: dict
):
if not isinstance(tf_spec, TaskFunction):
raise TypeError("TF Spec was not derived from task function.")

self._TOOL_NAME = "Milhoja DataPacket"
self._sizes = deepcopy(sizes)
self._indent = indent
Expand Down Expand Up @@ -230,28 +224,6 @@ def generate_source_code(self, destination, overwrite):
)
self._log("Done", LOG_LEVEL_BASIC_DEBUG)

if self._tf_spec.language.lower() == "fortran":
# dirty hack for fixing the test suite. In reality, this code
# should be moved outside of the data packet generator and into
# the task function generator.
self.cpp2c_layer = Cpp2CLayerGenerator(
self._tf_spec, self._indent, self._logger
)
self.cpp2c_layer.generate_source_code(destination, overwrite)

# generate fortran to c layer if necessary
self.c2f_layer = C2FortranLayerGenerator(
self._tf_spec, self._indent, self._logger
)
# c2f layer does not use cgkit so no need
# to call generate_packet_file
self.c2f_layer.generate_source_code(destination, overwrite)

self.dp_module = DataPacketC2FModuleGenerator(
self._tf_spec, self._indent, self._logger
)
self.dp_module.generate_source_code(destination, overwrite)

@property
def language(self):
return self._tf_spec.language.lower()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
from . import LOG_LEVEL_BASIC


class DataPacketC2FModuleGenerator(AbcCodeGenerator):
class DataPacketModGenerator(AbcCodeGenerator):
"""
Responsible for generating the module interface file for use by the
fortran task function and interoperability layers. Nothing is generated
for C++ based task functions.
"""

# C2F Module generator uses its own specific type mapping for the
# fortran interface.
_TYPE_MAPPING = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def fname(self):
return f"F_{self.name}"


class C2FortranLayerGenerator(AbcCodeGenerator):
class TaskFunctionC2FGenerator_OpenACC_F(AbcCodeGenerator):
"""
C to Fortran layer generator. Should only be used internally with
the DataPacketGenerator.
Expand Down Expand Up @@ -80,7 +80,7 @@ def __init__(self, tf_spec, indent, logger):
super().__init__(
tf_spec, "",
tf_spec.output_filenames[TaskFunction.C2F_KEY]["source"],
indent, "Milhoja C2F Generator", logger
indent, "Milhoja Task Function C2F Generator OpenACC F", logger
)

self.INDENT = " " * indent
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
)


class Cpp2CLayerGenerator(AbcCodeGenerator):
class TaskFunctionCpp2CGenerator_OpenACC_F(AbcCodeGenerator):
"""
C++ to C layer generator for Data Packets. Should only be used
internally by the DataPacketGenerator.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ def generate_source_code(self, destination, overwrite):
intent = "OUT"
else:
raise LogicError("Unknown grid data variable class")

fptr.write(f"{INDENT*2}real, intent({intent}) :: {arg}_d(:, :, :, :, :)\n")

elif src == SCRATCH_ARGUMENT:
Expand All @@ -209,7 +210,7 @@ def generate_source_code(self, destination, overwrite):
assert dimension > 0
tmp = [":" for _ in range(dimension + 1)]
array = "(" + ", ".join(tmp) + ")"
fptr.write(f"{INDENT*2}{arg_type}, intent(IN) :: {arg}_d{array}\n")
fptr.write(f"{INDENT*2}{arg_type}, intent(INOUT) :: {arg}_d{array}\n")

else:
raise LogicError(f"{arg} of unknown argument class")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from .AbcCodeGenerator import AbcCodeGenerator


class TileWrapperGenerator_cpp(AbcCodeGenerator):
class TileWrapperGenerator(AbcCodeGenerator):
"""
A class for generating final, compilable C++ header and source code that
defines a Milhoja_TileWrapper derived class for constructing the data item
Expand Down Expand Up @@ -39,7 +39,7 @@ def __init__(self, tf_spec, indent, logger):

super().__init__(
tf_spec, header_filename, source_filename, indent,
TileWrapperGenerator_cpp.__LOG_TAG, logger
TileWrapperGenerator.__LOG_TAG, logger
)

# ----- DETERMINE INTERNAL SCRATCH NEEDED & STORE
Expand Down
7 changes: 6 additions & 1 deletion tools/milhoja_pypkg/src/milhoja/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,19 @@
from .TaskFunction import TaskFunction
from .TaskFunctionAssembler import TaskFunctionAssembler
from .AbcCodeGenerator import AbcCodeGenerator
from .TileWrapperGenerator_cpp import TileWrapperGenerator_cpp
from .TileWrapperGenerator import TileWrapperGenerator
from .TileWrapperModGenerator import TileWrapperModGenerator
from .TaskFunctionGenerator_cpu_cpp import TaskFunctionGenerator_cpu_cpp
from .DataPacketGenerator import DataPacketGenerator
from .TaskFunctionCpp2CGenerator_cpu_F import TaskFunctionCpp2CGenerator_cpu_F
from .TaskFunctionC2FGenerator_cpu_F import TaskFunctionC2FGenerator_cpu_F
from .TaskFunctionGenerator_OpenACC_F import TaskFunctionGenerator_OpenACC_F
from .TaskFunctionGenerator_cpu_F import TaskFunctionGenerator_cpu_F
from .TaskFunctionC2FGenerator_OpenACC_F \
import TaskFunctionC2FGenerator_OpenACC_F
from .TaskFunctionCpp2CGenerator_OpenACC_F \
import TaskFunctionCpp2CGenerator_OpenACC_F
from .DataPacketModGenerator import DataPacketModGenerator

# Functions that use classes
from .generate_data_item import generate_data_item
Expand Down
2 changes: 1 addition & 1 deletion tools/milhoja_pypkg/src/milhoja/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

LOG_LEVELS = list(range(LOG_LEVEL_NONE, LOG_LEVEL_MAX+1))

# If we ever want to support more languages in the future
# If we ever want to support more languages in the future?
SUPPORTED_LANGUAGES = ["c++", "fortran"]
# If we ever want to support TPUs or NPUs :) (kidding, just a formality)
SUPPORTED_PROCESSORS = ["cpu", "gpu"]
Expand Down
22 changes: 13 additions & 9 deletions tools/milhoja_pypkg/src/milhoja/generate_data_item.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from pathlib import Path

from .constants import LOG_LEVEL_BASIC_DEBUG
from .TileWrapperGenerator_cpp import TileWrapperGenerator_cpp
from .constants import SUPPORTED_LANGUAGES
from .TileWrapperGenerator import TileWrapperGenerator
from .DataPacketGenerator import DataPacketGenerator


Expand All @@ -28,18 +29,21 @@ def generate_data_item(tf_spec, destination, overwrite, library_path, indent,
data_item = tf_spec.data_item
language = tf_spec.language

if (language.lower() == "c++" or language.lower() == "fortran") and \
(data_item.lower() == "tilewrapper"):
# check language
if (language.lower() not in SUPPORTED_LANGUAGES):
msg = f"{language} is not supported."
raise ValueError(msg)

if data_item.lower() == "tilewrapper":

generator = TileWrapperGenerator_cpp(tf_spec, indent, logger)
generator = TileWrapperGenerator(tf_spec, indent, logger)
generator.generate_header_code(destination, overwrite)
generator.generate_source_code(destination, overwrite)

assert destination.joinpath(generator.header_filename).is_file()
assert destination.joinpath(generator.source_filename).is_file()

elif (language.lower() == "c++" or language.lower() == "fortran") and \
(data_item.lower() == "datapacket"):
elif data_item.lower() == "datapacket":
library = Path(library_path).resolve()
sizes_json = library.joinpath("include", "sizes.json")
if not library.is_dir():
Expand All @@ -55,9 +59,8 @@ def generate_data_item(tf_spec, destination, overwrite, library_path, indent,
with open(sizes_json, "r") as fptr:
sizes = json.load(fptr)
expected = {
"real", "int", "unsigned int", "std::size_t",
"IntVect", "RealVect",
"FArray1D", "FArray2D", "FArray3D", "FArray4D",
"real", "int", "unsigned int", "std::size_t", "IntVect",
"RealVect", "FArray1D", "FArray2D", "FArray3D", "FArray4D",
"byte_align"
}
assert set(sizes) == expected
Expand All @@ -74,6 +77,7 @@ def generate_data_item(tf_spec, destination, overwrite, library_path, indent,

assert destination.joinpath(generator.header_filename).is_file()
assert destination.joinpath(generator.source_filename).is_file()

else:
msg = f"Cannot generate data item code for {data_item}/{language}"
raise ValueError(msg)
29 changes: 20 additions & 9 deletions tools/milhoja_pypkg/src/milhoja/generate_task_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
from . import TaskFunctionC2FGenerator_cpu_F
from . import TaskFunctionCpp2CGenerator_cpu_F
from . import TileWrapperModGenerator
from . import TaskFunctionC2FGenerator_OpenACC_F
from . import TaskFunctionCpp2CGenerator_OpenACC_F
from . import DataPacketModGenerator


def generate_task_function(tf_spec, destination, overwrite, indent, logger):
Expand Down Expand Up @@ -46,21 +49,29 @@ def generate_task_function(tf_spec, destination, overwrite, indent, logger):
c2f_generator.generate_source_code(destination, overwrite)
assert destination.joinpath(generator.source_filename).is_file()

tile_wrapper_mod_generator = \
TileWrapperModGenerator(tf_spec, indent, logger)
tile_wrapper_mod_generator.generate_source_code(
destination, overwrite
)

assert destination.joinpath(
tile_wrapper_mod_generator.source_filename
).is_file()
mod_generator = TileWrapperModGenerator(tf_spec, indent, logger)
mod_generator.generate_source_code(destination, overwrite)
assert destination.joinpath(mod_generator.source_filename).is_file()

elif (language.lower() == "fortran") and (offloading == "openacc"):
generator = TaskFunctionGenerator_OpenACC_F(tf_spec, indent, logger)
generator.generate_source_code(destination, overwrite)
assert destination.joinpath(generator.source_filename).is_file()

generator = \
TaskFunctionC2FGenerator_OpenACC_F(tf_spec, indent, logger)
generator.generate_source_code(destination, overwrite)
assert destination.joinpath(generator.source_filename).is_file()

generator = \
TaskFunctionCpp2CGenerator_OpenACC_F(tf_spec, indent, logger)
generator.generate_source_code(destination, overwrite)
assert destination.joinpath(generator.source_filename).is_file()

generator = DataPacketModGenerator(tf_spec, indent, logger)
generator.generate_source_code(destination, indent)
assert destination.joinpath(generator.source_filename).is_file()

elif (language.lower() in ["c++", "fortran"]) and \
(data_item == "datapacket"):
logger.warn("Milhoja TF", "No TF generation for use with DataPackets")
Expand Down
Loading

0 comments on commit 83df7e8

Please sign in to comment.