From 4a40872183a215ca408262906d4e3c140e488561 Mon Sep 17 00:00:00 2001 From: Victor Zarubkin Date: Thu, 15 Sep 2016 23:15:07 +0300 Subject: [PATCH] (profiler_core) Added possibility to control event tracing priority level and to enable/disable event tracing at all. --- include/profiler/profiler.h | 133 ++++++++++++++++++++++++++++-------- src/event_trace_win.cpp | 56 ++++++++------- src/event_trace_win.h | 17 +++-- src/profile_manager.cpp | 33 +++++++-- src/profile_manager.h | 1 + 5 files changed, 170 insertions(+), 70 deletions(-) diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 7ab3b99..c77d045 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -32,32 +32,7 @@ along with this program.If not, see . \defgroup profiler EasyProfiler */ -/** If != 0 then EasyProfiler will measure time for blocks storage expansion. -If 0 then EasyProfiler will be compiled without blocks of code responsible -for measuring these events. - -These are "EasyProfiler.ExpandStorage" blocks on a diagram. - -\ingroup profiler -*/ -# define EASY_MEASURE_STORAGE_EXPAND 0 - -/** If true then "EasyProfiler.ExpandStorage" events are enabled by default and will be -writed to output file or translated over the net. -If false then you need to enable these events via GUI if you'll want to see them. - -\ingroup profiler -*/ -# define EASY_STORAGE_EXPAND_ENABLED true - -/** If true then EasyProfiler event tracing is enabled by default -and will be turned on and off when you call profiler::setEnabled(). -Otherwise, it have to be turned on via GUI and then it will be -turned on/off with next calls of profiler::setEnabled(). - -\ingroup profiler -*/ -# define EASY_EVENT_TRACING_ENABLED true +// EasyProfiler core API: /** Macro for beginning of a block with custom name and color. @@ -194,6 +169,35 @@ This is just for user's comfort. There is no difference for EasyProfiler GUI bet */ # define EASY_MAIN_THREAD EASY_THREAD("Main") +/** Enable or disable event tracing (context switch events). + +\note Default value is controlled by EASY_EVENT_TRACING_ENABLED macro. + +\note Change will take effect on the next call to EASY_PROFILER_ENABLE. + +\sa EASY_PROFILER_ENABLE, EASY_EVENT_TRACING_ENABLED + +\ingroup profiler +*/ +# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled) ::profiler::setEventTracingEnabled(isEnabled); + +/** Set event tracing thread priority (low or normal). + +Event tracing with low priority will affect your application performance much more less, but +it can be late to gather information about thread/process (thread could be finished to the moment +when event tracing thread will be awaken) and you will not see process name and process id +information in GUI for such threads. You will still be able to see all context switch events. + +Event tracing with normal priority could gather more information about processes but potentially +it could affect performance as it has more work to do. Usually you will not notice any performance +breakdown, but if you care about that then you change set event tracing priority level to low. + +\sa EASY_LOW_PRIORITY_EVENT_TRACING + +\ingroup profiler +*/ +# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) ::profiler::setLowPriorityEventTracing(isLowPriority); + # ifndef _WIN32 /** Macro for setting temporary log-file path for Unix event tracing system. @@ -210,10 +214,52 @@ This is just for user's comfort. There is no difference for EasyProfiler GUI bet # define EASY_EVENT_TRACING_LOG ::profiler::getContextSwitchLogFilename(); # endif -#else + + +// EasyProfiler settings: + +/** If != 0 then EasyProfiler will measure time for blocks storage expansion. +If 0 then EasyProfiler will be compiled without blocks of code responsible +for measuring these events. + +These are "EasyProfiler.ExpandStorage" blocks on a diagram. + +\ingroup profiler +*/ # define EASY_MEASURE_STORAGE_EXPAND 0 -# define EASY_STORAGE_EXPAND_ENABLED false -# define EASY_EVENT_TRACING_ENABLED false + +/** If true then "EasyProfiler.ExpandStorage" events are enabled by default and will be +writed to output file or translated over the net. +If false then you need to enable these events via GUI if you'll want to see them. + +\ingroup profiler +*/ +# define EASY_STORAGE_EXPAND_ENABLED true + +/** If true then EasyProfiler event tracing is enabled by default +and will be turned on and off when you call profiler::setEnabled(). +Otherwise, it have to be turned on via GUI and then it will be +turned on/off with next calls of profiler::setEnabled(). + +\ingroup profiler +*/ +# define EASY_EVENT_TRACING_ENABLED true + +/** If true then EasyProfiler.ETW thread (Event tracing for Windows) will have low priority by default. + +\sa EASY_SET_LOW_PRIORITY_EVENT_TRACING + +\note You can always change priority level via GUI or API while profiling session is not launched. +You don't need to rebuild or restart your application for that. + +\ingroup profiler +*/ +# define EASY_LOW_PRIORITY_EVENT_TRACING true + + + +#else // #ifndef FULL_DISABLE_PROFILER + # define EASY_BLOCK(...) # define EASY_FUNCTION(...) # define EASY_END_BLOCK @@ -222,13 +268,20 @@ This is just for user's comfort. There is no difference for EasyProfiler GUI bet # define EASY_EVENT(...) # define EASY_THREAD(...) # define EASY_MAIN_THREAD +# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled) +# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) # ifndef _WIN32 # define EASY_EVENT_TRACING_SET_LOG(filename) # define EASY_EVENT_TRACING_LOG "" # endif -#endif +# define EASY_MEASURE_STORAGE_EXPAND 0 +# define EASY_STORAGE_EXPAND_ENABLED false +# define EASY_EVENT_TRACING_ENABLED false +# define EASY_LOW_PRIORITY_EVENT_TRACING true + +#endif // #ifndef FULL_DISABLE_PROFILER ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// @@ -455,6 +508,26 @@ namespace profiler { */ PROFILER_API const char* registerThread(const char* _name); + /** Enable or disable event tracing. + + \note This change will take an effect on the next call of setEnabled(true); + + \sa setEnabled, EASY_SET_EVENT_TRACING_ENABLED + + \ingroup profiler + */ + PROFILER_API void setEventTracingEnabled(bool _isEnable); + + /** Set event tracing thread priority (low or normal). + + \note This change will take effect on the next call of setEnabled(true); + + \sa setEnabled, EASY_SET_LOW_PRIORITY_EVENT_TRACING + + \ingroup profiler + */ + PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority); + #ifndef _WIN32 /** Set temporary log-file path for Unix event tracing system. diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index fadce8d..35e0bb9 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -71,7 +71,7 @@ namespace profiler { auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart); - ProcessInfo* pinfo = nullptr; + const char* process_name = ""; auto it = THREAD_PROCESS_INFO_TABLE.find(_contextSwitchEvent->NewThreadId); if (it == THREAD_PROCESS_INFO_TABLE.end()) { @@ -79,10 +79,18 @@ namespace profiler { if (hThread != nullptr) { auto pid = GetProcessIdOfThread(hThread); - pinfo = &PROCESS_INFO_TABLE[pid]; + auto pinfo = &PROCESS_INFO_TABLE[pid]; if (pinfo->valid == 0) { + if (pinfo->name.empty()) + { + static char numbuf[128] = {}; + sprintf(numbuf, "%u", pid); + pinfo->name = numbuf; + pinfo->id = pid; + } + // According to documentation, using GetModuleBaseName() requires // PROCESS_QUERY_INFORMATION | PROCESS_VM_READ access rights. // But it works fine with PROCESS_QUERY_LIMITED_INFORMATION instead of PROCESS_QUERY_INFORMATION. @@ -94,54 +102,43 @@ namespace profiler { static TCHAR buf[MAX_PATH] = {}; // Using static is safe because processTraceEvent() is called from one thread auto success = GetModuleBaseName(hProc, 0, buf, MAX_PATH); - if (pinfo->name.empty()) - { - static char numbuf[128] = {}; - sprintf(numbuf, "%u ", pid); - pinfo->name = numbuf; - pinfo->id = pid; - } - if (success) { - pinfo->name += buf; + auto len = strlen(buf); + pinfo->name.reserve(pinfo->name.size() + 2 + len); + pinfo->name.append(" ", 1); + pinfo->name.append(buf, len); pinfo->valid = 1; - //printf("PROCESS %u is %s\n", pid, buf); } CloseHandle(hProc); } else { + //printf("Can not OpenProcess(%u);\n", pid); pinfo->valid = -1; } } - if (pinfo->valid > 0) - { - THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = pinfo; - } - else if (pinfo->valid < 0) - { - pinfo = nullptr; - THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = nullptr; - } + process_name = pinfo->name.c_str(); + THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = pinfo; CloseHandle(hThread); } else { + //printf("Can not OpenThread(%u);\n", _contextSwitchEvent->NewThreadId); THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = nullptr; } } else { - pinfo = it->second; - if (pinfo != nullptr && pinfo->valid < 0) - pinfo = nullptr; + auto pinfo = it->second; + if (pinfo != nullptr) + process_name = pinfo->name.c_str(); } - MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, pinfo ? pinfo->name.c_str() : ""); + MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, process_name); MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time); } @@ -155,6 +152,7 @@ namespace profiler { EasyEventTracer::EasyEventTracer() { + m_lowPriority = ATOMIC_VAR_INIT(EASY_LOW_PRIORITY_EVENT_TRACING); } EasyEventTracer::~EasyEventTracer() @@ -162,6 +160,11 @@ namespace profiler { disable(); } + void EasyEventTracer::setLowPriority(bool _value) + { + m_lowPriority.store(_value, ::std::memory_order_release); + } + ::profiler::EventTracingEnableStatus EasyEventTracer::startTrace(bool _force, int _step) { auto startTraceResult = StartTrace(&m_sessionHandle, KERNEL_LOGGER_NAME, props()); @@ -242,7 +245,8 @@ namespace profiler { })); // Set low priority for event tracing thread - SetThreadPriority(m_processThread.native_handle(), THREAD_PRIORITY_LOWEST); + if (m_lowPriority.load(::std::memory_order_acquire)) + SetThreadPriority(m_processThread.native_handle(), THREAD_PRIORITY_LOWEST); m_bEnabled = true; diff --git a/src/event_trace_win.h b/src/event_trace_win.h index 731c9ed..54f1215 100644 --- a/src/event_trace_win.h +++ b/src/event_trace_win.h @@ -12,6 +12,7 @@ #include #include #include +#include #include "event_trace_status.h" #include "spin_lock.h" @@ -30,13 +31,14 @@ namespace profiler { }; #pragma pack(pop) - ::std::thread m_processThread; - Properties m_properties; - EVENT_TRACE_LOGFILE m_trace; - profiler::spin_lock m_spin; - TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE; - TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE; - bool m_bEnabled = false; + ::std::thread m_processThread; + Properties m_properties; + EVENT_TRACE_LOGFILE m_trace; + profiler::spin_lock m_spin; + ::std::atomic_bool m_lowPriority; + TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE; + TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE; + bool m_bEnabled = false; public: @@ -45,6 +47,7 @@ namespace profiler { ::profiler::EventTracingEnableStatus enable(bool _force = false); void disable(); + void setLowPriority(bool _value); private: diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 7b734fd..5e3e2c3 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -82,6 +82,20 @@ extern "C" { return MANAGER.registerThread(name);// , filename, _funcname, line); } + PROFILER_API void setEventTracingEnabled(bool _isEnable) + { + MANAGER.setEventTracingEnabled(_isEnable); + } + +#ifdef _WIN32 + PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority) + { + EasyEventTracer::instance().setLowPriority(_isLowPriority); + } +#else + PROFILER_API void setLowPriorityEventTracing(bool) { } +#endif + #ifndef _WIN32 PROFILER_API void setContextSwitchLogFilename(const char* name) { @@ -245,7 +259,7 @@ ThreadStorage* ProfileManager::_findThreadStorage(profiler::thread_id_t _thread_ void ProfileManager::storeBlock(const profiler::BaseBlockDescriptor& _desc, const char* _runtimeName) { - if (!m_isEnabled || !_desc.enabled()) + if (!m_isEnabled.load(std::memory_order_acquire) || !_desc.enabled()) return; profiler::Block b(_desc, _runtimeName); @@ -259,7 +273,7 @@ void ProfileManager::storeBlock(const profiler::BaseBlockDescriptor& _desc, cons void ProfileManager::beginBlock(Block& _block) { - if (!m_isEnabled) + if (!m_isEnabled.load(std::memory_order_acquire)) return; if (THREAD_STORAGE == nullptr) @@ -290,7 +304,7 @@ void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profil void ProfileManager::endBlock() { - if (!m_isEnabled) + if (!m_isEnabled.load(std::memory_order_acquire)) return; if (THREAD_STORAGE->blocks.openedList.empty()) @@ -322,11 +336,11 @@ void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler void ProfileManager::setEnabled(bool isEnable) { - m_isEnabled = isEnable; + m_isEnabled.store(isEnable, std::memory_order_release); #ifdef _WIN32 if (isEnable) { - if (m_isEventTracingEnabled) + if (m_isEventTracingEnabled.load(std::memory_order_acquire)) EasyEventTracer::instance().enable(true); } else { EasyEventTracer::instance().disable(); @@ -334,12 +348,17 @@ void ProfileManager::setEnabled(bool isEnable) #endif } +void ProfileManager::setEventTracingEnabled(bool _isEnable) +{ + m_isEventTracingEnabled.store(_isEnable, std::memory_order_release); +} + ////////////////////////////////////////////////////////////////////////// uint32_t ProfileManager::dumpBlocksToStream(profiler::OStream& _outputStream) { - const bool wasEnabled = m_isEnabled; - const bool eventTracingEnabled = m_isEventTracingEnabled; + const bool wasEnabled = m_isEnabled.load(std::memory_order_acquire); + const bool eventTracingEnabled = m_isEventTracingEnabled.load(std::memory_order_acquire); if (wasEnabled) ::profiler::setEnabled(false); diff --git a/src/profile_manager.h b/src/profile_manager.h index c4d2a49..0f87950 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -369,6 +369,7 @@ public: void beginBlock(profiler::Block& _block); void endBlock(); void setEnabled(bool isEnable); + void setEventTracingEnabled(bool _isEnable); uint32_t dumpBlocksToFile(const char* filename); const char* registerThread(const char* name);// , const char* filename, const char* _funcname, int line);