]>
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 | { | |
165 | typedef uint64_t (WINAPI* 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__) | |
195 | #if defined(__i386__) && defined(__PIC__) && __PIC__ != 0 | |
196 | // We have to backup ebx in 32 bit PIC code because it is reserved by the ABI | |
197 | uint32_t ebx_backup; | |
198 | __asm__ __volatile__ | |
199 | ( | |
200 | "movl %%ebx, %0\n\t" | |
201 | "movl %1, %%ebx\n\t" | |
202 | "cpuid\n\t" | |
203 | "movl %%ebx, %1\n\t" | |
204 | "movl %0, %%ebx\n\t" | |
205 | : "=m" (ebx_backup), "+m" (ebx), "+a" (eax), "+c" (ecx), "+d" (edx) | |
206 | ); | |
207 | #else | |
208 | __asm__ __volatile__ | |
209 | ( | |
210 | "cpuid\n\t" | |
211 | : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx) | |
212 | ); | |
213 | #endif | |
214 | #elif defined(_MSC_VER) | |
215 | int regs[4] = {}; | |
216 | __cpuid(regs, eax); | |
217 | eax = regs[0]; | |
218 | ebx = regs[1]; | |
219 | ecx = regs[2]; | |
220 | edx = regs[3]; | |
221 | #else | |
222 | #error Boost.Log: Unexpected compiler | |
223 | #endif | |
224 | } | |
225 | ||
226 | static void enable_ssse3() | |
227 | { | |
228 | dump_data_char = &dump_data_char_ssse3; | |
229 | dump_data_wchar = &dump_data_wchar_ssse3; | |
230 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
231 | dump_data_char16 = &dump_data_char16_ssse3; | |
232 | #endif | |
233 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
234 | dump_data_char32 = &dump_data_char32_ssse3; | |
235 | #endif | |
236 | } | |
237 | ||
238 | #if defined(BOOST_LOG_USE_AVX2) | |
239 | static void enable_avx2() | |
240 | { | |
241 | dump_data_char = &dump_data_char_avx2; | |
242 | dump_data_wchar = &dump_data_wchar_avx2; | |
243 | #if !defined(BOOST_NO_CXX11_CHAR16_T) | |
244 | dump_data_char16 = &dump_data_char16_avx2; | |
245 | #endif | |
246 | #if !defined(BOOST_NO_CXX11_CHAR32_T) | |
247 | dump_data_char32 = &dump_data_char32_avx2; | |
248 | #endif | |
249 | } | |
250 | #endif // defined(BOOST_LOG_USE_AVX2) | |
251 | }; | |
252 | ||
253 | static function_pointer_initializer g_function_pointer_initializer; | |
254 | ||
255 | } // namespace | |
256 | ||
257 | #endif // defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2) | |
258 | ||
259 | } // namespace aux | |
260 | ||
261 | BOOST_LOG_CLOSE_NAMESPACE // namespace log | |
262 | ||
263 | } // namespace boost | |
264 | ||
265 | #include <boost/log/detail/footer.hpp> |