]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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)) | |
b32b8144 | 21 | #include <boost/winapi/dll.hpp> |
7c673cae FG |
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 > | |
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 | |
b32b8144 | 162 | boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); |
7c673cae FG |
163 | if (hKernel32) |
164 | { | |
92f5a8d4 | 165 | typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t); |
b32b8144 | 166 | get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures"); |
7c673cae FG |
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__) | |
92f5a8d4 TL |
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; | |
7c673cae FG |
200 | __asm__ __volatile__ |
201 | ( | |
92f5a8d4 | 202 | "xchgq %%rbx, %0\n\t" |
7c673cae | 203 | "cpuid\n\t" |
92f5a8d4 TL |
204 | "xchgq %%rbx, %0\n\t" |
205 | : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx) | |
7c673cae | 206 | ); |
92f5a8d4 TL |
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__) | |
7c673cae FG |
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> |