Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cpp14 support #314

Merged
merged 16 commits into from
May 23, 2024
Merged

Cpp14 support #314

merged 16 commits into from
May 23, 2024

Conversation

oliverlee
Copy link
Contributor

I've updated the P0009 headers to compile without C++17 extensions.

For the last commit, I've dumped a few common utilities in the extents header. Please feel free to edit as desired.


#ifdef __cpp_lib_span
#include <span>
#endif
#include <array>
#include <type_traits>
#include <stdexcept>
Copy link
Contributor

@mhoemmen mhoemmen Feb 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing in this header threw an std::exception subclass before. Furthermore, the only reason this code now throws an exception is to trigger a call to terminate in a noexcept function.

Would you consider just calling std::abort as before? Alternately, would you consider adding a configurable precondition violation handler (e.g., a macro that takes a message and just calls std::abort by default)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you consider just calling std::abort as before? Alternately, would you consider adding a configurable precondition violation handler (e.g., a macro that takes a message and just calls std::abort by default)?

Sure that sounds like a better approach. I'm also wondering if extents.hpp is the right location for the terminate_if_invalid_strides function. Maybe layout_stride.hpp is a better place?

Comment on lines 426 to 428
static_assert(std::is_same<Layout, layout_left>::value or
std::is_same<Layout, layout_right>::value
, "");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you consider adding a nonempty message here?

Comment on lines 10 to 11
template <std::size_t N>
struct with_rank {};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you consider making this an alias of std::integral_constant, so as to avoid more instantiations of types?

@mhoemmen
Copy link
Contributor

Thanks for the contribution! There are some nice refactorings in there as well. @crtrott et al. will likely want to comment.

  1. Do mdspan's tests and examples all build with C++14, or do these changes only just make your application build? We're generally only interested in the former.

  2. Would you consider adding C++14 testing to https://github.com/kokkos/mdspan/blob/stable/.github/workflows/cmake.yml as a part of this PR? Current PR automatic testing will not exercise C++14.

@oliverlee
Copy link
Contributor Author

1. Do mdspan's tests and examples all build with C++14, or do these changes only just make your application build?  We're generally only interested in the former.

I've only tested with the tests defined in CMake along with C++14 so far. All tests pass before and after this PR - however after this PR now builds without warnings.

2. Would you consider adding C++14 testing to https://github.com/kokkos/mdspan/blob/stable/.github/workflows/cmake.yml as a part of this PR?  Current PR automatic testing will not exercise C++14.

Sure.

@oliverlee oliverlee force-pushed the cpp14-support branch 3 times, most recently from 5c44070 to 22258de Compare February 12, 2024 21:30
@mhoemmen
Copy link
Contributor

mhoemmen commented Feb 13, 2024

Thanks for making the changes! Building with C++14 results in the following CMake error message.

CMake Error at CMakeLists.txt:200 (MESSAGE):
  Benchmarks are not available in C++14 or C++23 mode.  Turn
  MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.

I think you could just change line 200 of CMakeLists.txt (

MESSAGE(FATAL_ERROR "Benchmarks are not available in C++14 or C++23 mode. Turn MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.")
) from what it is currently,

MESSAGE(FATAL_ERROR "Benchmarks are not available in C++14 or C++23 mode. Turn MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.")

to something like

set(MDSPAN_ENABLE_BENCHMARKS OFF)
MESSAGE(STATUS "Benchmarks are not available in C++14 or C++23 mode. Turn MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.")

@oliverlee
Copy link
Contributor Author

Thanks for making the changes! Building with C++14 results in the following CMake error message.

CMake Error at CMakeLists.txt:200 (MESSAGE):
  Benchmarks are not available in C++14 or C++23 mode.  Turn
  MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.

I think you could just change line 200 of CMakeLists.txt (

MESSAGE(FATAL_ERROR "Benchmarks are not available in C++14 or C++23 mode. Turn MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.")

) from what it is currently,

MESSAGE(FATAL_ERROR "Benchmarks are not available in C++14 or C++23 mode. Turn MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.")

to something like

set(MDSPAN_ENABLE_BENCHMARKS OFF)
MESSAGE(STATUS "Benchmarks are not available in C++14 or C++23 mode. Turn MDSPAN_ENABLE_BENCHMARKS OFF or use C++17 or C++20.")

I disabled benchmarking for C++14 using the same approach for C++23 (i.e. via matrix settings in cmake.yml) since I thought it would be simpler to maintain. Let me know if you still prefer a CMake option based approach.

Copy link
Member

@crtrott crtrott left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks pretty good. Finally found sufficient time to review it. The new macros are not a bad idea, but I think they should all be IMPL macros.

include/experimental/__p0009_bits/extents.hpp Outdated Show resolved Hide resolved
include/experimental/__p0009_bits/macros.hpp Outdated Show resolved Hide resolved
include/experimental/__p0009_bits/macros.hpp Outdated Show resolved Hide resolved
include/experimental/__p0009_bits/macros.hpp Outdated Show resolved Hide resolved
include/experimental/__p0009_bits/macros.hpp Outdated Show resolved Hide resolved
tests/test_alternate_precondition_violation_handler.cpp Outdated Show resolved Hide resolved
tests/test_alternate_precondition_violation_handler.cpp Outdated Show resolved Hide resolved
tests/test_alternate_precondition_violation_handler.cpp Outdated Show resolved Hide resolved
tests/test_macros.cpp Outdated Show resolved Hide resolved
tests/test_macros.cpp Outdated Show resolved Hide resolved
@crtrott
Copy link
Member

crtrott commented May 2, 2024

I will rebase this and merge my suggestions.

@crtrott
Copy link
Member

crtrott commented May 2, 2024

@oliverlee FYI: I rebased and force pushed. I'd like to get this in before I work on more of the features for C++26.

@oliverlee
Copy link
Contributor Author

Not sure why the death tests are failing now - they were fine a few months back.

I'll probably have time to look into it tomorrow.

@crtrott
Copy link
Member

crtrott commented May 3, 2024

They passed now. We might have changed Debug to Release build at some point and so the rebase made them fail.

@oliverlee
Copy link
Contributor Author

It should be possible to enable precondition checks in release mode with a preprocessor macro - I imagine this is enabled only for tests and disabled for benchmarks.

It shouldn't be too much trouble to do in a separate PR if you want to merge this PR and use it as a base for c++26 stuff.

@oliverlee
Copy link
Contributor Author

@crtrott It looks like the macro in test/CMakeLists.txt was missed in the rename commit.

I've created two commits - please squash or do whatever is normal for this repo.

@crtrott
Copy link
Member

crtrott commented May 3, 2024

Thanks! I had overlooked that. That said I am not sure it's the best way to go about this. Now the tests never take the code path where the preconditions are skipped. Maybe instead we should have a mix of debug and non-debug test configs.

@crtrott
Copy link
Member

crtrott commented May 3, 2024

Also I am waiting for a second review to finish (should happen latest by Monday I pinged appropriate people in my team).

@oliverlee
Copy link
Contributor Author

That said I am not sure it's the best way to go about this.

Same - whatever makes the most sense to you in terms of maintenance.

I've seen precondition tests defined in a separate test file. That could remove the need to conditionally define test cases with ASSERT_DEATH and simplify running tests with debug and non-debug configs. Would that make sense here?

@crtrott
Copy link
Member

crtrott commented May 3, 2024

It could make sense to separate them out. We had some platforms where the death tests never fully worked ...

@oliverlee
Copy link
Contributor Author

It could make sense to separate them out. We had some platforms where the death tests never fully worked ...

There are only a few DEATH_TESTS now.

It makes sense to do it earlier rather than later if this is approach you want to pursue.

@crtrott
Copy link
Member

crtrott commented May 3, 2024

Yeah let's do it. Do you have time to tackle that? If not I might get around to it some point this weekend.

@oliverlee
Copy link
Contributor Author

Yeah let's do it. Do you have time to tackle that? If not I might get around to it some point this weekend.

Maybe this afternoon? If not, also this weekend.

@crtrott
Copy link
Member

crtrott commented May 3, 2024

Sounds good. Also I send you an invite to our slack channel in case you are interested.

@crtrott
Copy link
Member

crtrott commented May 4, 2024

Yeah this is great. Thanks so much!

namespace detail {

template <bool check = MDSPAN_IMPL_CHECK_PRECONDITION>
constexpr void precondition(const char* cond, const char* file, unsigned line)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be decorated with MDSPAN_FUNCTION

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you consider tag dispatching instead ,having two non templated overloads

MDSPAN_FUNCTION constexpr void precondition(std::false_type /*checked*/, const char* /*cond*/, const char* /*file*/, unsigned /*line*/) { /* do nothing */ }
MDSPAN_FUNCTION constexpr void precondition(std::true_type /*checked*/, const char* cond, const char* file, unsigned line) { MDSPAN_IMPL_PRECONDITION_VIOLATION_HANDLER(cond, file, line); }

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have a while back? Not sure.

But I tested it out just now, and this approach produces warnings with Clang and GCC:

Clang-18:

.../mdspan/include/mdspan/../experimental/__p0009_bits/macros.hpp:142:16: error: constexpr function never produces a constant expression [-Winvalid-constexpr]
  142 | constexpr void precondition(std::true_type, const char* cond, const char* file, unsigned line)

GCC-11:

.../mdspan/include/mdspan/../experimental/__p0009_bits/macros.hpp:120:81: error: call to non-‘constexpr’ function ‘void Kokkos::detail::default_precondition_violation_handler(const char*, const char*, unsigned int)’

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect the issue is the constexpr specifier

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you needed it to be call it in other functions that themselves are callable in a constant expression...

include/experimental/__p0009_bits/utility.hpp Show resolved Hide resolved
namespace MDSPAN_IMPL_STANDARD_NAMESPACE {
namespace detail {

inline void default_precondition_violation_handler(const char* cond, const char* file, unsigned line)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine by me but just noting that the default handler would not work with CUDA/HIP

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please feel free to make any changes if CUDA/HIP compatibility is necessary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

printf works just fine with CUDA; it's HIP that's broken lol ; - )

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is a fprintf and it is qualified so there is no way it works on CUDA. As far as I know HIP behaves just the same as CUDA here.

layout_padded_constants<typename _OtherMapping::layout_type,
_ExtentsType>::padded_stride_idx;
constexpr auto extent_to_pad_idx = layout_padded_constants<typename _OtherMapping::layout_type, _ExtentsType>::extent_to_pad_idx;
assert(other_mapping.stride(padded_stride_idx) == other_mapping.extents().extent(extent_to_pad_idx));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we not be using MDSPAN_IMPL_PRECONDITION here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure let's do that.

if(MDSPAN_TEST_LANGUAGE)
set_source_files_properties(${name} PROPERTIES LANGUAGE ${MDSPAN_TEST_LANGUAGE})
endif()
add_executable(${name} ${name}.cpp)
target_link_libraries(${name} mdspan gtest_main)
add_test(${name} ${name})
endmacro()
set_property(TARGET ${name} PROPERTY COMPILE_WARNING_AS_ERROR ON)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not necessarily opposed to this but IMO it does not belong to this PR

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is related to C++14 support to some degree - otherwise C++17 language features are still usable with some compilers when building for C++14. But I also see that the impact of this change has wider consequences.

What do you think about breaking out this change into a separate PR and rebasing this PR on top of that? I can do that later this evening - or feel free to change this PR as you see fit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Christian did you mean to keep this?

tests/test_macros.cpp Show resolved Hide resolved
Comment on lines 110 to 129
{
(void)std::fprintf(::stderr, "%s:%u: precondition failure: `%s`\n", file, line, cond);
std::abort();
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know how HIP or SYCL work, but the following should be fine for CUDA. Note that in device code, printf may have a performance cost even if it is never called at run time. (For example, the compiler may need to reserve registers for it.)

Suggested change
{
(void)std::fprintf(::stderr, "%s:%u: precondition failure: `%s`\n", file, line, cond);
std::abort();
}
{
#if defined(__CUDA_ARCH__)
# if ! defined(NDEBUG)
printf("%s:%u: precondition failure: `%s`\n", file, line, cond);
assert(false);
# endif
#else
fprintf(stderr, "%s:%u: precondition failure: `%s`\n", file, line, cond);
assert(false);
#endif
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HIP works the same as Cuda. For SYCL (oneAPI), you would need to use sycl::ext::oneapi::experimental::printf.

nmm0
nmm0 previously requested changes May 15, 2024
Copy link
Contributor

@nmm0 nmm0 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm good with almost everything, just lets keep the padded layout stuff isolated (since it requires C++17 anyway)

@crtrott
Copy link
Member

crtrott commented May 23, 2024

I just noticed that this requires CXX Extensions for GCC. I.e. -std=gnu++14 - it doesn't work with -std=c++14. Do you consider that acceptable?

oliverlee and others added 15 commits May 23, 2024 09:28
Use the `_MDSPAN_FOLD_AND` macro to avoid using fold expressions
when building for C++14.
Add an empty message to static assert in `layout_padded_fwd.hpp` to
avoid use of C++17 extensions when building for C++14.
Replace use of constexpr if in headers used to implement p0009 in
order to allow compilation for C++14 without C++17 extensions.
Move test cases that test preconditions with `ASSERT_DEATH` to separate
test files. This allows other (non-precondition) tests to be compiled
with or without preconditions. CMake test targets will enable
preconditions during compilation if passed the option
`ENABLE_PRECONDITIONS`.

This only requires moving a single test case from `test_layout_ctors` -
`test_alternate_precondition_violation_handler`
and `test_macros` are test files have been written primary to test
preconditions.
@crtrott crtrott dismissed nmm0’s stale review May 23, 2024 15:42

addressed

@oliverlee
Copy link
Contributor Author

I just noticed that this requires CXX Extensions for GCC. I.e. -std=gnu++14 - it doesn't work with -std=c++14. Do you consider that acceptable?

Do you know what requires extensions? I didn't intend for that and I believe I am only using -std=c++14 in projects using mdspan (however, those don't use CMake).

@crtrott
Copy link
Member

crtrott commented May 23, 2024

Its now fixed.

include/experimental/__p0009_bits/macros.hpp Show resolved Hide resolved
MDSPAN_FUNCTION inline void default_precondition_violation_handler(const char* cond, const char* file, unsigned line)
{
printf("%s:%u: precondition failure: `%s`\n", file, line, cond);
assert(0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please confirm that you did not see issue with Clang as the CUDA compiler.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I couldn't find a variant which fails and we will use in Kokkos Kokkos::abort anyway.

if(MDSPAN_TEST_LANGUAGE)
set_source_files_properties(${name} PROPERTIES LANGUAGE ${MDSPAN_TEST_LANGUAGE})
endif()
add_executable(${name} ${name}.cpp)
target_link_libraries(${name} mdspan gtest_main)
add_test(${name} ${name})
endmacro()
set_property(TARGET ${name} PROPERTY COMPILE_WARNING_AS_ERROR ON)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Christian did you mean to keep this?

tests/test_layout_preconditions.cpp Show resolved Hide resolved
@@ -55,6 +55,7 @@ void test_mdspan_size(std::vector<char>& storage, Extents&& e)

TEST(TestMdspan, MdspanSizeReturnTypeAndPrecondition)
{
(void) test_info_;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yuk

tests/test_macros.cpp Show resolved Hide resolved
Copy link
Member

@dalg24 dalg24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good enough.
Thank you Oliver.

@dalg24 dalg24 merged commit 2f5ae3d into kokkos:stable May 23, 2024
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants