From dccdb263e8b7cf336aff102df008e52786af07ce Mon Sep 17 00:00:00 2001 From: Mark Olesen Date: Tue, 25 Feb 2025 09:52:20 +0100 Subject: [PATCH] ENH: add UPstreamTraits support to map data types and opcodes The front-end traits: - UPstream_dataType trait: This wrapper is unwinds the type to check against base/alias, but also checks if it is a component aggregate of a supported UPstream data type. This will be that main entry point for usage. - UPstream_opType trait: Provides a mapping of OpenFOAM ops to their MPI equivalent. The \c opcode_id is the corresponding internal representation. The lower-level traits (not normally used within coding) - UPstream_base_dataType trait: Tests true/false if the specified data type has an internal MPI equivalent. The \c datatype_id is the corresponding internal enumeration. Even if this tests as false, it will always return \c type_byte as the fallback for general contiguous data - UPstream_alias_dataType trait: Provides mapping for to the fundamental 32/64 integrals, since may not otherwise directly map on all systems. NOTE: can use the updates Test-machine-sizes test application to determine if all data types and aliases are properly defined on different systems --- .../00-machine-sizes/Test-machine-sizes.cpp | 171 ++++++++- applications/test/UPstreamTraits/Make/files | 3 + applications/test/UPstreamTraits/Make/options | 2 + .../UPstreamTraits/Test-UPstreamTraits.cxx | 267 ++++++++++++++ .../db/IOstreams/Pstreams/UPstreamTraits.H | 328 +++++++++++++++++- 5 files changed, 765 insertions(+), 6 deletions(-) create mode 100644 applications/test/UPstreamTraits/Make/files create mode 100644 applications/test/UPstreamTraits/Make/options create mode 100644 applications/test/UPstreamTraits/Test-UPstreamTraits.cxx diff --git a/applications/test/00-machine-sizes/Test-machine-sizes.cpp b/applications/test/00-machine-sizes/Test-machine-sizes.cpp index 0e88c4c943..917782dfde 100644 --- a/applications/test/00-machine-sizes/Test-machine-sizes.cpp +++ b/applications/test/00-machine-sizes/Test-machine-sizes.cpp @@ -5,7 +5,7 @@ \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- - Copyright (C) 2018-2022 OpenCFD Ltd. + Copyright (C) 2018-2025 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -25,9 +25,12 @@ License Description Test the sizeof for basic types. + Also tests how the data mapping of OpenFOAM types to UPstream (MPI) + type ids are handled. + Can be compiled and run without any OpenFOAM libraries. - g++ -std=c++11 -oTest-machine-sizes Test-machine-sizes.cpp + g++ -std=c++17 -oTest-machine-sizes Test-machine-sizes.cpp \*---------------------------------------------------------------------------*/ @@ -37,6 +40,114 @@ Description #include #include #include +#include + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Partial copy from UPstream.H + +//- Some MPI data types +// +//- Mapping of some fundamental and aggregate types to MPI data types +enum class dataTypes : int +{ + // Builtin Types [8]: + DataTypes_begin, //!< Begin builtin types (internal use) + type_byte = DataTypes_begin, // also for char, unsigned char + type_int32, + type_int64, + type_uint32, + type_uint64, + type_float, + type_double, + type_long_double, + invalid +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // + +// Partial copy from UPstreamTraits.H + +//- A supported UPstream data type (intrinsic or user-defined) +template +struct UPstream_base_dataType : std::false_type +{ + static constexpr auto datatype_id = dataTypes::invalid; +}; + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Specializations of the above, +// each to match the elements of UPstream::dataTypes + +#undef defineUPstreamDataTraits +#define defineUPstreamDataTraits(TypeId, Type) \ + template<> struct UPstream_base_dataType : std::true_type \ + { \ + static constexpr auto datatype_id = dataTypes::TypeId; \ + }; + + +defineUPstreamDataTraits(type_byte, char); +defineUPstreamDataTraits(type_byte, unsigned char); +defineUPstreamDataTraits(type_int32, int32_t); +defineUPstreamDataTraits(type_int64, int64_t); +defineUPstreamDataTraits(type_uint32, uint32_t); +defineUPstreamDataTraits(type_uint64, uint64_t); +defineUPstreamDataTraits(type_float, float); +defineUPstreamDataTraits(type_double, double); +defineUPstreamDataTraits(type_long_double, long double); + +#undef defineUPstreamDataTraits + + +//- Explicit handling of data type aliases. This is necessary since +//- different systems map things like 'unsigned long' differently but we +//- restrict ourselves to int32/int64 types +template +struct UPstream_alias_dataType +: + std::bool_constant + < + // Base type (no alias needed) + UPstream_base_dataType>::value || + ( + // Or some int 32/64 type to re-map + std::is_integral_v + && (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t)) + ) + > +{ + // Is it using the base type? (no alias needed) + static constexpr bool is_base = + UPstream_base_dataType>::value; + + using base = std::conditional_t + < + UPstream_base_dataType>::value, // is_base + std::remove_cv_t, + std::conditional_t + < + ( + std::is_integral_v + && (sizeof(T) == sizeof(int32_t) || sizeof(T) == sizeof(int64_t)) + ), + std::conditional_t + < + (sizeof(T) == sizeof(int32_t)), + std::conditional_t, int32_t, uint32_t>, + std::conditional_t, int64_t, uint64_t> + >, + char // Fallback value (assuming it is contiguous) + > + >; + + static constexpr auto datatype_id = + UPstream_base_dataType::datatype_id; +}; + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template void print(const char* name, bool showLimits = true) @@ -47,28 +158,78 @@ void print(const char* name, bool showLimits = true) if (showLimits) { std::cout - << " \"max\"=" << std::numeric_limits::max(); + << " max=<"; + + if constexpr (sizeof(T) == 1) + { + std::cout << int(std::numeric_limits::max()); + } + else + { + std::cout << std::numeric_limits::max(); + } + std::cout << '>'; + } + + // A declared or deduced MPI type, or aliased + std::cout + << " is_mpi=" << UPstream_base_dataType::value + << " (" << int(UPstream_base_dataType::datatype_id) << ")"; + + if (UPstream_alias_dataType::value) + { + if (UPstream_alias_dataType::is_base) + { + std::cout<< " is_base"; + } + else + { + std::cout<< " is_alias (" + << int(UPstream_alias_dataType::datatype_id) << ")"; + } + } + else + { + std::cout<< " no_alias"; } std::cout<< '\n'; } + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // Main program: int main(int argc, char *argv[]) { std::cout<< "c++ = " << __cplusplus << '\n'; - std::cout<< "machine sizes\n---\n\n"; + std::cout<< "machine sizes (and some MPI traits)\n---\n\n"; + print("int8_t"); + print("uint8_t"); + print("int16_t"); + print("uint16_t"); + print("int32_t"); + print("uint32_t"); + print("int64_t"); + print("uint64_t"); + + std::cout << '\n'; + print("char"); + print("unsigned char"); print("short"); print("int"); + print("unsigned"); print("long"); print("unsigned long"); - print("std::size_t"); print("long long"); + std::cout << '\n'; + print("std::size_t"); + print("std::streamsize"); + + std::cout << '\n'; print("float"); print("double"); print("long double"); diff --git a/applications/test/UPstreamTraits/Make/files b/applications/test/UPstreamTraits/Make/files new file mode 100644 index 0000000000..5e1dc7bafd --- /dev/null +++ b/applications/test/UPstreamTraits/Make/files @@ -0,0 +1,3 @@ +Test-UPstreamTraits.cxx + +EXE = $(FOAM_USER_APPBIN)/Test-UPstreamTraits diff --git a/applications/test/UPstreamTraits/Make/options b/applications/test/UPstreamTraits/Make/options new file mode 100644 index 0000000000..18e6fe47af --- /dev/null +++ b/applications/test/UPstreamTraits/Make/options @@ -0,0 +1,2 @@ +/* EXE_INC = */ +/* EXE_LIBS = */ diff --git a/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx b/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx new file mode 100644 index 0000000000..9c747c61fa --- /dev/null +++ b/applications/test/UPstreamTraits/Test-UPstreamTraits.cxx @@ -0,0 +1,267 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | www.openfoam.com + \\/ M anipulation | +------------------------------------------------------------------------------- + Copyright (C) 2025 OpenCFD Ltd. +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see . + +Description + Simple compilation tests and access for UPstream types + +\*---------------------------------------------------------------------------*/ + +#include "pTraits.H" +#include "contiguous.H" +#include "FixedList.H" +#include "boolVector.H" // A FixedList pretending to be a vector +#include "barycentric.H" +#include "complex.H" +#include "vector.H" +#include "tensor.H" +#include "uLabel.H" +#include "Switch.H" +#include "IOstreams.H" +#include "UPstream.H" + +#include + +using namespace Foam; + +// Just for debugging +const List dataType_names +({ + "byte", + "int32", + "int64", + "uint32", + "uint64", + "float", + "double", + "long_double", + + "float(2)", + "double(2)", + "float(3)", + "double(3)", + "float(6)", + "double(6)", + "float(9)", + "double(9)" +}); + +//- Test for pTraits typeName member : default is false +template +struct check_has_typeName : std::false_type {}; + +//- Test for pTraits zero +template +struct check_has_typeName +< + T, + std::void_t>::typeName)> +> +: + std::true_type +{}; + + +// Possible future change... +// //- A supported UPstream data type (intrinsic or user-defined) +// template<> +// struct UPstream_base_dataType : std::true_type +// { +// static constexpr auto datatype_id = []() +// { +// if constexpr (sizeof(complex) == 2*sizeof(float)) +// return UPstream::dataTypes::type_2float; +// else +// return UPstream::dataTypes::type_2double; +// }(); +// }; + + +template +void printTypeName(const bool showSize = false) +{ + // Both float and double have pTraits typeName = "scalar"! + if constexpr (std::is_same_v>) + { + Info<< ""; + } + else if constexpr (std::is_same_v>) + { + Info<< ""; + } + else if constexpr (check_has_typeName::value) + { + Info<< pTraits>::typeName; + } + else + { + Info<< typeid(T).name(); + } + if (showSize) + { + Info<< " (" << sizeof(T) << " bytes)"; + } +} + +template +void printPstreamTraits(const std::string_view name = std::string_view()) +{ + Info<< "========" << nl; + Info<< "type: "; + if (!name.empty()) + { + Info<< name << ' '; + } + if constexpr (UseTypeName) + { + printTypeName(true); + } + else + { + Info<< typeid(Type).name(); + Info<< " (" << sizeof(Type) << " bytes)"; + } + + Info<< ", cmpt:"; + printTypeName::type>(true); + + Info<< nl + << " is_contiguous:" + << is_contiguous::value + << ", is base:" + << UPstream_base_dataType::value + << ", is cmpt:" + << UPstream_dataType::value << nl; + + Info<< "is base:" + << UPstream_base_dataType::value + << " (type:" << int(UPstream_base_dataType::datatype_id) + << ") is alias:" << UPstream_alias_dataType::value + << " (type:" << int(UPstream_alias_dataType::datatype_id) + << ")" << nl; + + + { + int index = int(UPstream_base_dataType::datatype_id); + Info<< "datatype: " << index; + + if (index < dataType_names.size()) + { + Info<< ' ' << dataType_names[index]; + } + Info<< nl; + } + + { + // Use element or component type (or byte-wise) for data type + using base = typename UPstream_dataType::base; + constexpr auto datatype = UPstream_dataType::datatype_id; + + Info<< "datatype => "; + printTypeName(); + Info<< " (" << sizeof(Type)/sizeof(base) << " elems)" << nl + << "datatype: " << static_cast(datatype) << nl; + } +} + + +template +void printOpCodeTraits(BinaryOp bop, std::string_view name) +{ + Info<< "op: " << name << ' '; + if constexpr (UPstream_opType::value) + { + Info<< "supported"; + } + else + { + Info<< "unknown"; + } + Info<< ": " << int(UPstream_opType::opcode_id) << nl; +} + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Main program: + +int main() +{ + printPstreamTraits(); + printPstreamTraits