1 | /* |
2 | * Copyright Andrey Semashev 2007 - 2021. |
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 | 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 |
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 | |
63 | BOOST_ALIGNMENT(16) extern const char g_hex_char_table[2][16] = |
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; |
140 | const uint32_t cpu_vendor[3u] = { ebx, edx, ecx }; |
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)) |
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 | } |
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 | ); |
182 | mmstate = (eax & 6u) == 6u; |
183 | #elif defined(BOOST_WINDOWS) |
184 | // MSVC does not have an intrinsic for xgetbv, we have to query OS |
185 | boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll" ); |
186 | if (hKernel32) |
187 | { |
188 | typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t); |
189 | get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures" ); |
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 | |
205 | if (ebx & (1u << 5)) |
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__) |
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; |
223 | __asm__ __volatile__ |
224 | ( |
225 | "xchgq %%rbx, %0\n\t" |
226 | "cpuid\n\t" |
227 | "xchgq %%rbx, %0\n\t" |
228 | : "+DS" (rbx), "+a" (eax), "+c" (ecx), "+d" (edx) |
229 | ); |
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__) |
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 |
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; |
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> |
311 | |