-
Notifications
You must be signed in to change notification settings - Fork 114
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
Host Implementation of Histogram APIs #1974
base: main
Are you sure you want to change the base?
Changes from 46 commits
7bcd21e
955f0e2
ebcada6
93dd493
4d95044
a7fe8a1
6be0b7b
9e3f16c
0592c15
6ac87a0
af5defb
65c30af
eec36d5
1faece5
a39accd
2cd184d
b3dd2a0
bff45d9
2c8cc04
790121b
0392f23
4556399
2fdea34
a0c016a
e87ba02
9f74810
e0ed14c
db2a474
240447e
741f8e3
fd310b6
6820340
4798d2c
ce8b55f
5d1f6e8
6630018
83a9f81
a3f1304
14cca58
766f42c
6425d37
a590cac
dd35fc9
455cf9c
8b094fe
7e1463e
d9d4f08
bebba5e
d494601
0a2847f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4289,6 +4289,86 @@ __pattern_shift_right(_Tag __tag, _ExecutionPolicy&& __exec, _BidirectionalItera | |
return __res.base(); | ||
} | ||
|
||
template <class _ForwardIterator, class _IdxHashFunc, class _RandomAccessIterator, class _IsVector> | ||
void | ||
__brick_histogram(_ForwardIterator __first, _ForwardIterator __last, _IdxHashFunc __func, | ||
_RandomAccessIterator __histogram_first, _IsVector) noexcept | ||
{ | ||
for (; __first != __last; ++__first) | ||
{ | ||
std::int32_t __bin = __func.get_bin(*__first); | ||
if (__bin >= 0) | ||
{ | ||
++__histogram_first[__bin]; | ||
} | ||
} | ||
} | ||
|
||
template <class _Tag, class _ExecutionPolicy, class _ForwardIterator, class _Size, class _IdxHashFunc, | ||
class _RandomAccessIterator> | ||
void | ||
__pattern_histogram(_Tag, _ExecutionPolicy&& __exec, _ForwardIterator __first, _ForwardIterator __last, | ||
_Size __num_bins, _IdxHashFunc __func, _RandomAccessIterator __histogram_first) | ||
{ | ||
using _HistogramValueT = typename std::iterator_traits<_RandomAccessIterator>::value_type; | ||
static_assert(__is_serial_tag_v<_Tag> || __is_parallel_forward_tag_v<_Tag>); | ||
__pattern_fill(_Tag{}, std::forward<_ExecutionPolicy>(__exec), __histogram_first, __histogram_first + __num_bins, | ||
_HistogramValueT{0}); | ||
__brick_histogram(__first, __last, __func, __histogram_first, typename _Tag::__is_vector{}); | ||
} | ||
|
||
template <class _IsVector, class _ExecutionPolicy, class _RandomAccessIterator1, class _Size, class _IdxHashFunc, | ||
class _RandomAccessIterator2> | ||
void | ||
__pattern_histogram(__parallel_tag<_IsVector>, _ExecutionPolicy&& __exec, _RandomAccessIterator1 __first, | ||
_RandomAccessIterator1 __last, _Size __num_bins, _IdxHashFunc __func, | ||
_RandomAccessIterator2 __histogram_first) | ||
{ | ||
using __backend_tag = typename __parallel_tag<_IsVector>::__backend_tag; | ||
using _HistogramValueT = typename std::iterator_traits<_RandomAccessIterator2>::value_type; | ||
using _DiffType = typename std::iterator_traits<_RandomAccessIterator2>::difference_type; | ||
|
||
_DiffType __n = __last - __first; | ||
if (__n > 0) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't insist... But there is a common good practice to process a shorter branch of
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I rearranged if and else, but did not return early and remove braces for else. |
||
{ | ||
__par_backend::__thread_enumerable_storage<std::vector<_HistogramValueT>> __tls{__num_bins, | ||
SergeyKopienko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_HistogramValueT{0}}; | ||
|
||
//main histogram loop | ||
//TODO: add defaulted grain-size option for __parallel_for and use larger one here to account for overhead | ||
__par_backend::__parallel_for( | ||
__backend_tag{}, __exec, __first, __last, | ||
[__func, &__tls](_RandomAccessIterator1 __first_local, _RandomAccessIterator1 __last_local) { | ||
__internal::__brick_histogram(__first_local, __last_local, __func, | ||
__tls.get_for_current_thread().begin(), _IsVector{}); | ||
}); | ||
// now accumulate temporary storage into output global histogram | ||
__par_backend::__parallel_for( | ||
__backend_tag{}, std::forward<_ExecutionPolicy>(__exec), __histogram_first, __histogram_first + __num_bins, | ||
[__histogram_first, &__tls](auto __global_histogram_first, auto __global_histogram_last) { | ||
_DiffType __local_n = __global_histogram_last - __global_histogram_first; | ||
std::uint32_t __num_temporary_copies = __tls.size(); | ||
mmichel11 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_DiffType __range_begin_id = __global_histogram_first - __histogram_first; | ||
SergeyKopienko marked this conversation as resolved.
Show resolved
Hide resolved
|
||
//initialize output global histogram with first local histogram via assign | ||
__internal::__brick_walk2_n(__tls.get_with_id(0).begin() + __range_begin_id, __local_n, | ||
__global_histogram_first, oneapi::dpl::__internal::__pstl_assign(), | ||
_IsVector{}); | ||
for (std::uint32_t __i = 1; __i < __num_temporary_copies; ++__i) | ||
{ | ||
//accumulate into output global histogram with other local histogram via += operator | ||
__internal::__brick_walk2_n( | ||
__tls.get_with_id(__i).begin() + __range_begin_id, __local_n, __global_histogram_first, | ||
[](_HistogramValueT __x, _HistogramValueT& __y) { __y += __x; }, _IsVector{}); | ||
} | ||
}); | ||
} | ||
else | ||
{ | ||
__pattern_fill(__parallel_tag<_IsVector>{}, std::forward<_ExecutionPolicy>(__exec), __histogram_first, | ||
__histogram_first + __num_bins, _HistogramValueT{0}); | ||
} | ||
} | ||
|
||
} // namespace __internal | ||
} // namespace dpl | ||
} // namespace oneapi | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
get_bin
return negative value?__brick_histogram
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes,
-1
is returned when the input element does not fall within any histogram bin. The correct behavior is to do nothing and skip this input element.Specification
"Input values that do not map to a defined bin are skipped silently."
I recently looked into expanding the bin helper interface to include a separate function to check bounds, and another to get the bin which assumes it is in bounds. I thought this might provide benefit by reducing the number of branches by 1, but I saw no performance benefit from this change for CPU or GPU. It is still something we could pursue in the future.