mirror of
https://github.com/boostorg/log.git
synced 2026-02-10 23:42:22 +00:00
265 lines
8.1 KiB
C++
265 lines
8.1 KiB
C++
/*
|
|
* Copyright Andrey Semashev 2007 - 2013.
|
|
* 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)
|
|
*/
|
|
/*!
|
|
* \file dump.cpp
|
|
* \author Andrey Semashev
|
|
* \date 03.05.2013
|
|
*
|
|
* \brief This header is the Boost.Log library implementation, see the library documentation
|
|
* at http://www.boost.org/libs/log/doc/log.html.
|
|
*/
|
|
|
|
#include <ostream>
|
|
#include <boost/cstdint.hpp>
|
|
#include <boost/log/utility/manipulators/dump.hpp>
|
|
#if defined(_MSC_VER)
|
|
#include "windows_version.hpp"
|
|
#include <windows.h>
|
|
#include <intrin.h> // __cpuid
|
|
#endif
|
|
#include <boost/log/detail/header.hpp>
|
|
|
|
namespace boost {
|
|
|
|
BOOST_LOG_OPEN_NAMESPACE
|
|
|
|
namespace aux {
|
|
|
|
#if defined(BOOST_LOG_USE_SSSE3)
|
|
extern dump_data_char_t dump_data_char_ssse3;
|
|
extern dump_data_wchar_t dump_data_wchar_ssse3;
|
|
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
|
extern dump_data_char16_t dump_data_char16_ssse3;
|
|
#endif
|
|
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
|
extern dump_data_char32_t dump_data_char32_ssse3;
|
|
#endif
|
|
#endif
|
|
#if defined(BOOST_LOG_USE_AVX2)
|
|
extern dump_data_char_t dump_data_char_avx2;
|
|
extern dump_data_wchar_t dump_data_wchar_avx2;
|
|
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
|
extern dump_data_char16_t dump_data_char16_avx2;
|
|
#endif
|
|
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
|
extern dump_data_char32_t dump_data_char32_avx2;
|
|
#endif
|
|
#endif
|
|
|
|
enum { stride = 256 };
|
|
|
|
extern const char g_lowercase_dump_char_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
|
|
extern const char g_uppercase_dump_char_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
|
|
|
template< typename CharT >
|
|
void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
|
|
{
|
|
typedef CharT char_type;
|
|
|
|
char_type buf[stride * 3u];
|
|
|
|
const char* const char_table = (strm.flags() & std::ios_base::uppercase) ? g_uppercase_dump_char_table : g_lowercase_dump_char_table;
|
|
const std::size_t stride_count = size / stride, tail_size = size % stride;
|
|
|
|
const uint8_t* p = static_cast< const uint8_t* >(data);
|
|
char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
|
|
char_type* buf_end = buf + sizeof(buf) / sizeof(*buf);
|
|
|
|
for (std::size_t i = 0; i < stride_count; ++i)
|
|
{
|
|
char_type* b = buf;
|
|
for (unsigned int j = 0; j < stride; ++j, b += 3u, ++p)
|
|
{
|
|
uint32_t n = *p;
|
|
b[0] = static_cast< char_type >(' ');
|
|
b[1] = static_cast< char_type >(char_table[n >> 4]);
|
|
b[2] = static_cast< char_type >(char_table[n & 0x0F]);
|
|
}
|
|
|
|
strm.write(buf_begin, buf_end - buf_begin);
|
|
buf_begin = buf;
|
|
}
|
|
|
|
if (tail_size > 0)
|
|
{
|
|
char_type* b = buf;
|
|
unsigned int i = 0;
|
|
do
|
|
{
|
|
uint32_t n = *p;
|
|
b[0] = static_cast< char_type >(' ');
|
|
b[1] = static_cast< char_type >(char_table[n >> 4]);
|
|
b[2] = static_cast< char_type >(char_table[n & 0x0F]);
|
|
++i;
|
|
++p;
|
|
b += 3u;
|
|
}
|
|
while (i < tail_size);
|
|
|
|
strm.write(buf_begin, b - buf_begin);
|
|
}
|
|
}
|
|
|
|
BOOST_LOG_API dump_data_char_t* dump_data_char = &dump_data_generic< char >;
|
|
BOOST_LOG_API dump_data_wchar_t* dump_data_wchar = &dump_data_generic< wchar_t >;
|
|
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
|
BOOST_LOG_API dump_data_char16_t* dump_data_char16 = &dump_data_generic< char16_t >;
|
|
#endif
|
|
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
|
BOOST_LOG_API dump_data_char32_t* dump_data_char32 = &dump_data_generic< char32_t >;
|
|
#endif
|
|
|
|
#if defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
|
|
|
|
BOOST_LOG_ANONYMOUS_NAMESPACE {
|
|
|
|
struct function_pointer_initializer
|
|
{
|
|
function_pointer_initializer()
|
|
{
|
|
// First, let's check for the max supported cpuid function
|
|
uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
|
|
cpuid(eax, ebx, ecx, edx);
|
|
|
|
const uint32_t max_cpuid_function = eax;
|
|
if (max_cpuid_function >= 1)
|
|
{
|
|
eax = 1;
|
|
ebx = ecx = edx = 0;
|
|
cpuid(eax, ebx, ecx, edx);
|
|
|
|
// Check for SSSE3 support
|
|
if (ecx & (1u << 9))
|
|
enable_ssse3();
|
|
|
|
#if defined(BOOST_LOG_USE_AVX2)
|
|
if (max_cpuid_function >= 7)
|
|
{
|
|
// To check for AVX2 availability we also need to verify that OS supports it
|
|
// Check that OSXSAVE is supported by CPU
|
|
if (ecx & (1u << 27))
|
|
{
|
|
// Check that it is used by the OS
|
|
bool mmstate = false;
|
|
#if defined(__GNUC__)
|
|
// Get the XFEATURE_ENABLED_MASK register
|
|
__asm__ __volatile__
|
|
(
|
|
"xgetbv\n\t"
|
|
: "=a" (eax), "=d" (edx)
|
|
: "c" (0)
|
|
);
|
|
mmstate = (eax & 6U) == 6U;
|
|
#elif defined(_MSC_VER)
|
|
// MSVC does not have an intrinsic for xgetbv, we have to query OS
|
|
HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
|
|
if (hKernel32)
|
|
{
|
|
typedef uint64_t (__stdcall* get_enabled_extended_features_t)(uint64_t);
|
|
get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)GetProcAddress(hKernel32, "GetEnabledExtendedFeatures");
|
|
if (get_enabled_extended_features)
|
|
{
|
|
// XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6
|
|
mmstate = get_enabled_extended_features(6u) == 6u;
|
|
}
|
|
}
|
|
#else
|
|
#error Boost.Log: Unexpected compiler
|
|
#endif
|
|
|
|
if (mmstate)
|
|
{
|
|
// Finally, check for AVX2 support in CPU
|
|
eax = 7;
|
|
ebx = ecx = edx = 0;
|
|
cpuid(eax, ebx, ecx, edx);
|
|
|
|
if (ebx & (1U << 5))
|
|
enable_avx2();
|
|
}
|
|
}
|
|
}
|
|
#endif // defined(BOOST_LOG_USE_AVX2)
|
|
}
|
|
}
|
|
|
|
private:
|
|
static void cpuid(uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx)
|
|
{
|
|
#if defined(__GNUC__)
|
|
#if defined(__i386__) && defined(__PIC__) && __PIC__ != 0
|
|
// We have to backup ebx in 32 bit PIC code because it is reserved by the ABI
|
|
uint32_t ebx_backup;
|
|
__asm__ __volatile__
|
|
(
|
|
"movl %%ebx, %0\n\t"
|
|
"movl %1, %%ebx\n\t"
|
|
"cpuid\n\t"
|
|
"movl %%ebx, %1\n\t"
|
|
"movl %0, %%ebx\n\t"
|
|
: "=m" (ebx_backup), "+m" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx)
|
|
);
|
|
#else
|
|
__asm__ __volatile__
|
|
(
|
|
"cpuid\n\t"
|
|
: "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)
|
|
);
|
|
#endif
|
|
#elif defined(_MSC_VER)
|
|
int regs[4] = {};
|
|
__cpuid(regs, eax);
|
|
eax = regs[0];
|
|
ebx = regs[1];
|
|
ecx = regs[2];
|
|
edx = regs[3];
|
|
#else
|
|
#error Boost.Log: Unexpected compiler
|
|
#endif
|
|
}
|
|
|
|
static void enable_ssse3()
|
|
{
|
|
dump_data_char = &dump_data_char_ssse3;
|
|
dump_data_wchar = &dump_data_wchar_ssse3;
|
|
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
|
dump_data_char16 = &dump_data_char16_ssse3;
|
|
#endif
|
|
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
|
dump_data_char32 = &dump_data_char32_ssse3;
|
|
#endif
|
|
}
|
|
|
|
#if defined(BOOST_LOG_USE_AVX2)
|
|
static void enable_avx2()
|
|
{
|
|
dump_data_char = &dump_data_char_avx2;
|
|
dump_data_wchar = &dump_data_wchar_avx2;
|
|
#if !defined(BOOST_NO_CXX11_CHAR16_T)
|
|
dump_data_char16 = &dump_data_char16_avx2;
|
|
#endif
|
|
#if !defined(BOOST_NO_CXX11_CHAR32_T)
|
|
dump_data_char32 = &dump_data_char32_avx2;
|
|
#endif
|
|
}
|
|
#endif // defined(BOOST_LOG_USE_AVX2)
|
|
};
|
|
|
|
static function_pointer_initializer g_function_pointer_initializer;
|
|
|
|
} // namespace
|
|
|
|
#endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
|
|
|
|
} // namespace aux
|
|
|
|
BOOST_LOG_CLOSE_NAMESPACE // namespace log
|
|
|
|
} // namespace boost
|
|
|
|
#include <boost/log/detail/footer.hpp>
|