• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *          Copyright Andrey Semashev 2007 - 2015.
3  * Distributed under the Boost Software License, Version 1.0.
4  *    (See accompanying file LICENSE_1_0.txt or copy at
5  *          http://www.boost.org/LICENSE_1_0.txt)
6  */
7 /*!
8  * \file   dump.cpp
9  * \author Andrey Semashev
10  * \date   03.05.2013
11  *
12  * \brief  This header is the Boost.Log library implementation, see the library documentation
13  *         at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
14  */
15 
16 #include <boost/log/detail/config.hpp>
17 #include <ostream>
18 #include <boost/cstdint.hpp>
19 #include <boost/log/utility/manipulators/dump.hpp>
20 #if defined(_MSC_VER) && (defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2))
21 #include <boost/winapi/dll.hpp>
22 #include <intrin.h> // __cpuid
23 #endif
24 #include <boost/log/detail/header.hpp>
25 
26 namespace boost {
27 
28 BOOST_LOG_OPEN_NAMESPACE
29 
30 namespace aux {
31 
32 #if defined(BOOST_LOG_USE_SSSE3)
33 extern dump_data_char_t dump_data_char_ssse3;
34 extern dump_data_wchar_t dump_data_wchar_ssse3;
35 #if !defined(BOOST_NO_CXX11_CHAR16_T)
36 extern dump_data_char16_t dump_data_char16_ssse3;
37 #endif
38 #if !defined(BOOST_NO_CXX11_CHAR32_T)
39 extern dump_data_char32_t dump_data_char32_ssse3;
40 #endif
41 #endif
42 #if defined(BOOST_LOG_USE_AVX2)
43 extern dump_data_char_t dump_data_char_avx2;
44 extern dump_data_wchar_t dump_data_wchar_avx2;
45 #if !defined(BOOST_NO_CXX11_CHAR16_T)
46 extern dump_data_char16_t dump_data_char16_avx2;
47 #endif
48 #if !defined(BOOST_NO_CXX11_CHAR32_T)
49 extern dump_data_char32_t dump_data_char32_avx2;
50 #endif
51 #endif
52 
53 enum { stride = 256 };
54 
55 extern const char g_hex_char_table[2][16] =
56 {
57     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' },
58     { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }
59 };
60 
61 template< typename CharT >
dump_data_generic(const void * data,std::size_t size,std::basic_ostream<CharT> & strm)62 void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm)
63 {
64     typedef CharT char_type;
65 
66     char_type buf[stride * 3u];
67 
68     const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0];
69     const std::size_t stride_count = size / stride, tail_size = size % stride;
70 
71     const uint8_t* p = static_cast< const uint8_t* >(data);
72     char_type* buf_begin = buf + 1u; // skip the first space of the first chunk
73     char_type* buf_end = buf + sizeof(buf) / sizeof(*buf);
74 
75     for (std::size_t i = 0; i < stride_count; ++i)
76     {
77         char_type* b = buf;
78         for (unsigned int j = 0; j < stride; ++j, b += 3u, ++p)
79         {
80             uint32_t n = *p;
81             b[0] = static_cast< char_type >(' ');
82             b[1] = static_cast< char_type >(char_table[n >> 4]);
83             b[2] = static_cast< char_type >(char_table[n & 0x0F]);
84         }
85 
86         strm.write(buf_begin, buf_end - buf_begin);
87         buf_begin = buf;
88     }
89 
90     if (tail_size > 0)
91     {
92         char_type* b = buf;
93         unsigned int i = 0;
94         do
95         {
96             uint32_t n = *p;
97             b[0] = static_cast< char_type >(' ');
98             b[1] = static_cast< char_type >(char_table[n >> 4]);
99             b[2] = static_cast< char_type >(char_table[n & 0x0F]);
100             ++i;
101             ++p;
102             b += 3u;
103         }
104         while (i < tail_size);
105 
106         strm.write(buf_begin, b - buf_begin);
107     }
108 }
109 
110 BOOST_LOG_API dump_data_char_t* dump_data_char = &dump_data_generic< char >;
111 BOOST_LOG_API dump_data_wchar_t* dump_data_wchar = &dump_data_generic< wchar_t >;
112 #if !defined(BOOST_NO_CXX11_CHAR16_T)
113 BOOST_LOG_API dump_data_char16_t* dump_data_char16 = &dump_data_generic< char16_t >;
114 #endif
115 #if !defined(BOOST_NO_CXX11_CHAR32_T)
116 BOOST_LOG_API dump_data_char32_t* dump_data_char32 = &dump_data_generic< char32_t >;
117 #endif
118 
119 #if defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
120 
121 BOOST_LOG_ANONYMOUS_NAMESPACE {
122 
123 struct function_pointer_initializer
124 {
125     function_pointer_initializer()
126     {
127         // First, let's check for the max supported cpuid function
128         uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0;
129         cpuid(eax, ebx, ecx, edx);
130 
131         const uint32_t max_cpuid_function = eax;
132         if (max_cpuid_function >= 1)
133         {
134             eax = 1;
135             ebx = ecx = edx = 0;
136             cpuid(eax, ebx, ecx, edx);
137 
138             // Check for SSSE3 support
139             if (ecx & (1u << 9))
140                 enable_ssse3();
141 
142 #if defined(BOOST_LOG_USE_AVX2)
143             if (max_cpuid_function >= 7)
144             {
145                 // To check for AVX2 availability we also need to verify that OS supports it
146                 // Check that OSXSAVE is supported by CPU
147                 if (ecx & (1u << 27))
148                 {
149                     // Check that it is used by the OS
150                     bool mmstate = false;
151 #if defined(__GNUC__)
152                     // Get the XFEATURE_ENABLED_MASK register
153                     __asm__ __volatile__
154                     (
155                         "xgetbv\n\t"
156                             : "=a" (eax), "=d" (edx)
157                             : "c" (0)
158                     );
159                     mmstate = (eax & 6U) == 6U;
160 #elif defined(BOOST_WINDOWS)
161                     // MSVC does not have an intrinsic for xgetbv, we have to query OS
162                     boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll");
163                     if (hKernel32)
164                     {
165                         typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t);
166                         get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures");
167                         if (get_enabled_extended_features)
168                         {
169                             // XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6
170                             mmstate = get_enabled_extended_features(6u) == 6u;
171                         }
172                     }
173 #endif
174 
175                     if (mmstate)
176                     {
177                         // Finally, check for AVX2 support in CPU
178                         eax = 7;
179                         ebx = ecx = edx = 0;
180                         cpuid(eax, ebx, ecx, edx);
181 
182                         if (ebx & (1U << 5))
183                             enable_avx2();
184                     }
185                 }
186             }
187 #endif // defined(BOOST_LOG_USE_AVX2)
188         }
189     }
190 
191 private:
192     static void cpuid(uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx)
193     {
194 #if defined(__GNUC__)
195 #if (defined(__i386__) || defined(__VXWORKS__)) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && BOOST_GCC >= 50100))
196         // Unless the compiler can do it automatically, we have to backup ebx in 32-bit PIC/PIE code because it is reserved by the ABI.
197         // For VxWorks ebx is reserved on 64-bit as well.
198 #if defined(__x86_64__)
199         uint64_t rbx = ebx;
200         __asm__ __volatile__
201         (
202             "xchgq %%rbx, %0\n\t"
203             "cpuid\n\t"
204             "xchgq %%rbx, %0\n\t"
205                 : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx)
206         );
207         ebx = static_cast< uint32_t >(rbx);
208 #else // defined(__x86_64__)
209         __asm__ __volatile__
210         (
211             "xchgl %%ebx, %0\n\t"
212             "cpuid\n\t"
213             "xchgl %%ebx, %0\n\t"
214                 : "+DS" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx)
215         );
216 #endif // defined(__x86_64__)
217 #else
218         __asm__ __volatile__
219         (
220             "cpuid\n\t"
221                 : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)
222         );
223 #endif
224 #elif defined(_MSC_VER)
225         int regs[4] = {};
226         __cpuid(regs, eax);
227         eax = regs[0];
228         ebx = regs[1];
229         ecx = regs[2];
230         edx = regs[3];
231 #else
232 #error Boost.Log: Unexpected compiler
233 #endif
234     }
235 
236     static void enable_ssse3()
237     {
238         dump_data_char = &dump_data_char_ssse3;
239         dump_data_wchar = &dump_data_wchar_ssse3;
240 #if !defined(BOOST_NO_CXX11_CHAR16_T)
241         dump_data_char16 = &dump_data_char16_ssse3;
242 #endif
243 #if !defined(BOOST_NO_CXX11_CHAR32_T)
244         dump_data_char32 = &dump_data_char32_ssse3;
245 #endif
246     }
247 
248 #if defined(BOOST_LOG_USE_AVX2)
249     static void enable_avx2()
250     {
251         dump_data_char = &dump_data_char_avx2;
252         dump_data_wchar = &dump_data_wchar_avx2;
253 #if !defined(BOOST_NO_CXX11_CHAR16_T)
254         dump_data_char16 = &dump_data_char16_avx2;
255 #endif
256 #if !defined(BOOST_NO_CXX11_CHAR32_T)
257         dump_data_char32 = &dump_data_char32_avx2;
258 #endif
259     }
260 #endif // defined(BOOST_LOG_USE_AVX2)
261 };
262 
263 static function_pointer_initializer g_function_pointer_initializer;
264 
265 } // namespace
266 
267 #endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)
268 
269 } // namespace aux
270 
271 BOOST_LOG_CLOSE_NAMESPACE // namespace log
272 
273 } // namespace boost
274 
275 #include <boost/log/detail/footer.hpp>
276