]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | /* |
1e59de90 | 2 | * Copyright Andrey Semashev 2007 - 2021. |
7c673cae FG |
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 | |
1e59de90 TL |
41 | extern dump_data_char_t dump_data_char_ssse3_slow_pshufb; |
42 | extern dump_data_wchar_t dump_data_wchar_ssse3_slow_pshufb; | |
43 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
44 | extern dump_data_char16_t dump_data_char16_ssse3_slow_pshufb; | |
45 | #endif | |
46 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
47 | extern dump_data_char32_t dump_data_char32_ssse3_slow_pshufb; | |
48 | #endif | |
7c673cae FG |
49 | #endif |
50 | #if defined(BOOST_LOG_USE_AVX2) | |
51 | extern dump_data_char_t dump_data_char_avx2; | |
52 | extern dump_data_wchar_t dump_data_wchar_avx2; | |
53 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
54 | extern dump_data_char16_t dump_data_char16_avx2; | |
55 | #endif | |
56 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
57 | extern dump_data_char32_t dump_data_char32_avx2; | |
58 | #endif | |
59 | #endif | |
60 | ||
61 | enum { stride = 256 }; | |
62 | ||
1e59de90 | 63 | BOOST_ALIGNMENT(16) extern const char g_hex_char_table[2][16] = |
7c673cae FG |
64 | { |
65 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }, | |
66 | { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } | |
67 | }; | |
68 | ||
69 | template< typename CharT > | |
70 | void dump_data_generic(const void* data, std::size_t size, std::basic_ostream< CharT >& strm) | |
71 | { | |
72 | typedef CharT char_type; | |
73 | ||
74 | char_type buf[stride * 3u]; | |
75 | ||
76 | const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; | |
77 | const std::size_t stride_count = size / stride, tail_size = size % stride; | |
78 | ||
79 | const uint8_t* p = static_cast< const uint8_t* >(data); | |
80 | char_type* buf_begin = buf + 1u; // skip the first space of the first chunk | |
81 | char_type* buf_end = buf + sizeof(buf) / sizeof(*buf); | |
82 | ||
83 | for (std::size_t i = 0; i < stride_count; ++i) | |
84 | { | |
85 | char_type* b = buf; | |
86 | for (unsigned int j = 0; j < stride; ++j, b += 3u, ++p) | |
87 | { | |
88 | uint32_t n = *p; | |
89 | b[0] = static_cast< char_type >(' '); | |
90 | b[1] = static_cast< char_type >(char_table[n >> 4]); | |
91 | b[2] = static_cast< char_type >(char_table[n & 0x0F]); | |
92 | } | |
93 | ||
94 | strm.write(buf_begin, buf_end - buf_begin); | |
95 | buf_begin = buf; | |
96 | } | |
97 | ||
98 | if (tail_size > 0) | |
99 | { | |
100 | char_type* b = buf; | |
101 | unsigned int i = 0; | |
102 | do | |
103 | { | |
104 | uint32_t n = *p; | |
105 | b[0] = static_cast< char_type >(' '); | |
106 | b[1] = static_cast< char_type >(char_table[n >> 4]); | |
107 | b[2] = static_cast< char_type >(char_table[n & 0x0F]); | |
108 | ++i; | |
109 | ++p; | |
110 | b += 3u; | |
111 | } | |
112 | while (i < tail_size); | |
113 | ||
114 | strm.write(buf_begin, b - buf_begin); | |
115 | } | |
116 | } | |
117 | ||
118 | BOOST_LOG_API dump_data_char_t* dump_data_char = &dump_data_generic< char >; | |
119 | BOOST_LOG_API dump_data_wchar_t* dump_data_wchar = &dump_data_generic< wchar_t >; | |
120 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
121 | BOOST_LOG_API dump_data_char16_t* dump_data_char16 = &dump_data_generic< char16_t >; | |
122 | #endif | |
123 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
124 | BOOST_LOG_API dump_data_char32_t* dump_data_char32 = &dump_data_generic< char32_t >; | |
125 | #endif | |
126 | ||
127 | #if defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2) | |
128 | ||
129 | BOOST_LOG_ANONYMOUS_NAMESPACE { | |
130 | ||
131 | struct function_pointer_initializer | |
132 | { | |
133 | function_pointer_initializer() | |
134 | { | |
135 | // First, let's check for the max supported cpuid function | |
136 | uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; | |
137 | cpuid(eax, ebx, ecx, edx); | |
138 | ||
139 | const uint32_t max_cpuid_function = eax; | |
1e59de90 | 140 | const uint32_t cpu_vendor[3u] = { ebx, edx, ecx }; |
7c673cae FG |
141 | if (max_cpuid_function >= 1) |
142 | { | |
143 | eax = 1; | |
144 | ebx = ecx = edx = 0; | |
145 | cpuid(eax, ebx, ecx, edx); | |
146 | ||
147 | // Check for SSSE3 support | |
148 | if (ecx & (1u << 9)) | |
1e59de90 TL |
149 | { |
150 | const uint32_t family = ((eax >> 8) & 0x0000000F) + ((eax >> 20) & 0x000000FF); | |
151 | const uint32_t model = ((eax >> 4) & 0x0000000F) | ((eax >> 12) & 0x000000F0); | |
152 | ||
153 | // Check if the CPU has slow pshufb. Some old Intel Atoms prior to Silvermont. | |
154 | if (cpu_vendor[0] == 0x756e6547 && cpu_vendor[1] == 0x49656e69 && cpu_vendor[2] == 0x6c65746e && | |
155 | family == 6 && (model == 28 || model == 38 || model == 39 || model == 53 || model == 54)) | |
156 | { | |
157 | enable_ssse3_slow_pshufb(); | |
158 | } | |
159 | else | |
160 | { | |
161 | enable_ssse3(); | |
162 | } | |
163 | } | |
7c673cae FG |
164 | |
165 | #if defined(BOOST_LOG_USE_AVX2) | |
166 | if (max_cpuid_function >= 7) | |
167 | { | |
168 | // To check for AVX2 availability we also need to verify that OS supports it | |
169 | // Check that OSXSAVE is supported by CPU | |
170 | if (ecx & (1u << 27)) | |
171 | { | |
172 | // Check that it is used by the OS | |
173 | bool mmstate = false; | |
174 | #if defined(__GNUC__) | |
175 | // Get the XFEATURE_ENABLED_MASK register | |
176 | __asm__ __volatile__ | |
177 | ( | |
178 | "xgetbv\n\t" | |
179 | : "=a" (eax), "=d" (edx) | |
180 | : "c" (0) | |
181 | ); | |
1e59de90 | 182 | mmstate = (eax & 6u) == 6u; |
7c673cae FG |
183 | #elif defined(BOOST_WINDOWS) |
184 | // MSVC does not have an intrinsic for xgetbv, we have to query OS | |
b32b8144 | 185 | boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); |
7c673cae FG |
186 | if (hKernel32) |
187 | { | |
92f5a8d4 | 188 | typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t); |
b32b8144 | 189 | get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures"); |
7c673cae FG |
190 | if (get_enabled_extended_features) |
191 | { | |
192 | // XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6 | |
193 | mmstate = get_enabled_extended_features(6u) == 6u; | |
194 | } | |
195 | } | |
196 | #endif | |
197 | ||
198 | if (mmstate) | |
199 | { | |
200 | // Finally, check for AVX2 support in CPU | |
201 | eax = 7; | |
202 | ebx = ecx = edx = 0; | |
203 | cpuid(eax, ebx, ecx, edx); | |
204 | ||
1e59de90 | 205 | if (ebx & (1u << 5)) |
7c673cae FG |
206 | enable_avx2(); |
207 | } | |
208 | } | |
209 | } | |
210 | #endif // defined(BOOST_LOG_USE_AVX2) | |
211 | } | |
212 | } | |
213 | ||
214 | private: | |
215 | static void cpuid(uint32_t& eax, uint32_t& ebx, uint32_t& ecx, uint32_t& edx) | |
216 | { | |
217 | #if defined(__GNUC__) | |
92f5a8d4 TL |
218 | #if (defined(__i386__) || defined(__VXWORKS__)) && (defined(__PIC__) || defined(__PIE__)) && !(defined(__clang__) || (defined(BOOST_GCC) && BOOST_GCC >= 50100)) |
219 | // 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. | |
220 | // For VxWorks ebx is reserved on 64-bit as well. | |
221 | #if defined(__x86_64__) | |
222 | uint64_t rbx = ebx; | |
7c673cae FG |
223 | __asm__ __volatile__ |
224 | ( | |
92f5a8d4 | 225 | "xchgq %%rbx, %0\n\t" |
7c673cae | 226 | "cpuid\n\t" |
92f5a8d4 TL |
227 | "xchgq %%rbx, %0\n\t" |
228 | : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx) | |
7c673cae | 229 | ); |
92f5a8d4 TL |
230 | ebx = static_cast< uint32_t >(rbx); |
231 | #else // defined(__x86_64__) | |
232 | __asm__ __volatile__ | |
233 | ( | |
234 | "xchgl %%ebx, %0\n\t" | |
235 | "cpuid\n\t" | |
236 | "xchgl %%ebx, %0\n\t" | |
237 | : "+DS" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx) | |
238 | ); | |
239 | #endif // defined(__x86_64__) | |
7c673cae FG |
240 | #else |
241 | __asm__ __volatile__ | |
242 | ( | |
243 | "cpuid\n\t" | |
244 | : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx) | |
245 | ); | |
246 | #endif | |
247 | #elif defined(_MSC_VER) | |
248 | int regs[4] = {}; | |
249 | __cpuid(regs, eax); | |
250 | eax = regs[0]; | |
251 | ebx = regs[1]; | |
252 | ecx = regs[2]; | |
253 | edx = regs[3]; | |
254 | #else | |
255 | #error Boost.Log: Unexpected compiler | |
1e59de90 TL |
256 | #endif |
257 | } | |
258 | ||
259 | static void enable_ssse3_slow_pshufb() | |
260 | { | |
261 | dump_data_char = &dump_data_char_ssse3_slow_pshufb; | |
262 | dump_data_wchar = &dump_data_wchar_ssse3_slow_pshufb; | |
263 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
264 | dump_data_char16 = &dump_data_char16_ssse3_slow_pshufb; | |
265 | #endif | |
266 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
267 | dump_data_char32 = &dump_data_char32_ssse3_slow_pshufb; | |
7c673cae FG |
268 | #endif |
269 | } | |
270 | ||
271 | static void enable_ssse3() | |
272 | { | |
273 | dump_data_char = &dump_data_char_ssse3; | |
274 | dump_data_wchar = &dump_data_wchar_ssse3; | |
275 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
276 | dump_data_char16 = &dump_data_char16_ssse3; | |
277 | #endif | |
278 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
279 | dump_data_char32 = &dump_data_char32_ssse3; | |
280 | #endif | |
281 | } | |
282 | ||
283 | #if defined(BOOST_LOG_USE_AVX2) | |
284 | static void enable_avx2() | |
285 | { | |
286 | dump_data_char = &dump_data_char_avx2; | |
287 | dump_data_wchar = &dump_data_wchar_avx2; | |
288 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
289 | dump_data_char16 = &dump_data_char16_avx2; | |
290 | #endif | |
291 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
292 | dump_data_char32 = &dump_data_char32_avx2; | |
293 | #endif | |
294 | } | |
295 | #endif // defined(BOOST_LOG_USE_AVX2) | |
296 | }; | |
297 | ||
298 | static function_pointer_initializer g_function_pointer_initializer; | |
299 | ||
300 | } // namespace | |
301 | ||
302 | #endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2) | |
303 | ||
304 | } // namespace aux | |
305 | ||
306 | BOOST_LOG_CLOSE_NAMESPACE // namespace log | |
307 | ||
308 | } // namespace boost | |
309 | ||
310 | #include <boost/log/detail/footer.hpp> |