//@HEADER // ************************************************************************ // // Kokkos v. 4.0 // Copyright (2022) National Technology & Engineering // Solutions of Sandia, LLC (NTESS). // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. // See https://kokkos.org/LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //@HEADER #ifndef KOKKOS_IMPL_PUBLIC_INCLUDE #include static_assert(false, "Including non-public Kokkos header files is not allowed."); #endif #ifndef KOKKOS_KOKKOS_TUNERS_HPP #define KOKKOS_KOKKOS_TUNERS_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace Kokkos { namespace Tools { namespace Experimental { // forward declarations SetOrRange make_candidate_set(size_t size, int64_t* data); bool have_tuning_tool(); size_t declare_output_type(const std::string&, Kokkos::Tools::Experimental::VariableInfo); void request_output_values(size_t, size_t, Kokkos::Tools::Experimental::VariableValue*); VariableValue make_variable_value(size_t, int64_t); VariableValue make_variable_value(size_t, double); SetOrRange make_candidate_range(double lower, double upper, double step, bool openLower, bool openUpper); size_t get_new_context_id(); void begin_context(size_t context_id); void end_context(size_t context_id); namespace Impl { /** We're going to take in search space descriptions * as nested maps, which aren't efficient to * iterate across by index. These are very similar * to nested maps, but better for index-based lookup */ template struct ValueHierarchyNode; template struct ValueHierarchyNode { std::vector root_values; std::vector sub_values; void add_root_value(const ValueType& in) noexcept { root_values.push_back(in); } void add_sub_container(const ContainedType& in) { sub_values.push_back(in); } const ValueType& get_root_value(const size_t index) const { return root_values[index]; } const ContainedType& get_sub_value(const size_t index) const { return sub_values[index]; } }; template struct ValueHierarchyNode { std::vector root_values; explicit ValueHierarchyNode(std::vector rv) : root_values(std::move(rv)) {} void add_root_value(const ValueType& in) noexcept { root_values.push_back(in); } const ValueType& get_root_value(const size_t index) const { return root_values[index]; } }; /** For a given nested map type, we need a way to * declare the equivalent ValueHierarchyNode * structure */ template struct MapTypeConverter; // Vectors are our lowest-level, no nested values template struct MapTypeConverter> { using type = ValueHierarchyNode; }; // Maps contain both the "root" types and sub-vectors template struct MapTypeConverter> { using type = ValueHierarchyNode::type>; }; /** * We also need to be able to construct a ValueHierarchyNode set from a * map */ template struct ValueHierarchyConstructor; // Vectors are our lowest-level, no nested values. Just fill in the fundamental // values template struct ValueHierarchyConstructor> { using return_type = typename MapTypeConverter>::type; static return_type build(const std::vector& in) { return return_type{in}; } }; // For maps, we need to fill in the fundamental values, and construct child // nodes template struct ValueHierarchyConstructor> { using return_type = typename MapTypeConverter>::type; static return_type build(const std::map& in) { return_type node_to_build; for (auto& entry : in) { node_to_build.add_root_value(entry.first); node_to_build.add_sub_container( ValueHierarchyConstructor::build(entry.second)); } return node_to_build; } }; /** * We're going to be declaring a sparse multidimensional * tuning space as a set of nested maps. The innermost level * will be a vector. The dimensionality of such a space is the number of * maps + 1. * * The following templates implement such logic recursively */ template struct get_space_dimensionality; // The dimensionality of a vector is 1 template struct get_space_dimensionality> { static constexpr int value = 1; }; // The dimensionality of a map is 1 (the map) plus the dimensionality // of the map's value type template struct get_space_dimensionality> { static constexpr int value = 1 + get_space_dimensionality::value; }; template struct n_dimensional_sparse_structure; template struct n_dimensional_sparse_structure { using type = std::vector; }; template struct n_dimensional_sparse_structure { using type = std::map::type>; }; /** * This is the ugly part of this implementation: mapping a set of doubles in * [0.0,1.0) into a point in this multidimensional space. We're going to * implement this concept recursively, building up a tuple at each level. */ // First, a helper to get the value in one dimension template struct DimensionValueExtractor; // At any given level, just return your value at that level template struct DimensionValueExtractor> { static RootType get(const ValueHierarchyNode& dimension, double fraction_to_traverse) { size_t index = dimension.root_values.size() * fraction_to_traverse; return dimension.get_root_value(index); } }; /** Now we're going to do the full "get a point in the space". * At a root level, we'll take in a ValueHierarchyNode and a set of doubles * representing the value in [0.0,1.0) we want to pick */ // At the bottom level, we have one double and a base-level ValueHierarchyNode template struct GetMultidimensionalPoint; template struct GetMultidimensionalPoint, double> { using node_type = ValueHierarchyNode; using return_type = std::tuple; static return_type build(const node_type& in, double index) { return std::make_tuple(DimensionValueExtractor::get(in, index)); } }; // At levels above the bottom, we tuple_cat the result of our child on the end // of our own tuple template struct GetMultidimensionalPoint, double, Indices...> { using node_type = ValueHierarchyNode; using sub_tuple = typename GetMultidimensionalPoint::return_type; using return_type = decltype(std::tuple_cat( std::declval>(), std::declval())); static return_type build(const node_type& in, double fraction_to_traverse, Indices... indices) { size_t index = in.sub_values.size() * fraction_to_traverse; auto dimension_value = std::make_tuple( DimensionValueExtractor::get(in, fraction_to_traverse)); return std::tuple_cat(dimension_value, GetMultidimensionalPoint::build( in.get_sub_value(index), indices...)); } }; template auto get_point_helper(const PointType& in, const ArrayType& indices, std::index_sequence) { using helper = GetMultidimensionalPoint< PointType, decltype(std::get(std::declval()).value.double_value)...>; return helper::build(in, std::get(indices).value.double_value...); } template struct GetPoint; template struct GetPoint< PointType, std::array> { using index_set_type = std::array; static auto build(const PointType& in, const index_set_type& indices) { return get_point_helper(in, indices, std::make_index_sequence{}); } }; template auto get_point(const PointType& point, const ArrayType& indices) { return GetPoint::build(point, indices); } } // namespace Impl template