Skip to content

Commit

Permalink
Merge pull request #2149 from STEllAR-GROUP/fix_copy_optimized
Browse files Browse the repository at this point in the history
std::memmove copies bytes, use bytes*sizeof(type) when copying larger…
  • Loading branch information
hkaiser committed May 11, 2016
2 parents 2adabdf + 128c32f commit 73407c5
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 80 deletions.
92 changes: 12 additions & 80 deletions hpx/parallel/util/transfer.hpp
Expand Up @@ -7,6 +7,7 @@
#define HPX_PARALLEL_UTIL_TRANSFER_MAY_06_2016_0140PM

#include <hpx/config.hpp>
#include <hpx/traits/pointer_category.hpp>

#include <algorithm>
#include <cstring> // for std::memmove
Expand All @@ -20,79 +21,8 @@ namespace hpx { namespace parallel { namespace util
///////////////////////////////////////////////////////////////////////////
namespace detail
{
struct general_pointer_tag {};

template <typename Source, typename Dest>
inline general_pointer_tag
get_pointer_category(Source const&, Dest const&)
{
return general_pointer_tag();
}

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
// We know that we can optimize copy operations if the iterators are
// pointers and if the value_type is layout compatible.
struct trivially_copyable_pointer_tag : general_pointer_tag {};

template <typename Source, typename Dest>
struct pointer_category
{
typedef typename std::conditional<
std::integral_constant<bool,
sizeof(Source) == sizeof(Dest)
>::value &&
std::is_integral<Source>::value &&
std::is_integral<Dest>::value &&
!std::is_volatile<Source>::value &&
!std::is_volatile<Dest>::value &&
(std::is_same<bool, Source>::value ==
std::is_same<bool, Dest>::value),
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// every type is layout-compatible with itself
template <typename T>
struct pointer_category<T, T>
{
typedef typename std::conditional<
std::is_trivially_copyable<T>::value,
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// pointers are layout compatible
template <typename T>
struct pointer_category<T*, T const*>
{
typedef trivially_copyable_pointer_tag type;
};

// isolate iterators which are pointers and their value_types are
// assignable
template <typename Source, typename Dest>
inline typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename pointer_category<
typename std::remove_reference<Source>::type, Dest
>::type,
general_pointer_tag
>::type
get_pointer_category(Source* const&, Dest* const&)
{
typedef typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename pointer_category<
typename std::remove_reference<Source>::type, Dest
>::type,
general_pointer_tag
>::type category_type;

return category_type();
}

///////////////////////////////////////////////////////////////////////
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -102,10 +32,12 @@ namespace hpx { namespace parallel { namespace util
std::is_pointer<OutIter>::value,
"optimized copy is possible for pointer-iterators only");

typedef typename std::iterator_traits<InIter>::value_type data_type;

const char* const first_ch = reinterpret_cast<const char*>(first);
char* const dest_ch = reinterpret_cast<char*>(dest);

std::memmove(dest_ch, first_ch, count);
std::memmove(dest_ch, first_ch, count * sizeof(data_type));

std::advance(first, count);
std::advance(dest, count);
Expand All @@ -130,7 +62,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct copy_helper<trivially_copyable_pointer_tag>
struct copy_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -146,7 +78,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
copy_helper(InIter first, InIter last, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::copy_helper<category>::call(first, last, dest);
}

Expand All @@ -169,7 +101,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct copy_n_helper<trivially_copyable_pointer_tag>
struct copy_n_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -185,7 +117,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
copy_n_helper(InIter first, std::size_t count, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::copy_n_helper<category>::call(first, count, dest);
}

Expand All @@ -208,7 +140,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct move_helper<trivially_copyable_pointer_tag>
struct move_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -224,7 +156,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
move_helper(InIter first, InIter last, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::move_helper<category>::call(first, last, dest);
}

Expand All @@ -247,7 +179,7 @@ namespace hpx { namespace parallel { namespace util

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
template <>
struct move_n_helper<trivially_copyable_pointer_tag>
struct move_n_helper<hpx::traits::trivially_copyable_pointer_tag>
{
template <typename InIter, typename OutIter>
HPX_FORCEINLINE static std::pair<InIter, OutIter>
Expand All @@ -263,7 +195,7 @@ namespace hpx { namespace parallel { namespace util
HPX_FORCEINLINE std::pair<InIter, OutIter>
move_n_helper(InIter first, std::size_t count, OutIter dest)
{
typedef decltype(detail::get_pointer_category(first, dest)) category;
typedef decltype(hpx::traits::get_pointer_category(first, dest)) category;
return detail::move_n_helper<category>::call(first, count, dest);
}
}}}
Expand Down
10 changes: 10 additions & 0 deletions hpx/traits.hpp
Expand Up @@ -229,6 +229,16 @@ namespace hpx { namespace traits

template <typename T, typename Enable = void>
struct is_executor_parameters;

///////////////////////////////////////////////////////////////////////////
struct general_pointer_tag {};

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)
struct trivially_copyable_pointer_tag : general_pointer_tag {};
#endif

template <typename Source, typename Dest>
general_pointer_tag get_pointer_category(Source const&, Dest const&);
}}

#endif
95 changes: 95 additions & 0 deletions hpx/traits/pointer_category.hpp
@@ -0,0 +1,95 @@
// Copyright (c) 2016 Hartmut Kaiser
// Copyright (c) 2016 John Biddiscombe
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#if !defined(HPX_TRAITS_POINTER_CATEGORY_MAY_10_2016)
#define HPX_TRAITS_POINTER_CATEGORY_MAY_10_2016

#include <hpx/traits.hpp>

#include <type_traits>

// Select a copy tag type to enable optimization
// of copy/move operations if the iterators are
// pointers and if the value_type is layout compatible.

namespace hpx { namespace traits
{

template <typename Source, typename Dest>
inline general_pointer_tag
get_pointer_category(Source const&, Dest const&)
{
return general_pointer_tag();
}

#if defined(HPX_HAVE_CXX11_IS_TRIVIALLY_COPYABLE)

namespace detail {

template <typename Source, typename Dest>
struct pointer_category
{
typedef typename std::conditional<
std::integral_constant<bool,
sizeof(Source) == sizeof(Dest)
>::value &&
std::is_integral<Source>::value &&
std::is_integral<Dest>::value &&
!std::is_volatile<Source>::value &&
!std::is_volatile<Dest>::value &&
(std::is_same<bool, Source>::value ==
std::is_same<bool, Dest>::value),
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// every type is layout-compatible with itself
template <typename T>
struct pointer_category<T, T>
{
typedef typename std::conditional<
std::is_trivially_copyable<T>::value,
trivially_copyable_pointer_tag,
general_pointer_tag
>::type type;
};

// pointers are layout compatible
template <typename T>
struct pointer_category<T*, T const*>
{
typedef trivially_copyable_pointer_tag type;
};
}

// isolate iterators which are pointers and their value_types are
// assignable
template <typename Source, typename Dest>
inline typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename detail::pointer_category<
typename std::remove_const<Source>::type, Dest
>::type,
general_pointer_tag
>::type
get_pointer_category(Source* const&, Dest* const&)
{
typedef typename std::conditional<
std::is_assignable<Dest&, Source&>::value,
typename detail::pointer_category<
typename std::remove_const<Source>::type, Dest
>::type,
general_pointer_tag
>::type category_type;

return category_type();
}
#endif

}}

#endif

0 comments on commit 73407c5

Please sign in to comment.