0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 16:11:02 +08:00

(profiler_core) Added possibility to control event tracing priority level and to enable/disable event tracing at all.

This commit is contained in:
Victor Zarubkin 2016-09-15 23:15:07 +03:00
parent d8296ad43a
commit 4a40872183
5 changed files with 170 additions and 70 deletions

View File

@ -32,32 +32,7 @@ along with this program.If not, see <http://www.gnu.org/licenses/>.
\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.

View File

@ -71,7 +71,7 @@ namespace profiler {
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_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;

View File

@ -12,6 +12,7 @@
#include <evntrace.h>
#include <evntcons.h>
#include <thread>
#include <atomic>
#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:

View File

@ -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);

View File

@ -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);