Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r84155 - in trunk: boost/log/utility/manipulators libs/log/build libs/log/src libs/log/test/performance
From: andrey.semashev_at_[hidden]
Date: 2013-05-05 17:11:21


Author: andysem
Date: 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
New Revision: 84155
URL: http://svn.boost.org/trac/boost/changeset/84155

Log:
Added SIMD versions of dump manipulator. Fixed performance tests compilation.
Added:
   trunk/libs/log/build/architecture.jam (contents, props changed)
   trunk/libs/log/src/dump_avx2.cpp (contents, props changed)
   trunk/libs/log/src/dump_ssse3.cpp (contents, props changed)
   trunk/libs/log/test/performance/dump.cpp (contents, props changed)
Text files modified:
   trunk/boost/log/utility/manipulators/dump.hpp | 33 +++++
   trunk/libs/log/build/Jamfile.v2 | 220 ++++++++++++++++++++++++++++++++++++++++
   trunk/libs/log/src/dump.cpp | 184 ++++++++++++++++++++++++++++++--
   trunk/libs/log/test/performance/Jamfile.v2 | 4
   trunk/libs/log/test/performance/record_emission.cpp | 2
   5 files changed, 426 insertions(+), 17 deletions(-)

Modified: trunk/boost/log/utility/manipulators/dump.hpp
==============================================================================
--- trunk/boost/log/utility/manipulators/dump.hpp (original)
+++ trunk/boost/log/utility/manipulators/dump.hpp 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -30,8 +30,37 @@
 
 namespace aux {
 
-template< typename CharT >
-BOOST_LOG_API void dump_data(const void* data, std::size_t size, std::basic_ostream< CharT >& strm);
+typedef void dump_data_char_t(const void* data, std::size_t size, std::basic_ostream< char >& strm);
+extern BOOST_LOG_API dump_data_char_t* dump_data_char;
+BOOST_LOG_FORCEINLINE void dump_data(const void* data, std::size_t size, std::basic_ostream< char >& strm)
+{
+ (dump_data_char)(data, size, strm);
+}
+
+typedef void dump_data_wchar_t(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm);
+extern BOOST_LOG_API dump_data_wchar_t* dump_data_wchar;
+BOOST_LOG_FORCEINLINE void dump_data(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm)
+{
+ (dump_data_wchar)(data, size, strm);
+}
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+typedef void dump_data_char16_t(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm);
+extern BOOST_LOG_API dump_data_char16_t* dump_data_char16;
+BOOST_LOG_FORCEINLINE void dump_data(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm)
+{
+ (dump_data_char16)(data, size, strm);
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+typedef void dump_data_char32_t(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm);
+extern BOOST_LOG_API dump_data_char32_t* dump_data_char32;
+BOOST_LOG_FORCEINLINE void dump_data(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm)
+{
+ (dump_data_char32)(data, size, strm);
+}
+#endif
 
 template< std::size_t SizeV, typename R >
 struct enable_dump_size_based

Modified: trunk/libs/log/build/Jamfile.v2
==============================================================================
--- trunk/libs/log/build/Jamfile.v2 (original)
+++ trunk/libs/log/build/Jamfile.v2 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -5,9 +5,13 @@
 # http://www.boost.org/LICENSE_1_0.txt)
 #
 
+import common ;
 import modules ;
 import os ;
 import feature ;
+import version ;
+import property ;
+import architecture ;
 using mc ;
 
 lib psapi ;
@@ -23,9 +27,41 @@
 feature.feature logapi : unix winnt : propagated ;
 feature.set-default logapi : [ default_logapi ] ;
 
+rule select-instruction-set ( properties * )
+{
+ local result ;
+
+ if <architecture>x86 in $(properties) && <address-model>32 in $(properties)
+ {
+ result = [ property.select <instruction-set> : $(properties) ] ;
+ if $(result)
+ {
+ if $(result) = <instruction-set>i386 || $(result) = <instruction-set>i486
+ {
+ if ! $(.annouced-failure)
+ {
+ ECHO Boost.Log is not supported on the specified target CPU and will not be built. At least i586 class CPU is required. ;
+ .annouced-failure = 1 ;
+ }
+ result = <build>no ;
+ }
+ }
+ else
+ {
+ # We build for Pentium Pro and later CPUs by default. This is used as the target in many Linux distributions, and Windows and OS X also seem to not support older CPUs.
+ result = <instruction-set>i686 ;
+ }
+ }
+
+ return $(result) ;
+}
+
 project boost/log
     : source-location ../src
     : requirements
+ [ architecture.architecture ]
+ [ architecture.address-model ]
+ <conditional>@select-instruction-set
         <define>BOOST_SPIRIT_USE_PHOENIX_V3=1
         <define>BOOST_THREAD_DONT_USE_CHRONO=1 # Don't introduce false dependency on Boost.Chrono
         <logapi>unix:<define>BOOST_LOG_USE_NATIVE_SYSLOG=1
@@ -95,9 +131,191 @@
     dump.cpp
     ;
 
+local BOOST_LOG_COMMON_SSSE3_SRC =
+ dump_ssse3
+ ;
+
+local BOOST_LOG_COMMON_AVX2_SRC =
+ dump_avx2
+ ;
+
+rule ssse3-targets-cond ( properties * )
+{
+ local result = <build>no ;
+
+ if <architecture>x86 in $(properties)
+ {
+ if <toolset>gcc in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-gcc:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ if ! [ version.version-less $(version) : 4 3 ]
+ {
+ result = <cxxflags>"-march=core2 -msse -msse2 -msse3 -mssse3" ;
+ }
+ }
+ else if <toolset>msvc in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-msvc:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ if ! [ version.version-less $(version) : 9 0 ]
+ {
+ # MSVC doesn't really care about these switches, all SSE intrinsics are always available, but still...
+ result = <cxxflags>"/arch:SSE2" ;
+ }
+ }
+ else if <toolset>clang in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-clang:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ # I don't know which version started to support SSSE3, but we don't support versions before 3.2 anyway and it has support for SSSE3
+ if ! [ version.version-less $(version) : 3 2 ]
+ {
+ result = <cxxflags>"-march=core2 -msse -msse2 -msse3 -mssse3" ;
+ }
+ }
+ else if <toolset>intel in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-intel:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ if ! [ version.version-less $(version) : 10 0 ]
+ {
+ if <toolset-intel:platform>win in $(properties)
+ {
+ if ! [ version.version-less $(version) : 11 0 ]
+ {
+ result = <cxxflags>"/QxSSSE3" ;
+ }
+ else
+ {
+ result = <cxxflags>"/QxT" ;
+ }
+ }
+ else
+ {
+ result = <cxxflags>"-march=core2 -msse -msse2 -msse3 -mssse3" ;
+ }
+ }
+ }
+ }
+
+# if ! <build>no in $(result)
+# {
+# ECHO Boost.Log: Using SSSE3 optimized implementation ;
+# }
+# ECHO $(result) ;
+
+ return $(result) ;
+}
+
+for local src in $(BOOST_LOG_COMMON_SSSE3_SRC)
+{
+ obj $(src)
+ : ## sources ##
+ $(src).cpp
+ : ## requirements ##
+ <conditional>@ssse3-targets-cond
+ <link>shared:<define>BOOST_LOG_DLL
+ <define>BOOST_LOG_BUILDING_THE_LIB=1
+ : ## default-build ##
+ : ## usage-requirements ##
+ <define>BOOST_LOG_USE_SSSE3
+ ;
+}
+
+
+rule avx2-targets-cond ( properties * )
+{
+ local result = <build>no ;
+
+ if <architecture>x86 in $(properties)
+ {
+ if <toolset>gcc in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-gcc:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ if ! [ version.version-less $(version) : 4 7 ]
+ {
+ result = <cxxflags>"-march=core-avx2 -mavx -mavx2" ;
+ }
+ }
+ else if <toolset>msvc in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-msvc:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ if ! [ version.version-less $(version) : 11 0 ]
+ {
+ result = <cxxflags>"/arch:AVX" ;
+ }
+ }
+ else if <toolset>clang in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-clang:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ # I don't know which version started to support AVX2, but we don't support versions before 3.2 anyway and it has support for AVX2
+ if ! [ version.version-less $(version) : 3 2 ]
+ {
+ result = <cxxflags>"-march=core-avx2 -mavx -mavx2" ;
+ }
+ }
+ else if <toolset>intel in $(properties)
+ {
+ local string_version = [ feature.get-values "toolset-intel:version" : $(properties) ] ;
+ local version = [ SPLIT_BY_CHARACTERS $(string_version) : "." ] ;
+
+ # AVX2 support added in Composer XE 2011 Update 7, while the original Composer XE 2011 had icc version 12.
+ # I don't know what version Update 7 had, so to be on the safe side enable this optimization since version 13.
+ if ! [ version.version-less $(version) : 13 0 ]
+ {
+ if <toolset-intel:platform>win in $(properties)
+ {
+ result = <cxxflags>"/QxAVX2" ;
+ }
+ else
+ {
+ result = <cxxflags>"-march=core-avx2 -mavx -mavx2" ;
+ }
+ }
+ }
+ }
+
+# if ! <build>no in $(result)
+# {
+# ECHO Boost.Log: Using AVX2 optimized implementation ;
+# }
+# ECHO $(result) ;
+
+ return $(result) ;
+}
+
+for local src in $(BOOST_LOG_COMMON_AVX2_SRC)
+{
+ obj $(src)
+ : ## sources ##
+ $(src).cpp
+ : ## requirements ##
+ <conditional>@avx2-targets-cond
+ <link>shared:<define>BOOST_LOG_DLL
+ <define>BOOST_LOG_BUILDING_THE_LIB=1
+ : ## default-build ##
+ : ## usage-requirements ##
+ <define>BOOST_LOG_USE_AVX2
+ ;
+}
+
+
 lib boost_log
     : ## sources ##
         $(BOOST_LOG_COMMON_SRC)
+ $(BOOST_LOG_COMMON_SSSE3_SRC)
+ $(BOOST_LOG_COMMON_AVX2_SRC)
       ## winnt sources ##
         $(BOOST_LOG_MC_SRC)
         event_log_backend.cpp
@@ -118,6 +336,8 @@
 lib boost_log
     : ## sources ##
         $(BOOST_LOG_COMMON_SRC)
+ $(BOOST_LOG_COMMON_SSSE3_SRC)
+ $(BOOST_LOG_COMMON_AVX2_SRC)
       ## unix sources ##
     : ## requirements ##
         <link>shared:<define>BOOST_LOG_DLL

Added: trunk/libs/log/build/architecture.jam
==============================================================================
--- (empty file)
+++ trunk/libs/log/build/architecture.jam 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -0,0 +1,80 @@
+# architecture.jam
+#
+# Copyright 2012 Steven Watanabe
+#
+# 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)
+
+import configure ;
+import project ;
+import path ;
+import property ;
+
+local here = [ modules.binding $(__name__) ] ;
+
+project.push-current [ project.current ] ;
+project.load [ path.join [ path.make $(here:D) ] ../config ] ;
+project.pop-current ;
+
+rule deduce-address-model ( properties * )
+{
+ local result = [ property.select <address-model> : $(properties) ] ;
+ if $(result)
+ {
+ return $(result) ;
+ }
+ else
+ {
+ if [ configure.builds /boost/architecture//32 : $(properties) : 32-bit ]
+ {
+ return <address-model>32 ;
+ }
+ else if [ configure.builds /boost/architecture//64 : $(properties) : 64-bit ]
+ {
+ return <address-model>64 ;
+ }
+ }
+}
+
+rule address-model ( )
+{
+ return <conditional>@architecture.deduce-address-model ;
+}
+
+rule deduce-architecture ( properties * )
+{
+ local result = [ property.select <architecture> : $(properties) ] ;
+ if $(result)
+ {
+ return $(result) ;
+ }
+ else
+ {
+ if [ configure.builds /boost/architecture//x86 : $(properties) : x86 ]
+ {
+ return <architecture>x86 ;
+ }
+ else if [ configure.builds /boost/architecture//arm : $(properties) : arm ]
+ {
+ return <architecture>arm ;
+ }
+ else if [ configure.builds /boost/architecture//mips1 : $(properties) : mips1 ]
+ {
+ return <architecture>mips1 ;
+ }
+ else if [ configure.builds /boost/architecture//power : $(properties) : power ]
+ {
+ return <architecture>power ;
+ }
+ else if [ configure.builds /boost/architecture//sparc : $(properties) : sparc ]
+ {
+ return <architecture>sparc ;
+ }
+ }
+}
+
+rule architecture ( )
+{
+ return <conditional>@architecture.deduce-architecture ;
+}

Modified: trunk/libs/log/src/dump.cpp
==============================================================================
--- trunk/libs/log/src/dump.cpp (original)
+++ trunk/libs/log/src/dump.cpp 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -16,6 +16,11 @@
 #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 {
@@ -24,19 +29,40 @@
 
 namespace aux {
 
-enum { stride = 64 };
+#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 };
 
-static const char g_lowercase_char_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
-static const char g_uppercase_char_table[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+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(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
+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_char_table : g_lowercase_char_table;
+ 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);
@@ -78,18 +104,149 @@
     }
 }
 
-template BOOST_LOG_API
-void dump_data< char >(const void* data, std::size_t size, std::basic_ostream< char >& strm);
-template BOOST_LOG_API
-void dump_data< wchar_t >(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm);
+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 (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)
+ 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();
+ }
+ }
+ }
+ }
+ }
+
+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)
-template BOOST_LOG_API
-void dump_data< char16_t >(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm);
+ dump_data_char16 = &dump_data_char16_ssse3;
 #endif
 #if !defined(BOOST_NO_CXX11_CHAR32_T)
-template BOOST_LOG_API
-void dump_data< char32_t >(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm);
+ dump_data_char32 = &dump_data_char32_ssse3;
 #endif
+ }
+
+ 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
+ }
+};
+
+static function_pointer_initializer g_function_pointer_initializer;
+
+} // namespace
+
+#endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
 
 } // namespace aux
 
@@ -98,4 +255,3 @@
 } // namespace boost
 
 #include <boost/log/detail/footer.hpp>
-

Added: trunk/libs/log/src/dump_avx2.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/log/src/dump_avx2.cpp 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -0,0 +1,270 @@
+/*
+ * 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_avx2.cpp
+ * \author Andrey Semashev
+ * \date 05.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.
+ */
+
+// NOTE: You should generally avoid including headers as much as possible here, because this file
+// is compiled with special compiler options, and any included header may result in generation of
+// unintended code with these options and violation of ODR.
+#include <ostream>
+#include <immintrin.h>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/config.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+extern const char g_lowercase_dump_char_table[];
+extern const char g_uppercase_dump_char_table[];
+
+template< typename CharT >
+extern void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm);
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+enum
+{
+ packs_per_stride = 32,
+ stride = packs_per_stride * 16
+};
+
+union xmm_constant
+{
+ uint8_t as_bytes[16];
+ __m128i as_mm;
+};
+
+static const xmm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }};
+static const xmm_constant mm_9 = {{ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }};
+static const xmm_constant mm_char_0 = {{ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' }};
+static const xmm_constant mm_char_space_mask = {{ ' ', 0, 0, ' ', 0, 0, ' ', 0, 0, ' ', 0, 0, ' ', 0, 0, ' ' }};
+static const xmm_constant mm_shuffle_pattern1 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80 }};
+static const xmm_constant mm_shuffle_pattern2 = {{ 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10 }};
+static const xmm_constant mm_shuffle_pattern3 = {{ 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15 }};
+
+//! Dumps a pack of input data into a string of 8 bit ASCII characters
+static BOOST_LOG_FORCEINLINE void dump_pack(__m128i mm_char_10_to_a, __m128i mm_input, __m128i& mm_output1, __m128i& mm_output2, __m128i& mm_output3)
+{
+ // Split half-bytes
+ __m128i mm_input_hi = _mm_and_si128(_mm_srli_epi16(mm_input, 4), mm_15.as_mm);
+ __m128i mm_input_lo = _mm_and_si128(mm_input, mm_15.as_mm);
+
+ // Stringize each of the halves
+ __m128i mm_addend_hi = _mm_cmpgt_epi8(mm_input_hi, mm_9.as_mm);
+ __m128i mm_addend_lo = _mm_cmpgt_epi8(mm_input_lo, mm_9.as_mm);
+ mm_addend_hi = _mm_and_si128(mm_char_10_to_a, mm_addend_hi);
+ mm_addend_lo = _mm_and_si128(mm_char_10_to_a, mm_addend_lo);
+
+ mm_input_hi = _mm_add_epi8(mm_input_hi, mm_char_0.as_mm);
+ mm_input_lo = _mm_add_epi8(mm_input_lo, mm_char_0.as_mm);
+
+ mm_input_hi = _mm_add_epi8(mm_input_hi, mm_addend_hi);
+ mm_input_lo = _mm_add_epi8(mm_input_lo, mm_addend_lo);
+
+ // Join them back together
+ __m128i mm_1 = _mm_unpacklo_epi8(mm_input_hi, mm_input_lo);
+ __m128i mm_2 = _mm_unpackhi_epi8(mm_input_hi, mm_input_lo);
+
+ // Insert spaces between stringized bytes:
+ // |0123456789abcdef|0123456789abcdef|
+ // | 01 23 45 67 89 |ab cd ef 01 23 4|5 67 89 ab cd ef|
+ mm_output1 = _mm_shuffle_epi8(mm_1, mm_shuffle_pattern1.as_mm);
+ mm_output2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 10), mm_shuffle_pattern2.as_mm);
+ mm_output3 = _mm_shuffle_epi8(mm_2, mm_shuffle_pattern3.as_mm);
+
+ __m128i mm_char_space = mm_char_space_mask.as_mm;
+ mm_output1 = _mm_or_si128(mm_output1, mm_char_space);
+ mm_char_space = _mm_srli_si128(mm_char_space, 1);
+ mm_output2 = _mm_or_si128(mm_output2, mm_char_space);
+ mm_char_space = _mm_srli_si128(mm_char_space, 1);
+ mm_output3 = _mm_or_si128(mm_output3, mm_char_space);
+}
+
+template< typename CharT >
+BOOST_LOG_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf)
+{
+ switch (sizeof(CharT))
+ {
+ case 1:
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars);
+ break;
+
+ case 2:
+ {
+ __m128i mm_0 = _mm_setzero_si128();
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi8(mm_chars, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi8(mm_chars, mm_0));
+ }
+ break;
+
+ case 4:
+ {
+ __m128i mm_0 = _mm_setzero_si128();
+ __m128i mm = _mm_unpacklo_epi8(mm_chars, mm_0);
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi16(mm, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi16(mm, mm_0));
+ mm = _mm_unpackhi_epi8(mm_chars, mm_0);
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 2, _mm_unpacklo_epi16(mm, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 3, _mm_unpackhi_epi16(mm, mm_0));
+ }
+ break;
+ }
+}
+
+template< typename CharT >
+BOOST_LOG_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
+{
+ typedef CharT char_type;
+
+ char_type buf_storage[stride * 3u + 16u];
+ // Align the temporary buffer at 16 bytes
+ char_type* const buf = buf_storage + (16u - ((std::size_t)(char_type*)buf_storage & 15u));
+ char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
+ char_type* buf_end = buf + stride * 3u;
+
+ __m128i mm_char_10_to_a;
+ if (strm.flags() & std::ios_base::uppercase)
+ mm_char_10_to_a = _mm_set1_epi32(0x07070707); // '9' is 0x39 and 'A' is 0x41 in ASCII, so we have to add 0x07 to 0x3A to get uppercase letters
+ else
+ mm_char_10_to_a = _mm_set1_epi32(0x27272727); // ...and 'a' is 0x61, which means we have to add 0x27 to 0x3A to get lowercase letters
+
+ // First, check the input alignment
+ const uint8_t* p = static_cast< const uint8_t* >(data);
+ if (const std::size_t prealign_size = ((16u - ((std::size_t)p & 15u)) & 15u))
+ {
+ __m128i mm_input = _mm_lddqu_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+
+ strm.write(buf_begin, prealign_size * 3u - 1u);
+ buf_begin = buf;
+ size -= prealign_size;
+ p += prealign_size;
+ }
+
+ const std::size_t stride_count = size / stride;
+ std::size_t tail_size = size % stride;
+ for (std::size_t i = 0; i < stride_count; ++i)
+ {
+ char_type* b = buf;
+ for (unsigned int j = 0; j < packs_per_stride; ++j, b += 3u * 16u, p += 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+ }
+
+ strm.write(buf_begin, buf_end - buf_begin);
+ buf_begin = buf;
+ }
+
+ if (tail_size > 0)
+ {
+ char_type* b = buf;
+ while (tail_size >= 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+ b += 3u * 16u;
+ p += 16u;
+ tail_size -= 16u;
+ }
+
+ const char* const char_table = (strm.flags() & std::ios_base::uppercase) ? g_uppercase_dump_char_table : g_lowercase_dump_char_table;
+ for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u)
+ {
+ 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, b - buf_begin);
+ }
+}
+
+} // namespace
+
+void dump_data_char_avx2(const void* data, std::size_t size, std::basic_ostream< char >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+void dump_data_wchar_avx2(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+void dump_data_char16_avx2(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+void dump_data_char32_avx2(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_avx2(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>

Added: trunk/libs/log/src/dump_ssse3.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/log/src/dump_ssse3.cpp 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -0,0 +1,270 @@
+/*
+ * 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_ssse3.cpp
+ * \author Andrey Semashev
+ * \date 05.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.
+ */
+
+// NOTE: You should generally avoid including headers as much as possible here, because this file
+// is compiled with special compiler options, and any included header may result in generation of
+// unintended code with these options and violation of ODR.
+#include <ostream>
+#include <tmmintrin.h>
+#include <boost/cstdint.hpp>
+#include <boost/log/detail/config.hpp>
+#include <boost/log/detail/header.hpp>
+
+namespace boost {
+
+BOOST_LOG_OPEN_NAMESPACE
+
+namespace aux {
+
+extern const char g_lowercase_dump_char_table[];
+extern const char g_uppercase_dump_char_table[];
+
+template< typename CharT >
+extern void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm);
+
+BOOST_LOG_ANONYMOUS_NAMESPACE {
+
+enum
+{
+ packs_per_stride = 32,
+ stride = packs_per_stride * 16
+};
+
+union xmm_constant
+{
+ uint8_t as_bytes[16];
+ __m128i as_mm;
+};
+
+static const xmm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }};
+static const xmm_constant mm_9 = {{ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }};
+static const xmm_constant mm_char_0 = {{ '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0' }};
+static const xmm_constant mm_char_space_mask = {{ ' ', 0, 0, ' ', 0, 0, ' ', 0, 0, ' ', 0, 0, ' ', 0, 0, ' ' }};
+static const xmm_constant mm_shuffle_pattern1 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80 }};
+static const xmm_constant mm_shuffle_pattern2 = {{ 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10 }};
+static const xmm_constant mm_shuffle_pattern3 = {{ 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15 }};
+
+//! Dumps a pack of input data into a string of 8 bit ASCII characters
+static BOOST_LOG_FORCEINLINE void dump_pack(__m128i mm_char_10_to_a, __m128i mm_input, __m128i& mm_output1, __m128i& mm_output2, __m128i& mm_output3)
+{
+ // Split half-bytes
+ __m128i mm_input_hi = _mm_and_si128(_mm_srli_epi16(mm_input, 4), mm_15.as_mm);
+ __m128i mm_input_lo = _mm_and_si128(mm_input, mm_15.as_mm);
+
+ // Stringize each of the halves
+ __m128i mm_addend_hi = _mm_cmpgt_epi8(mm_input_hi, mm_9.as_mm);
+ __m128i mm_addend_lo = _mm_cmpgt_epi8(mm_input_lo, mm_9.as_mm);
+ mm_addend_hi = _mm_and_si128(mm_char_10_to_a, mm_addend_hi);
+ mm_addend_lo = _mm_and_si128(mm_char_10_to_a, mm_addend_lo);
+
+ mm_input_hi = _mm_add_epi8(mm_input_hi, mm_char_0.as_mm);
+ mm_input_lo = _mm_add_epi8(mm_input_lo, mm_char_0.as_mm);
+
+ mm_input_hi = _mm_add_epi8(mm_input_hi, mm_addend_hi);
+ mm_input_lo = _mm_add_epi8(mm_input_lo, mm_addend_lo);
+
+ // Join them back together
+ __m128i mm_1 = _mm_unpacklo_epi8(mm_input_hi, mm_input_lo);
+ __m128i mm_2 = _mm_unpackhi_epi8(mm_input_hi, mm_input_lo);
+
+ // Insert spaces between stringized bytes:
+ // |0123456789abcdef|0123456789abcdef|
+ // | 01 23 45 67 89 |ab cd ef 01 23 4|5 67 89 ab cd ef|
+ mm_output1 = _mm_shuffle_epi8(mm_1, mm_shuffle_pattern1.as_mm);
+ mm_output2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 10), mm_shuffle_pattern2.as_mm);
+ mm_output3 = _mm_shuffle_epi8(mm_2, mm_shuffle_pattern3.as_mm);
+
+ __m128i mm_char_space = mm_char_space_mask.as_mm;
+ mm_output1 = _mm_or_si128(mm_output1, mm_char_space);
+ mm_char_space = _mm_srli_si128(mm_char_space, 1);
+ mm_output2 = _mm_or_si128(mm_output2, mm_char_space);
+ mm_char_space = _mm_srli_si128(mm_char_space, 1);
+ mm_output3 = _mm_or_si128(mm_output3, mm_char_space);
+}
+
+template< typename CharT >
+BOOST_LOG_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf)
+{
+ switch (sizeof(CharT))
+ {
+ case 1:
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars);
+ break;
+
+ case 2:
+ {
+ __m128i mm_0 = _mm_setzero_si128();
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi8(mm_chars, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi8(mm_chars, mm_0));
+ }
+ break;
+
+ case 4:
+ {
+ __m128i mm_0 = _mm_setzero_si128();
+ __m128i mm = _mm_unpacklo_epi8(mm_chars, mm_0);
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi16(mm, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi16(mm, mm_0));
+ mm = _mm_unpackhi_epi8(mm_chars, mm_0);
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 2, _mm_unpacklo_epi16(mm, mm_0));
+ _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 3, _mm_unpackhi_epi16(mm, mm_0));
+ }
+ break;
+ }
+}
+
+template< typename CharT >
+BOOST_LOG_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
+{
+ typedef CharT char_type;
+
+ char_type buf_storage[stride * 3u + 16u];
+ // Align the temporary buffer at 16 bytes
+ char_type* const buf = buf_storage + (16u - ((std::size_t)(char_type*)buf_storage & 15u));
+ char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
+ char_type* buf_end = buf + stride * 3u;
+
+ __m128i mm_char_10_to_a;
+ if (strm.flags() & std::ios_base::uppercase)
+ mm_char_10_to_a = _mm_set1_epi32(0x07070707); // '9' is 0x39 and 'A' is 0x41 in ASCII, so we have to add 0x07 to 0x3A to get uppercase letters
+ else
+ mm_char_10_to_a = _mm_set1_epi32(0x27272727); // ...and 'a' is 0x61, which means we have to add 0x27 to 0x3A to get lowercase letters
+
+ // First, check the input alignment
+ const uint8_t* p = static_cast< const uint8_t* >(data);
+ if (const std::size_t prealign_size = ((16u - ((std::size_t)p & 15u)) & 15u))
+ {
+ __m128i mm_input = _mm_lddqu_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+
+ strm.write(buf_begin, prealign_size * 3u - 1u);
+ buf_begin = buf;
+ size -= prealign_size;
+ p += prealign_size;
+ }
+
+ const std::size_t stride_count = size / stride;
+ std::size_t tail_size = size % stride;
+ for (std::size_t i = 0; i < stride_count; ++i)
+ {
+ char_type* b = buf;
+ for (unsigned int j = 0; j < packs_per_stride; ++j, b += 3u * 16u, p += 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+ }
+
+ strm.write(buf_begin, buf_end - buf_begin);
+ buf_begin = buf;
+ }
+
+ if (tail_size > 0)
+ {
+ char_type* b = buf;
+ while (tail_size >= 16u)
+ {
+ __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p));
+ __m128i mm_output1, mm_output2, mm_output3;
+ dump_pack(mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3);
+ store_characters(mm_output1, buf);
+ store_characters(mm_output2, buf + 16u);
+ store_characters(mm_output3, buf + 32u);
+ b += 3u * 16u;
+ p += 16u;
+ tail_size -= 16u;
+ }
+
+ const char* const char_table = (strm.flags() & std::ios_base::uppercase) ? g_uppercase_dump_char_table : g_lowercase_dump_char_table;
+ for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u)
+ {
+ 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, b - buf_begin);
+ }
+}
+
+} // namespace
+
+void dump_data_char_ssse3(const void* data, std::size_t size, std::basic_ostream< char >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+void dump_data_wchar_ssse3(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+
+#if !defined(BOOST_NO_CXX11_CHAR16_T)
+void dump_data_char16_ssse3(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+#if !defined(BOOST_NO_CXX11_CHAR32_T)
+void dump_data_char32_ssse3(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm)
+{
+ if (size >= 32)
+ {
+ dump_data_ssse3(data, size, strm);
+ }
+ else
+ {
+ dump_data_generic(data, size, strm);
+ }
+}
+#endif
+
+} // namespace aux
+
+BOOST_LOG_CLOSE_NAMESPACE // namespace log
+
+} // namespace boost
+
+#include <boost/log/detail/footer.hpp>

Modified: trunk/libs/log/test/performance/Jamfile.v2
==============================================================================
--- trunk/libs/log/test/performance/Jamfile.v2 (original)
+++ trunk/libs/log/test/performance/Jamfile.v2 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -9,3 +9,7 @@
     : record_emission.cpp ../../build//boost_log
     ;
 
+exe dump
+ : dump.cpp ../../build//boost_log
+ ;
+

Added: trunk/libs/log/test/performance/dump.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/log/test/performance/dump.cpp 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -0,0 +1,76 @@
+/*
+ * 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 05.05.2013
+ *
+ * \brief This code measures performance dumping binary data
+ */
+
+#include <cstdlib>
+#include <iomanip>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <algorithm>
+
+#include <boost/cstdint.hpp>
+#include <boost/date_time/microsec_time_clock.hpp>
+#include <boost/date_time/posix_time/posix_time_types.hpp>
+
+#include <boost/log/utility/formatting_ostream.hpp>
+#include <boost/log/utility/manipulators/dump.hpp>
+
+namespace logging = boost::log;
+
+const unsigned int base_loop_count = 10000;
+
+void test(std::size_t block_size)
+{
+ std::cout << "Block size: " << block_size << " bytes.";
+
+ std::vector< boost::uint8_t > data;
+ data.resize(block_size);
+ std::generate_n(data.begin(), block_size, &std::rand);
+
+ std::string str;
+ logging::formatting_ostream strm(str);
+
+ const boost::uint8_t* const p = &data[0];
+
+ boost::uint64_t data_processed = 0, duration = 0;
+ boost::posix_time::ptime start, end;
+ start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+ do
+ {
+ for (unsigned int i = 0; i < base_loop_count; ++i)
+ {
+ strm << logging::dump(p, block_size);
+ str.clear();
+ }
+ end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time();
+ data_processed += base_loop_count * block_size;
+ duration = (end - start).total_microseconds();
+ }
+ while (duration < 2000000);
+
+ std::cout << " Test duration: " << duration << " us ("
+ << std::fixed << std::setprecision(3) << static_cast< double >(data_processed) / (static_cast< double >(duration) * (1048576.0 / 1000000.0))
+ << " MiB per second)" << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+ test(32);
+ test(128);
+ test(1024);
+ test(16384);
+ test(1048576);
+
+ return 0;
+}

Modified: trunk/libs/log/test/performance/record_emission.cpp
==============================================================================
--- trunk/libs/log/test/performance/record_emission.cpp (original)
+++ trunk/libs/log/test/performance/record_emission.cpp 2013-05-05 17:11:20 EDT (Sun, 05 May 2013)
@@ -68,7 +68,7 @@
         public sinks::basic_sink_backend< sinks::concurrent_feeding >
     {
     public:
- void consume(logging::record const& rec)
+ void consume(logging::record_view const& rec)
         {
         }
     };


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk