Skip to content
This repository was archived by the owner on Mar 28, 2023. It is now read-only.

[SYCL][ESIMD] Enhance enum logging support #917

Merged
merged 4 commits into from
Mar 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 45 additions & 24 deletions SYCL/ESIMD/api/functional/logger.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,34 +62,55 @@ template <> struct fp_hex_representation<double> : support_flag<true> {

} // namespace detail

// Provides generic stringification for logging purposes
template <typename T> static std::string stringify(T val) {
if constexpr (std::is_convertible_v<T, std::string>) {
return val;
} else if constexpr (type_traits::is_sycl_floating_point_v<T>) {
// Define the output precision based on the type precision itself
// For example, state 9 decimal digits for 32-bit floating point
const auto significand_decimal_digits = sizeof(T) * 2 + 1;

std::ostringstream out;
out.precision(significand_decimal_digits);
out << val << " [";
if constexpr (detail::fp_hex_representation<T>::is_supported()) {
// Print out hex representation using type-punning
using hex_type = typename detail::fp_hex_representation<T>::type;
const auto &representation = reinterpret_cast<const hex_type &>(val);
out << "0x" << std::hex << representation;
// Provides a stringification helper for safe specialization
// Benefits:
// - makes partial specialization possible
// - avoids unexpected behaviour for function specializations and overloads
template <typename T> struct StringMaker {
static std::string stringify(T val) {
if constexpr (std::is_convertible_v<T, std::string>) {
return val;
} else if constexpr (type_traits::is_sycl_floating_point_v<T>) {
// Define the output precision based on the type precision itself
// For example, state 9 decimal digits for 32-bit floating point
const auto significand_decimal_digits = sizeof(T) * 2 + 1;

std::ostringstream out;
out.precision(significand_decimal_digits);
out << val << " [";
if constexpr (detail::fp_hex_representation<T>::is_supported()) {
// Print out hex representation using type-punning
using hex_type = typename detail::fp_hex_representation<T>::type;
const auto &representation = reinterpret_cast<const hex_type &>(val);
out << "0x" << std::hex << representation;
} else {
// Make support gap explicit to address if required
out << " - ";
}
out << "]";
return out.str();
} else if constexpr (std::is_enum_v<T>) {
// Any enumeration requires explicit cast to the underlying type
// Please note that StringMaker can be safely specialized for any
// enumeration type for more human-readable logs if required
return std::to_string(static_cast<std::underlying_type_t<T>>(val));
} else {
// Make support gap explicit to address if required
out << " - ";
return std::to_string(val);
}
out << "]";
return out.str();
} else {
return std::to_string(val);
}
};

// Provides generic stringification for logging purposes
// To tweak for specific type, please:
// - either provide overload,
// - or specialize the StringMaker for this type
template <typename T> static std::string stringify(T val) {
return log::StringMaker<T>::stringify(val);
}

// Overload to improve performance a bit; works as the first-class citizen
inline const std::string &stringify(const std::string &val) { return val; }

// Print line to the log using a custom set of parameters
//
// Lambda can be used to print out any custom information,
Expand Down Expand Up @@ -138,7 +159,7 @@ template <typename... argsT> inline void print_line(const argsT &...args) {
// logging disabled
template <typename... argsT> inline void debug(const argsT &...args) {
#ifdef ESIMD_TESTS_VERBOSE_LOG
print_line(args);
print_line(args...);
#else
// Suppress unused variables warning
(static_cast<void>(args), ...);
Expand Down
42 changes: 33 additions & 9 deletions SYCL/ESIMD/api/functional/type_coverage.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#pragma once

#include "logger.hpp"
#include "type_traits.hpp"

#include <cassert>
Expand Down Expand Up @@ -103,16 +104,14 @@ template <typename T, T... values> struct value_pack {
}

// Factory function to generate the type pack with stringified values stored
// within
// within. Would work with or without specific StringMaker specializations.
// For example:
// const auto targets =
// value_pack<sycl::target, sycl::target::device>::generate_named();
//
static inline auto generate_named() {
if constexpr (std::is_enum_v<T>) {
// Any enumeration requires explicit cast to the underlying type
return named_type_pack<std::integral_constant<T, values>...>::generate(
std::to_string(static_cast<std::underlying_type_t<T>>(values))...);
} else {
return named_type_pack<std::integral_constant<T, values>...>::generate(
std::to_string(values)...);
}
return named_type_pack<std::integral_constant<T, values>...>::generate(
log::stringify(values)...);
}

// Factory function to generate the type pack with names given for each value
Expand All @@ -131,6 +130,31 @@ template <typename T, T... values> struct value_pack {
return named_type_pack<std::integral_constant<T, values>...>::generate(
std::forward<argsT>(args)...);
}

// Factory function to generate the type pack using generator function
//
// It could be especially usefull for value packs with enums. For example:
// enum class access {read, write};
// template <access ... values>
// using access_pack = value_pack<access, values...>;
//
// const auto generator = [&](const access& value) {
// switch (value) {
// case access:read:
// return "read access";
// break;
// ...
// };
// };
// const auto accesses =
// access_pack<access::read, access::write>::generate_named_by(generator);
//
template <typename GeneratorT>
static auto generate_named_by(const GeneratorT &nameGenerator) {
static_assert(std::is_invocable_v<GeneratorT, T>,
"Unexpected name generator type");
return generate_named(nameGenerator(values)...);
}
};

// Alias to use mainly for simd vector sizes; no overhead as alias doesn't
Expand Down