1 // Copyright (c) 2012-2019 Intel Corporation
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a copy
4 // of this software and associated documentation files (the "Software"), to deal
5 // in the Software without restriction, including without limitation the rights
6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 // copies of the Software, and to permit persons to whom the Software is
8 // furnished to do so, subject to the following conditions:
9 //
10 // The above copyright notice and this permission notice shall be included in all
11 // copies or substantial portions of the Software.
12 //
13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 // SOFTWARE.
20 
21 #if defined(MFX_DISPATCHER_LOG)
22 
23 #include "mfx_dispatcher_log.h"
24 #include "mfxstructures.h"
25 #include <windows.h>
26 #if defined(DISPATCHER_LOG_REGISTER_EVENT_PROVIDER)
27 #include <evntprov.h>
28 #include <winmeta.h>
29 #endif
30 #include <stdarg.h>
31 #include <algorithm>
32 #include <string>
33 #include <sstream>
34 
35 struct CodeStringTable
36 {
37     int code;
38     const char *string;
39 } LevelStrings []=
40 {
41     {DL_INFO,  "INFO:   "},
42     {DL_WRN,   "WARNING:"},
43     {DL_ERROR, "ERROR:  "}
44 };
45 
46 #define DEFINE_CODE(code)\
47     {code, #code}
48 
49 static CodeStringTable StringsOfImpl[] = {
50     DEFINE_CODE(MFX_IMPL_AUTO),
51     DEFINE_CODE(MFX_IMPL_SOFTWARE),
52     DEFINE_CODE(MFX_IMPL_HARDWARE),
53     DEFINE_CODE(MFX_IMPL_AUTO_ANY),
54     DEFINE_CODE(MFX_IMPL_HARDWARE_ANY),
55     DEFINE_CODE(MFX_IMPL_HARDWARE2),
56     DEFINE_CODE(MFX_IMPL_HARDWARE3),
57     DEFINE_CODE(MFX_IMPL_HARDWARE4),
58 
59     DEFINE_CODE(MFX_IMPL_UNSUPPORTED)
60 };
61 
62 static CodeStringTable StringsOfImplVIA[] = {
63     DEFINE_CODE(MFX_IMPL_VIA_ANY),
64     DEFINE_CODE(MFX_IMPL_VIA_D3D9),
65     DEFINE_CODE(MFX_IMPL_VIA_D3D11),
66 };
67 
68 static CodeStringTable StringsOfStatus[] =
69 {
70     DEFINE_CODE(MFX_ERR_NONE                    ),
71     DEFINE_CODE(MFX_ERR_UNKNOWN                 ),
72     DEFINE_CODE(MFX_ERR_NULL_PTR                ),
73     DEFINE_CODE(MFX_ERR_UNSUPPORTED             ),
74     DEFINE_CODE(MFX_ERR_MEMORY_ALLOC            ),
75     DEFINE_CODE(MFX_ERR_NOT_ENOUGH_BUFFER       ),
76     DEFINE_CODE(MFX_ERR_INVALID_HANDLE          ),
77     DEFINE_CODE(MFX_ERR_LOCK_MEMORY             ),
78     DEFINE_CODE(MFX_ERR_NOT_INITIALIZED         ),
79     DEFINE_CODE(MFX_ERR_NOT_FOUND               ),
80     DEFINE_CODE(MFX_ERR_MORE_DATA               ),
81     DEFINE_CODE(MFX_ERR_MORE_SURFACE            ),
82     DEFINE_CODE(MFX_ERR_ABORTED                 ),
83     DEFINE_CODE(MFX_ERR_DEVICE_LOST             ),
84     DEFINE_CODE(MFX_ERR_INCOMPATIBLE_VIDEO_PARAM),
85     DEFINE_CODE(MFX_ERR_INVALID_VIDEO_PARAM     ),
86     DEFINE_CODE(MFX_ERR_UNDEFINED_BEHAVIOR      ),
87     DEFINE_CODE(MFX_ERR_DEVICE_FAILED           ),
88     DEFINE_CODE(MFX_WRN_IN_EXECUTION            ),
89     DEFINE_CODE(MFX_WRN_DEVICE_BUSY             ),
90     DEFINE_CODE(MFX_WRN_VIDEO_PARAM_CHANGED     ),
91     DEFINE_CODE(MFX_WRN_PARTIAL_ACCELERATION    ),
92     DEFINE_CODE(MFX_WRN_INCOMPATIBLE_VIDEO_PARAM),
93     DEFINE_CODE(MFX_WRN_VALUE_NOT_CHANGED       ),
94     DEFINE_CODE(MFX_WRN_OUT_OF_RANGE            ),
95 
96 };
97 
98 #define CODE_TO_STRING(code,  array)\
99     CodeToString(code, array, sizeof(array)/sizeof(array[0]))
100 
CodeToString(int code,CodeStringTable array[],int len)101 const char* CodeToString(int code, CodeStringTable array[], int len )
102 {
103     for (int i = 0 ; i < len; i++)
104     {
105         if (array[i].code == code)
106             return array[i].string;
107     }
108     return "undef";
109 }
110 
DispatcherLog_GetMFXImplString(int impl)111 std::string DispatcherLog_GetMFXImplString(int impl)
112 {
113     std::string str1 = CODE_TO_STRING(impl & ~(-MFX_IMPL_VIA_ANY), StringsOfImpl);
114     std::string str2 = CODE_TO_STRING(impl & (-MFX_IMPL_VIA_ANY), StringsOfImplVIA);
115 
116     return str1 + (str2 == "undef" ? "" : "|"+str2);
117 }
118 
DispatcherLog_GetMFXStatusString(int sts)119 const char *DispatcherLog_GetMFXStatusString(int sts)
120 {
121     return CODE_TO_STRING(sts, StringsOfStatus);
122 }
123 
124 //////////////////////////////////////////////////////////////////////////
125 
126 
Write(const char * str,...)127 void DispatcherLogBracketsHelper::Write(const char * str, ...)
128 {
129     va_list argsptr;
130     va_start(argsptr, str);
131     DispatchLog::get().Write(m_level, m_opcode, str, argsptr);
132     va_end(argsptr);
133 }
134 
Write(const char * str,...)135 void DispatchLogBlockHelper::Write(const char * str, ...)
136 {
137     va_list argsptr;
138     va_start(argsptr, str);
139     DispatchLog::get().Write(m_level, DL_EVENT_START, str, argsptr);
140     va_end(argsptr);
141 }
142 
~DispatchLogBlockHelper()143 DispatchLogBlockHelper::~DispatchLogBlockHelper()
144 {
145     DispatchLog::get().Write(m_level, DL_EVENT_STOP, NULL, NULL);
146 }
147 
148 //////////////////////////////////////////////////////////////////////////
149 
DispatchLog()150 DispatchLog::DispatchLog()
151  : m_DispatcherLogSink(DL_SINK_PRINTF)
152 {
153 
154 }
155 
SetSink(int nSink,IMsgHandler * pHandler)156 void   DispatchLog::SetSink(int nSink, IMsgHandler * pHandler)
157 {
158     DetachAllSinks();
159     AttachSink(nSink, pHandler);
160 }
161 
AttachSink(int nsink,IMsgHandler * pHandler)162 void   DispatchLog::AttachSink(int nsink, IMsgHandler *pHandler)
163 {
164     m_DispatcherLogSink |= nsink;
165     if (NULL != pHandler)
166         m_Recepients.push_back(pHandler);
167 }
168 
DetachSink(int nsink,IMsgHandler * pHandler)169 void   DispatchLog::DetachSink(int nsink, IMsgHandler *pHandler)
170 {
171     if (nsink & DL_SINK_IMsgHandler)
172     {
173         m_Recepients.remove(pHandler);
174     }
175 
176     m_DispatcherLogSink &= ~nsink;
177 }
178 
ExchangeSink(int nsink,IMsgHandler * oldHdl,IMsgHandler * newHdl)179 void   DispatchLog::ExchangeSink(int nsink, IMsgHandler *oldHdl, IMsgHandler *newHdl)
180 {
181     if (nsink & DL_SINK_IMsgHandler)
182     {
183         std::list<IMsgHandler*> :: iterator it = std::find(m_Recepients.begin(), m_Recepients.end(), oldHdl);
184 
185         //cannot exchange in that case
186         if (m_Recepients.end() == it)
187             return;
188 
189         *it = newHdl;
190     }
191 }
192 
193 
DetachAllSinks()194 void   DispatchLog::DetachAllSinks()
195 {
196     m_Recepients.clear();
197     m_DispatcherLogSink = DL_SINK_NULL;
198 }
199 
Write(int level,int opcode,const char * msg,va_list argptr)200 void   DispatchLog::Write(int level, int opcode, const char * msg, va_list argptr)
201 {
202     int sinkTable[] =
203     {
204         DL_SINK_PRINTF,
205         DL_SINK_IMsgHandler,
206     };
207 
208     for (size_t i = 0; i < sizeof(sinkTable) / sizeof(sinkTable[0]); i++)
209     {
210         switch(m_DispatcherLogSink & sinkTable[i])
211         {
212             case  DL_SINK_NULL:
213                 break;
214 
215             case DL_SINK_PRINTF:
216             {
217                 char msg_formated[8048] = {0};
218 
219                 if (NULL != msg && level != DL_LOADED_LIBRARY)
220                 {
221 #if _MSC_VER >= 1400
222                     vsprintf_s(msg_formated, sizeof(msg_formated)/sizeof(msg_formated[0]), msg, argptr);
223 #else
224                     vsnprintf(msg_formated, sizeof(msg_formated)/sizeof(msg_formated[0]), msg, argptr);
225 #endif
226                     //TODO: improve this , add opcode handling
227                     printf("%s %s", CODE_TO_STRING(level, LevelStrings), msg_formated);
228                 }
229                 break;
230             }
231 
232             case DL_SINK_IMsgHandler:
233             {
234                 std::list<IMsgHandler*>::iterator it;
235 
236                 for (it = m_Recepients.begin(); it != m_Recepients.end(); ++it)
237                 {
238                     (*it)->Write(level, opcode, msg, argptr);
239                 }
240                 break;
241             }
242         }
243     }
244 }
245 
246 #if defined(DISPATCHER_LOG_REGISTER_EVENT_PROVIDER)
247 class ETWHandler : public IMsgHandler
248 {
249 public:
ETWHandler(const wchar_t * guid_str)250     ETWHandler(const wchar_t * guid_str)
251       : m_bUseFormatter(DISPATCHER_LOG_USE_FORMATING)
252       , m_EventHandle()
253       , m_bProviderEnable()
254     {
255         GUID rguid = GUID_NULL;
256         if (FAILED(CLSIDFromString(guid_str, &rguid)))
257         {
258             return;
259         }
260 
261         EventRegister(&rguid, NULL, NULL, &m_EventHandle);
262 
263         m_bProviderEnable = 0 != EventProviderEnabled(m_EventHandle, 1,0);
264     }
265 
~ETWHandler()266     ~ETWHandler()
267     {
268         if (m_EventHandle)
269         {
270             EventUnregister(m_EventHandle);
271         }
272     }
273 
Write(int level,int opcode,const char * msg,va_list argptr)274     virtual void Write(int level, int opcode, const char * msg, va_list argptr)
275     {
276         //event not registered
277         if (0==m_EventHandle)
278         {
279             return;
280         }
281         if (!m_bProviderEnable)
282         {
283             return;
284         }
285         if (level == DL_LOADED_LIBRARY)
286         {
287             return;
288         }
289 
290         char msg_formated[1024];
291         EVENT_DESCRIPTOR descriptor;
292         EVENT_DATA_DESCRIPTOR data_descriptor;
293 
294         EventDescZero(&descriptor);
295 
296         descriptor.Opcode = (UCHAR)opcode;
297         descriptor.Level  = (UCHAR)level;
298 
299         if (m_bUseFormatter)
300         {
301             if (NULL != msg)
302             {
303 #if _MSC_VER >= 1400
304                 vsprintf_s(msg_formated, sizeof (msg_formated) / sizeof (msg_formated[0]), msg, argptr);
305 #else
306                 vsnprintf(msg_formated, sizeof (msg_formated) / sizeof (msg_formated[0]), msg, argptr);
307 #endif
308                 EventDataDescCreate(&data_descriptor, msg_formated, (ULONG)(strlen(msg_formated) + 1));
309             }else
310             {
311                 EventDataDescCreate(&data_descriptor, NULL, 0);
312             }
313         }else
314         {
315             //TODO: non formated events supports under zbb
316         }
317 
318         EventWrite(m_EventHandle, &descriptor, 1, &data_descriptor);
319     }
320 
321 protected:
322 
323     //we may not use formatter in some cases described in dispatch_log macro
324     //it significantly increases performance by eliminating any vsprintf operations
325     bool      m_bUseFormatter;
326     //consumer is attached, dispatcher trace to reduce formating overhead
327     //submits event only if consumer attached
328     bool      m_bProviderEnable;
329     REGHANDLE m_EventHandle;
330 };
331 //
332 
333 
GetSink(const wchar_t * sguid)334 IMsgHandler *ETWHandlerFactory::GetSink(const wchar_t* sguid)
335 {
336     _storage_type::iterator it;
337     it = m_storage.find(sguid);
338     if (it == m_storage.end())
339     {
340         ETWHandler * handler = new ETWHandler(sguid);
341         _storage_type::_Pairib it_bool = m_storage.insert(_storage_type::value_type(sguid, handler));
342         it = it_bool.first;
343     }
344 
345    return it->second;
346 }
347 
~ETWHandlerFactory()348 ETWHandlerFactory::~ETWHandlerFactory()
349 {
350     for each(_storage_type::value_type val in m_storage)
351     {
352         delete val.second;
353     }
354 }
355 
356 class EventRegistrator : public IMsgHandler
357 {
358     const wchar_t * m_sguid;
359 public:
EventRegistrator(const wchar_t * sguid=DISPATCHER_LOG_EVENT_GUID)360     EventRegistrator(const wchar_t* sguid = DISPATCHER_LOG_EVENT_GUID)
361         :m_sguid(sguid)
362     {
363         DispatchLog::get().AttachSink( DL_SINK_IMsgHandler
364                                       , this);
365     }
366 
Write(int level,int opcode,const char * msg,va_list argptr)367     virtual void Write(int level, int opcode, const char * msg, va_list argptr)
368     {
369         //we cannot call attach sink since we may have been called from iteration
370         //we axchanging preserve that placeholding
371         IMsgHandler * pSink = NULL;
372         DispatchLog::get().ExchangeSink(DL_SINK_IMsgHandler,
373                                         this,
374                                         pSink = ETWHandlerFactory::get().GetSink(m_sguid));
375         //need to call only once here all next calls will be done inside dispatcherlog
376         if (NULL != pSink)
377         {
378             pSink->Write(level, opcode, msg, argptr);
379         }
380     }
381 };
382 #endif
383 
384 template <class TSink>
385 class SinkRegistrator
386 {
387 };
388 
389 #if defined(DISPATCHER_LOG_REGISTER_EVENT_PROVIDER)
390 template <>
391 class SinkRegistrator<ETWHandlerFactory>
392 {
393 public:
SinkRegistrator(const wchar_t * sguid=DISPATCHER_LOG_EVENT_GUID)394     SinkRegistrator(const wchar_t* sguid = DISPATCHER_LOG_EVENT_GUID)
395     {
396         DispatchLog::get().AttachSink( DL_SINK_IMsgHandler
397                                       , ETWHandlerFactory::get().GetSink(sguid));
398     }
399 };
400 #endif
401 
402 #if defined(DISPATCHER_LOG_REGISTER_FILE_WRITER)
403 template <>
404 class SinkRegistrator<FileSink>
405 {
406 public:
SinkRegistrator()407     SinkRegistrator()
408     {
409         DispatchLog::get().AttachSink( DL_SINK_IMsgHandler, &FileSink::get(DISPACTHER_LOG_FW_PATH));
410     }
411 };
412 
Write(int level,int,const char * msg,va_list argptr)413 void FileSink::Write(int level, int /*opcode*/, const char * msg, va_list argptr)
414 {
415     if (NULL != m_hdl && NULL != msg)
416     {
417         fprintf(m_hdl, "%s", CODE_TO_STRING(level, LevelStrings));
418         vfprintf(m_hdl, msg, argptr);
419     }
420 }
421 #endif
422 
423 //////////////////////////////////////////////////////////////////////////
424 //singletons initialization section
425 
426 
427 #ifdef  DISPATCHER_LOG_REGISTER_EVENT_PROVIDER
428     static SinkRegistrator<ETWHandlerFactory> g_registrator1;
429 #endif
430 
431 
432 #ifdef DISPATCHER_LOG_REGISTER_FILE_WRITER
433     static SinkRegistrator<FileSink> g_registrator2;
434 #endif
435 
436 
437 #endif//(MFX_DISPATCHER_LOG)