Skip to content

Commit

Permalink
Further help performance of indexing code in debug and sanitizer-enab…
Browse files Browse the repository at this point in the history
…led builds.
  • Loading branch information
Domagoj Šarić committed Apr 11, 2023
1 parent c53b46d commit a3e9453
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 39 deletions.
4 changes: 2 additions & 2 deletions include/kwk/detail/kumi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -919,8 +919,8 @@ namespace kumi
requires( (I0 <= size_v<Tuple>) && (I1 <= size_v<Tuple>) )
[[nodiscard]] constexpr
auto extract( Tuple const& t
, [[maybe_unused]] index_t<I0> const& i0
, [[maybe_unused]] index_t<I1> const& i1
, index_t<I0>
, index_t<I1>
) noexcept
{
return [&]<std::size_t... N>(std::index_sequence<N...>)
Expand Down
9 changes: 5 additions & 4 deletions include/kwk/detail/sequence/extent_builder.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace kwk::__
// Converts a sequence of value/joker/axis into a shape/stride descriptor type
//================================================================================================
template<typename SizeType, typename... Args>
KWK_FORCEINLINE constexpr auto as_descriptor(Args... args)
KWK_CONST KWK_TRIVIAL constexpr auto as_descriptor(Args... args)
{
if constexpr(sizeof...(Args) == 0) return combo<SizeType>{};
else
Expand All @@ -48,15 +48,15 @@ namespace kwk::__
}
};

return [&]<std::size_t... N>(std::index_sequence<N...>)
return [=]<std::size_t... N>(std::index_sequence<N...>)
{
return make_combo<SizeType>((convert(args, kumi::index<N>) * ...));
}(std::index_sequence_for<Args...>{});
}
}

template<typename SizeType, typename A>
KWK_FORCEINLINE constexpr auto as_descriptor(A const&)
KWK_CONST KWK_FORCEINLINE constexpr auto as_descriptor( A const & )
requires requires(A) { A::descriptor; }
{
return A::descriptor;
Expand Down Expand Up @@ -125,12 +125,13 @@ namespace kwk::__
, typename SizeType
, typename... Args
>
KWK_CONST KWK_FORCEINLINE
constexpr auto make_extent(Args... args)
requires( !duplicate_axis<decltype(as_descriptor<SizeType>(args...))>
&& (has_valid_index<decltype(as_descriptor<SizeType>(args...)),sizeof...(Args)>)
)
{
return [&]<std::size_t... N>(std::index_sequence<N...>)
return [=]<std::size_t... N>(std::index_sequence<N...>) KWK_LAMBDA_FORCEINLINE
{
constexpr std::int32_t sz = sizeof...(Args) - 1;
return Wrapper<as_descriptor<SizeType>(Args{}...)>
Expand Down
21 changes: 12 additions & 9 deletions include/kwk/detail/sequence/prefilled.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,21 +232,24 @@ namespace kwk::__
constexpr auto operator[](A) const noexcept = delete;

// Internal storage access for algorithms
constexpr storage_t & storage() noexcept { return static_cast<storage_t &>(*this); }
constexpr storage_t const& storage() const noexcept { return static_cast<storage_t const&>(*this); }
KWK_PURE KWK_TRIVIAL constexpr storage_t & storage() noexcept { return static_cast<storage_t &>(*this); }
KWK_PURE KWK_TRIVIAL constexpr storage_t const& storage() const noexcept { return static_cast<storage_t const&>(*this); }

// Total size of the array
static constexpr std::int32_t size() noexcept { return static_size; }

// Conversion to std::array
constexpr decltype(auto) as_array() const noexcept
KWK_PURE KWK_FORCEINLINE constexpr decltype(auto) as_array() const noexcept
{
return kumi::apply( [](auto... m)
{
return std::array<value_type,static_size>{static_cast<value_type>(m)...};
}
, *this
);
if constexpr (dynamic_size == static_size)
return storage();
else
return kumi::apply( [](auto... m)
{
return std::array<value_type,static_size>{static_cast<value_type>(m)...};
}
, *this
);
}

// Set a particular value
Expand Down
88 changes: 64 additions & 24 deletions include/kwk/utility/container/stride.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -174,53 +174,93 @@ namespace kwk

/// Indexing interface
template<std::convertible_to<size_type>... Is>
KWK_PURE KWK_FORCEINLINE constexpr
KWK_PURE constexpr
size_type linearize(Is... is) const noexcept
requires( sizeof...(Is) <= static_order )
{
return [=, *this]<int...i>(std::integer_sequence<int, i...>)
return [=, *this]<int...i>(std::integer_sequence<int, i...>) KWK_LAMBDA_FORCEINLINE
{
return (0 + ... + (get<i>(*this) * is));
}(std::make_integer_sequence<int, static_order>{});
}
};

//================================================================================================
//! @brief Generates a kwk::stride from a list of stride value or joker
//! @param ds Variadic pack of sizes
//================================================================================================
template<typename... Ds>
KWK_CONST KWK_FORCEINLINE
constexpr auto with_strides(Ds... ds) noexcept
{
return __::make_extent<kwk::stride,std::int32_t>(ds...);
}

template<kumi::product_type Ds>
KWK_CONST KWK_FORCEINLINE
constexpr auto with_strides(Ds ds) noexcept
{
return kumi::apply([](auto... s) KWK_LAMBDA_FORCEINLINE { return with_strides(s...); }, ds);
}

namespace __ // helpers for as_stride
{
KWK_CONST KWK_TRIVIAL constexpr auto make_stride(kumi::tuple<>, auto const... all_strides) noexcept { return with_strides(all_strides..., fixed<1>); }

template<typename AtleastOne, typename... Remaining>
KWK_CONST KWK_TRIVIAL constexpr auto make_stride(kumi::tuple<AtleastOne, Remaining...> const axis_tuple, auto const last_value, auto const... rightmost_values) noexcept
{
return make_stride
(
pop_back(axis_tuple),
back(axis_tuple) * last_value,
last_value, rightmost_values...
);
}

template<typename T, std::size_t size>
KWK_CONST constexpr auto make_fully_dynamic_stride(std::array<T, size> const axes) noexcept
{
return [&]<int... i>(std::integer_sequence<int, i...>) KWK_LAMBDA_FORCEINLINE
{
unsigned strides[size-1];
strides[0] = axes.back();
(
...,
(strides[i+1] = strides[i] * axes[size-2-i])
);
return with_strides(strides[size-2-i]..., axes.back(), fixed<1>);
}(std::make_integer_sequence<int, size-2>{});
}
} // namespace __

/// Converts a @ref kwk::shape into its corresponding @ref kwk::stride, conserving as much static
/// informations as possible.
/// information as possible.
template<auto Shape>
KWK_CONST constexpr
auto as_stride(shape<Shape> const s) noexcept
{
if constexpr(Shape.size() == 1) return stride<kumi::back(Shape)[1]>{};
if constexpr(Shape.static_size == 1 ) return with_strides( fixed<1>);
else if constexpr(Shape.static_size == 2 ) return with_strides(get<0>(Shape).value, fixed<1>);
else if constexpr(Shape.static_size == s.dynamic_size) return __::make_fully_dynamic_stride(s.storage()); // avoid kumi compile-time hoops for purely dynamic shapes
else
{
auto const d = kumi::fold_left( [](auto a, auto m){ return push_front(a, m * front(a)); }
# if 0 // FIXME: attempt to avoid the kumi foldable overhead - failed as it always produces fully dynamic strides (loses compile time information)?
return __::make_stride(kumi::extract(s,kumi::index<1>, kumi::index<Shape.size()-1>), kumi::back(s)); // major axis is irrelevant
# else

auto const d = kumi::fold_left( [](auto a, auto m) KWK_LAMBDA_FORCEINLINE { return push_front(a, m * front(a)); }
, s
, kumi::tuple{fixed<1>}
);

return [&]<std::size_t... I>(std::index_sequence<I...>, auto t)
return [=]<std::size_t... I>(std::index_sequence<I...>, auto t) KWK_LAMBDA_FORCEINLINE
{
return with_strides( (get<I>(Shape).base() = get<I>(t))...);
return with_strides((get<I>(Shape).base() = get<I>(t))...);
}(std::make_index_sequence<Shape.size()>{}, pop_front(d));
# endif
}
}

//================================================================================================
//! @brief Generates a kwk::stride from a list of stride value or joker
//! @param ds Variadic pack of sizes
//================================================================================================
template<typename... Ds>
constexpr auto with_strides(Ds... ds) noexcept
{
return __::make_extent<kwk::stride,std::int32_t>(ds...);
}

template<kumi::product_type Ds>
constexpr auto with_strides(Ds ds) noexcept
{
return kumi::apply([](auto... s) { return with_strides(s...); }, ds);
}
}

// Tuple interface adaptation
Expand All @@ -232,7 +272,7 @@ struct std::tuple_size<kwk::stride<Desc>>
template<std::size_t N, auto Desc>
struct std::tuple_element<N, kwk::stride<Desc>>
{
using type = typename kwk::stride<Desc>::size_type;
using type = typename kwk::stride<Desc>::size_type; // FIXME: is this the culprit - ignoring compile-time information/full axis type and always using size_type (same thing in other places)?
};

#if !defined(_MSC_VER)
Expand Down

0 comments on commit a3e9453

Please sign in to comment.