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

[oneDPL][ranges] + zip_view implementation for C++20 #1877

Open
wants to merge 44 commits into
base: main
Choose a base branch
from

Conversation

MikeDvorskiy
Copy link
Contributor

@MikeDvorskiy MikeDvorskiy commented Sep 25, 2024

[oneDPL][ranges] + zip_view implementation for C++20. The implementation and test.

  • namespace: oneapi::dpl::ranges
  • based on oneDPL device copyable tuple

@MikeDvorskiy MikeDvorskiy marked this pull request as draft September 25, 2024 15:06
@MikeDvorskiy MikeDvorskiy marked this pull request as ready for review September 27, 2024 14:04
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/zip_view branch 2 times, most recently from 603daed to 80ef9c5 Compare September 30, 2024 09:50
@danhoeflinger danhoeflinger self-requested a review October 2, 2024 12:21
Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev left a comment

Choose a reason for hiding this comment

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

Let me leave just a couple of minor comments. I am going to look at the whole PR during this week.

test/parallel_api/ranges/std_ranges_zip_view.pass.cpp Outdated Show resolved Hide resolved
test/parallel_api/ranges/std_ranges_zip_view.pass.cpp Outdated Show resolved Hide resolved
Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev left a comment

Choose a reason for hiding this comment

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

What do you think about testing the following properties of zip_view/zip?

  • begin/end (they should also probably be checked if they are iterators)
  • cbegin/cend
  • front/back
  • size
  • empty
  • operator bool
  • construction:
    • ranges::zip(...)/ranges::zip_view(...)
    • empty view (views::zip())
    • another view (*move construction is not checked)
    • another zip_view
  • ranges::zip(...) is a customization point object

I assume that the functionality must match what is required from c++ standard looking at the description. That's why I suggest testing all these properties. Let me know if the implementation is expected to be more relaxed (and how if it is).

@dmitriy-sobolev
Copy link
Contributor

dmitriy-sobolev commented Oct 18, 2024

The description says:

... based on oneDPL device copyable tuple

According to SYCL 2020, std::tuple is also device copyable (if the wrapped types are also device copyable, of course). Does it make sense to use std::tuple instead of the internal one?

@danhoeflinger
Copy link
Contributor

danhoeflinger commented Oct 18, 2024

The description says:

... based on oneDPL device copyable tuple

According to SYCL 2020, std::tuple is also device copyable (if the wrapped types are also device copyable, of course). Does it make sense to use std::tuple instead of the internal one?

The advantage here of using oneDPL's tuple is that it is trivially copyable (for trivially copyable types) which means that any class or structure which uses oneDPL's tuple can be implicitly device copyable rather than requiring a specialization of sycl::is_device_copyable (because of the tuple). std::tuple isn't specified to be trivially copyable.

The advantage is not just to avoid extra code here but also to not impose requirements on users to provide these specializations for types which are composed of a zip_view as well.

There can be downsides to using oneDPLs tuple in that it may not be as fully featured as std::tuple in some ways but I think this is the better option.

@MikeDvorskiy
Copy link
Contributor Author

MikeDvorskiy commented Oct 18, 2024

to use std::tuple instead of the internal one?

Actually, before C++23 standard library there is a problem with std::tuple swap ability. It is bigger issue that doesn't allow to use std::tuple for zip_view implementation for oneDPL C++20.

include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
@MikeDvorskiy MikeDvorskiy force-pushed the dev/mdvorski/zip_view branch 3 times, most recently from f1c08a6 to 74d52be Compare October 22, 2024 12:39
@MikeDvorskiy
Copy link
Contributor Author

MikeDvorskiy commented Oct 25, 2024

regarding > * cbegin + cend
cppreference:

cbegin
  
(C++23)
 
returns a constant iterator to the beginning of the range.
(public member function of std::ranges::view_interface<D>)
cend
  
(C++23)
 
returns a sentinel for the constant iterator of the range.
(public member function of std::ranges::view_interface<D>)

include/oneapi/dpl/pstl/zip_view_impl.h Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
Comment on lines +192 to +195
if (x.current_ < y.current_)
return -1;
else if (x.current_ == y.current_)
return 0;
return 1; //x.current > y.current_
Copy link
Contributor

Choose a reason for hiding this comment

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

Why cannot we use x.current <=> y.current? Spaceship operator is undefined for some of our internal iterator types or it is undefined for internal tuple?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, spaceship operator is undefined for x.current_...

Copy link
Contributor

Choose a reason for hiding this comment

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

When adding comparison between internal tuples, we looked at adding spaceship and it was deemed not worth the effort at the time. We could use this as motivation for adding it, but it would require a bit of work. We would need to trigger it off of __cpp_lib_three_way_comparison >= 201907L, and in that case replace the existing comparison operators with the spaceship, to time it properly with std::tuple <=> operator

#1472 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

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

The thought was that it wasn't worth the maintenance because we would need to implement both to support our full support matrix, and it would be only helpful for those explicitly calling <=> on the internal tuple (which is what we might want to do here as I understand it).

include/oneapi/dpl/pstl/zip_view_impl.h Outdated Show resolved Hide resolved
include/oneapi/dpl/pstl/zip_view_impl.h Show resolved Hide resolved

std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); });
for(int i = 0; i < max_n; ++i)
assert(std::get<0>(zip_view_sort[i]) == max_n - 1 - i);
Copy link
Contributor

Choose a reason for hiding this comment

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

Our testing framework is not adapted for assert: it defines NDEBUG during release test builds. We should either avoid that definition, or do not rely on assert in the tests.

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Nov 19, 2024

Choose a reason for hiding this comment

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

  1. In spite of that we are using assert in our tests more then 10 files... It seems an issue should be created.
  2. I know that a better way to use our own macro like EXPECT_TRUE f.e.

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. I will create it.
  2. That sounds good. Could you do it? I see that there is still one assert in the test.

Copy link
Contributor

Choose a reason for hiding this comment

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

  1. I will create it.

Done: #1945.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

  1. done.
    And I suggest offline discussion about assert / EXPECT_TRUE / NDEBUG

int data[max_n] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

auto zip_view = dpl_ranges::zip(data, std::views::iota(0, max_n)) | std::views::take(5);
std::ranges::for_each(zip_view, test_std_ranges::f_mutuable, [](const auto& val) { return std::get<1>(val); });
Copy link
Contributor

Choose a reason for hiding this comment

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

The result is also should be checked. Would not it be better to use existing test_range_algo utility?

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Nov 19, 2024

Choose a reason for hiding this comment

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

It is a serial std::ranges::for_each. We believe that std::ranges::for_each works fine. So, we are checking just compilation with zip_view here.

Copy link
Contributor

Choose a reason for hiding this comment

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

Even if the algorithm is proven to work well, something can theoretically be wrong with the zip_view implementation, which would result in incorrect run-time behavior, e.g. wrong begin() or end() implementation. I am still inclined it would be viable to check the result.

Perhaps, it is also makes sense to check if the operation applies only to the projected value.

Comment on lines +77 to +79
std::sort(zip_view_sort.begin(), zip_view_sort.begin() + max_n, [](const auto& val1, const auto& val2) { return std::get<0>(val1) > std::get<0>(val2); });
for(int i = 0; i < max_n; ++i)
EXPECT_TRUE(std::get<0>(zip_view_sort[i]) == max_n - 1 - i, "Wrong effect for std::sort with zip_view.");
Copy link
Contributor

Choose a reason for hiding this comment

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

I would also expect checking the second sequence, e.g. to test if the zipped elements are moved together.

std::vector<int> vec1(max_n);
std::vector<int> vec2(max_n/2);

auto zip_view = dpl_ranges::zip(vec1, vec2);
Copy link
Contributor

@dmitriy-sobolev dmitriy-sobolev Nov 19, 2024

Choose a reason for hiding this comment

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

Should zip also be checked for availability in oneapi::dpl::views namespace?

@dmitriy-sobolev
Copy link
Contributor

dmitriy-sobolev commented Nov 20, 2024

regarding > * cbegin + cend cppreference:

cbegin
  
(C++23)
 
returns a constant iterator to the beginning of the range.
(public member function of std::ranges::view_interface<D>)
cend
  
(C++23)
 
returns a sentinel for the constant iterator of the range.
(public member function of std::ranges::view_interface<D>)

zip_view is based on view_iterface, and the later does not have cbegin/cend in c++20. That means our c++20 zip_view will not have cbegin/cend, and we are not going to provide them. Is that correct understanding?

#ifndef _ONEDPL_ZIP_VIEW_IMPL_H
#define _ONEDPL_ZIP_VIEW_IMPL_H

#if _ONEDPL_CPP20_RANGES_PRESENT
Copy link
Contributor

Choose a reason for hiding this comment

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

Did not we think about having oneapi::dpl::zip_view as part of namespace std::ranges prior to C++23?
It will allow the user to have portable code for each version of the standard. Otherwise, we will need to think about aligning oneapi::dpl::zip_view with the C++23 and later as well.

Copy link
Contributor Author

@MikeDvorskiy MikeDvorskiy Dec 3, 2024

Choose a reason for hiding this comment

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

Do you mean a kind of name injection into std::ranges prior to C++23? Good question.

On one hand - it is useful when a user is going to modify his code forward to C++23.
On the other hand, having std::ranges::zip_view (in result of name oneapi::dpl::zip_view injection), enforces us to be fully compliance with standard zip_view C++23. At least, the proposed zip_view implementation works only with random access views, for example. And we don't need more for oneDPL needs.

I would suggest rather to have an alias oneapi::dpl::zip_view, which is our own implementation class prior to C++23 and which is std::ranges::zip_view for C++23 and higher.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea of having the alias to std::ranges::zip_view in oneDPL for C++23 and higher. It perfectly fits the idea of having everything that should work in the offloaded code in oneapi::dpl namespace.

MikeDvorskiy and others added 24 commits November 28, 2024 18:44
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
Co-authored-by: Konstantin Boyarinov <konstantin.boyarinov@intel.com>
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.

4 participants