From dacb3dbae61833dbd99411f8f596120399384a6b Mon Sep 17 00:00:00 2001 From: Marcos Slomp Date: Tue, 16 Dec 2025 13:34:50 -0800 Subject: [PATCH 1/3] support for toggling EnableFlags after the singleton kernel session has started --- public/client/TracySysTrace.cpp | 24 ++------ public/client/windows/TracyETW.cpp | 90 ++++++++++++++++++++++++------ 2 files changed, 78 insertions(+), 36 deletions(-) diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index 55aa3152..b5f72e16 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -191,33 +191,21 @@ bool SysTraceStart( int64_t& samplingPeriod ) if ( !etw::CheckAdminPrivilege() ) return false; - ULONGLONG EnableFlags = 0; -#ifndef TRACY_NO_CONTEXT_SWITCH - EnableFlags |= EVENT_TRACE_FLAG_CSWITCH; - EnableFlags |= EVENT_TRACE_FLAG_DISPATCHER; - EnableFlags |= EVENT_TRACE_FLAG_THREAD; -#endif -#ifndef TRACY_NO_SAMPLING - DWORD access = etw::ElevatePrivilege( SE_SYSTEM_PROFILE_NAME ); - if( access != ERROR_SUCCESS ) - return access; - EnableFlags |= etw::IsOS64Bit() ? EVENT_TRACE_FLAG_PROFILE : 0; -#endif - - session_kernel = etw::StartSingletonKernelLoggerSession( EnableFlags ); + session_kernel = etw::StartSingletonKernelLoggerSession(); if ( session_kernel.handle == 0 ) return false; #ifndef TRACY_NO_CONTEXT_SWITCH - if ( etw::EnableStackWalk( session_kernel, etw::ThreadGuid, etw::CSwitch::Opcode ) != ERROR_SUCCESS ) + if ( etw::EnableProcessAndThreadMonitoring( session_kernel ) != ERROR_SUCCESS ) + return etw::StopSession( session_kernel ), false; + if ( etw::EnableContextSwitchMonitoring( session_kernel ) != ERROR_SUCCESS ) return etw::StopSession( session_kernel ), false; #endif + #ifndef TRACY_NO_SAMPLING - if ( etw::EnableStackWalk( session_kernel, etw::PerfInfoGuid, etw::SampledProfile::Opcode ) != ERROR_SUCCESS ) - return etw::StopSession( session_kernel ), false; int microseconds = GetSamplingInterval() / 10; - if ( etw::SetCPUProfilingInterval( microseconds ) != ERROR_SUCCESS ) + if ( etw::EnableCPUProfiling( session_kernel, microseconds ) != ERROR_SUCCESS ) return etw::StopSession( session_kernel ), false; samplingPeriod = GetSamplingPeriod(); #endif diff --git a/public/client/windows/TracyETW.cpp b/public/client/windows/TracyETW.cpp index 53997706..12910a81 100644 --- a/public/client/windows/TracyETW.cpp +++ b/public/client/windows/TracyETW.cpp @@ -317,7 +317,7 @@ static ULONG EnableStackWalk( Session& session, GUID EventGuid, UCHAR Opcode ) static ULONG SetCPUProfilingInterval(int microseconds) { if( !IsOS64Bit() ) - return 0 /* ERROR_SUCCESS */; // TODO: return error instead? + return 0 /* ERROR_SUCCESS */; // TODO: fabricate SetLastError(ERROR_NOT_SUPPORTED) instead? TRACE_PROFILE_INTERVAL interval = {}; interval.Source = 0; // 0: ProfileTime (from enum KPROFILE_SOURCE in wdm.h) interval.Interval = ( microseconds * 1000 ) / 100; // in 100's of nanoseconds @@ -326,7 +326,7 @@ static ULONG SetCPUProfilingInterval(int microseconds) return ETWError( status ); } -static Session StartSingletonKernelLoggerSession( ULONGLONG EnableFlags ) +static Session StartSingletonKernelLoggerSession( ULONGLONG EnableFlags = 0 ) { Session session = {}; @@ -421,29 +421,70 @@ static Session StartUserSession( const CHAR* name ) return session; } +bool IsSingletonKernelLoggerSession( Session& session ) +{ + bool check = true; + check &= ( session.handle == 0xFFFF ); + check &= ( strncmp( session.name, KERNEL_LOGGER_NAMEA, sizeof( session.name ) ) == 0 ); + return check; +} + +static ULONG UpdateSessionEnableFlags( Session& session, ULONGLONG EnableFlags ) +{ + // Use a copy of the session properties, because ControlTrace(UPDATE) will modify + // LogFileNameOffset and "pad" the rest with zeros, overwriting the session.handle! + Session temp = session; + temp.properties.EnableFlags = EnableFlags; + ULONG status = ControlTraceA( temp.handle, temp.name, &temp.properties, EVENT_TRACE_CONTROL_UPDATE ); + if (status != ERROR_SUCCESS) + return ETWError(status); + session.properties.EnableFlags = EnableFlags; + return status; +} + static ULONG EnableProcessAndThreadMonitoring( Session& session ) { + if ( IsSingletonKernelLoggerSession(session) ) + { + ULONGLONG EnableFlags = session.properties.EnableFlags; + EnableFlags |= EVENT_TRACE_FLAG_THREAD; + ULONG status = UpdateSessionEnableFlags( session, EnableFlags ); + return status; + } + ULONGLONG MatchAnyKeyword = SYSTEM_PROCESS_KW_THREAD; // ThreadStart and ThreadDCStart events ULONG status = EnableProvider( session, SystemProcessProviderGuid, EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, MatchAnyKeyword ); - if( status != ERROR_SUCCESS ) - return status; return status; } static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KHz = 125us */ ) { + if ( !IsOS64Bit() ) + return 0 /* ERROR_SUCCESS */; // TODO: fabricate SetLastError(ERROR_NOT_SUPPORTED) instead? + // CPU Profiling requires special privileges on top of admin privileges DWORD access = ElevatePrivilege( SE_SYSTEM_PROFILE_NAME ); if( access != ERROR_SUCCESS ) return access; - CheckProviderSessions( SystemProfileProviderGuid, 0 ); - ULONG status = EnableProvider( session, SystemProfileProviderGuid ); - if( status != ERROR_SUCCESS ) - return status; + if ( IsSingletonKernelLoggerSession( session ) ) + { + ULONGLONG EnableFlags = session.properties.EnableFlags; + EnableFlags |= EVENT_TRACE_FLAG_PROFILE; + ULONG status = UpdateSessionEnableFlags( session, EnableFlags ); + if ( status != ERROR_SUCCESS ) + return status; + } + else + { + CheckProviderSessions( SystemProfileProviderGuid, 0 ); + ULONG status = EnableProvider( session, SystemProfileProviderGuid ); + if( status != ERROR_SUCCESS ) + return status; + } - status = SetCPUProfilingInterval(microseconds); + ULONG status = SetCPUProfilingInterval(microseconds); if( status != ERROR_SUCCESS ) return status; @@ -453,15 +494,28 @@ static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KH static ULONG EnableContextSwitchMonitoring( Session& session ) { - ULONGLONG MatchAnyKeyword = 0; - MatchAnyKeyword |= SYSTEM_SCHEDULER_KW_CONTEXT_SWITCH; // CSwitch events - MatchAnyKeyword |= SYSTEM_SCHEDULER_KW_DISPATCHER; // ReadyThread events - CheckProviderSessions( SystemSchedulerProviderGuid, MatchAnyKeyword ); - ULONG status = EnableProvider( session, SystemSchedulerProviderGuid, - EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, MatchAnyKeyword ); - if( status != ERROR_SUCCESS ) - return status; - status = EnableStackWalk( session, ThreadGuid, CSwitch::Opcode ); + if ( IsSingletonKernelLoggerSession( session ) ) + { + ULONGLONG EnableFlags = session.properties.EnableFlags; + EnableFlags |= EVENT_TRACE_FLAG_CSWITCH; + EnableFlags |= EVENT_TRACE_FLAG_DISPATCHER; + ULONG status = UpdateSessionEnableFlags( session, EnableFlags ); + if ( status != ERROR_SUCCESS ) + return status; + } + else + { + ULONGLONG MatchAnyKeyword = 0; + MatchAnyKeyword |= SYSTEM_SCHEDULER_KW_CONTEXT_SWITCH; // CSwitch events + MatchAnyKeyword |= SYSTEM_SCHEDULER_KW_DISPATCHER; // ReadyThread events + CheckProviderSessions( SystemSchedulerProviderGuid, MatchAnyKeyword ); + ULONG status = EnableProvider( session, SystemSchedulerProviderGuid, + EVENT_CONTROL_CODE_ENABLE_PROVIDER, TRACE_LEVEL_INFORMATION, MatchAnyKeyword ); + if( status != ERROR_SUCCESS ) + return status; + } + + ULONG status = EnableStackWalk( session, ThreadGuid, CSwitch::Opcode ); return status; } From 44696c47c61c2a8c459ea26bfed2d4bee3dbb26b Mon Sep 17 00:00:00 2001 From: Marcos Slomp Date: Thu, 15 Jan 2026 11:25:26 -0800 Subject: [PATCH 2/3] formatting --- public/client/TracySysTrace.cpp | 18 +++++++++--------- public/client/windows/TracyETW.cpp | 30 +++++++++++++++--------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index b5f72e16..b0cd5df3 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -188,42 +188,42 @@ bool SysTraceStart( int64_t& samplingPeriod ) s_pid = GetCurrentProcessId(); - if ( !etw::CheckAdminPrivilege() ) + if( !etw::CheckAdminPrivilege() ) return false; session_kernel = etw::StartSingletonKernelLoggerSession(); - if ( session_kernel.handle == 0 ) + if( session_kernel.handle == 0 ) return false; #ifndef TRACY_NO_CONTEXT_SWITCH - if ( etw::EnableProcessAndThreadMonitoring( session_kernel ) != ERROR_SUCCESS ) + if( etw::EnableProcessAndThreadMonitoring( session_kernel ) != ERROR_SUCCESS ) return etw::StopSession( session_kernel ), false; - if ( etw::EnableContextSwitchMonitoring( session_kernel ) != ERROR_SUCCESS ) + if( etw::EnableContextSwitchMonitoring( session_kernel ) != ERROR_SUCCESS ) return etw::StopSession( session_kernel ), false; #endif #ifndef TRACY_NO_SAMPLING int microseconds = GetSamplingInterval() / 10; - if ( etw::EnableCPUProfiling( session_kernel, microseconds ) != ERROR_SUCCESS ) + if( etw::EnableCPUProfiling( session_kernel, microseconds ) != ERROR_SUCCESS ) return etw::StopSession( session_kernel ), false; samplingPeriod = GetSamplingPeriod(); #endif consumer_kernel = etw::SetupEventConsumer( session_kernel, EventRecordCallback ); - if ( consumer_kernel == INVALID_PROCESSTRACE_HANDLE ) + if( consumer_kernel == INVALID_PROCESSTRACE_HANDLE ) return etw::StopSession( session_kernel ), false; #ifndef TRACY_NO_VSYNC_CAPTURE session_vsync = etw::StartUserSession( "TracyVsync" ); - if ( session_vsync.handle != 0 ) + if( session_vsync.handle != 0 ) { - if ( etw::EnableVSyncMonitoring( session_vsync ) != ERROR_SUCCESS ) + if( etw::EnableVSyncMonitoring( session_vsync ) != ERROR_SUCCESS ) etw::StopSession( session_vsync ); else { consumer_vsync = etw::SetupEventConsumer( session_vsync, EventRecordCallback ); - if ( consumer_vsync != INVALID_PROCESSTRACE_HANDLE ) + if( consumer_vsync != INVALID_PROCESSTRACE_HANDLE ) { s_threadVsync = (Thread*)tracy_malloc( sizeof( Thread ) ); new(s_threadVsync) Thread( [] (void*) { diff --git a/public/client/windows/TracyETW.cpp b/public/client/windows/TracyETW.cpp index 12910a81..e9651713 100644 --- a/public/client/windows/TracyETW.cpp +++ b/public/client/windows/TracyETW.cpp @@ -134,12 +134,12 @@ constexpr uint32_t Color_Red4 = 0x8b0000; // TracyColor.hpp static void ETWErrorAction( ULONG error_code, const char* message, int length ) { #ifndef TRACY_NO_INTERNAL_MESSAGE -#ifdef TRACY_HAS_CALLSTACK +# ifdef TRACY_HAS_CALLSTACK tracy::InitCallstackCritical(); tracy::Profiler::LogString( MessageSourceType::Tracy, MessageSeverity::Error, Color_Red4, 60, length, message ); -#else +# else tracy::Profiler::LogString( MessageSourceType::Tracy, MessageSeverity::Error, Color_Red4, 0, length, message ); -#endif +# endif #endif #ifdef __cpp_exceptions // TODO: should we throw an exception? @@ -216,7 +216,7 @@ static ULONG StopSession( Session& session ) return ETWError( status ); // once stopped, the session handle becomes invalid session.handle = 0; - for ( auto&& sw : session.stackwalk ) + for( auto&& sw : session.stackwalk ) sw = {}; return ERROR_SUCCESS; } @@ -303,7 +303,7 @@ static ULONG EnableStackWalk( Session& session, GUID EventGuid, UCHAR Opcode ) // Instead, we keep our own array of active stack trace event ids in the session object. for( auto&& sw : session.stackwalk ) { - if ( !IsEqualGUID( sw.EventGuid, {} ) ) + if( !IsEqualGUID( sw.EventGuid, {} ) ) continue; sw.EventGuid = EventGuid; sw.Type = Opcode; @@ -314,7 +314,7 @@ static ULONG EnableStackWalk( Session& session, GUID EventGuid, UCHAR Opcode ) return 0 /* ERROR_SUCCESS */; // TODO: return error instead? } -static ULONG SetCPUProfilingInterval(int microseconds) +static ULONG SetCPUProfilingInterval( int microseconds ) { if( !IsOS64Bit() ) return 0 /* ERROR_SUCCESS */; // TODO: fabricate SetLastError(ERROR_NOT_SUPPORTED) instead? @@ -436,15 +436,15 @@ static ULONG UpdateSessionEnableFlags( Session& session, ULONGLONG EnableFlags ) Session temp = session; temp.properties.EnableFlags = EnableFlags; ULONG status = ControlTraceA( temp.handle, temp.name, &temp.properties, EVENT_TRACE_CONTROL_UPDATE ); - if (status != ERROR_SUCCESS) - return ETWError(status); + if( status != ERROR_SUCCESS ) + return ETWError( status ); session.properties.EnableFlags = EnableFlags; return status; } static ULONG EnableProcessAndThreadMonitoring( Session& session ) { - if ( IsSingletonKernelLoggerSession(session) ) + if( IsSingletonKernelLoggerSession( session ) ) { ULONGLONG EnableFlags = session.properties.EnableFlags; EnableFlags |= EVENT_TRACE_FLAG_THREAD; @@ -460,7 +460,7 @@ static ULONG EnableProcessAndThreadMonitoring( Session& session ) static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KHz = 125us */ ) { - if ( !IsOS64Bit() ) + if( !IsOS64Bit() ) return 0 /* ERROR_SUCCESS */; // TODO: fabricate SetLastError(ERROR_NOT_SUPPORTED) instead? // CPU Profiling requires special privileges on top of admin privileges @@ -468,12 +468,12 @@ static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KH if( access != ERROR_SUCCESS ) return access; - if ( IsSingletonKernelLoggerSession( session ) ) + if( IsSingletonKernelLoggerSession( session ) ) { ULONGLONG EnableFlags = session.properties.EnableFlags; EnableFlags |= EVENT_TRACE_FLAG_PROFILE; ULONG status = UpdateSessionEnableFlags( session, EnableFlags ); - if ( status != ERROR_SUCCESS ) + if( status != ERROR_SUCCESS ) return status; } else @@ -484,7 +484,7 @@ static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KH return status; } - ULONG status = SetCPUProfilingInterval(microseconds); + ULONG status = SetCPUProfilingInterval( microseconds ); if( status != ERROR_SUCCESS ) return status; @@ -494,13 +494,13 @@ static ULONG EnableCPUProfiling( Session& session, int microseconds = 125 /* 8KH static ULONG EnableContextSwitchMonitoring( Session& session ) { - if ( IsSingletonKernelLoggerSession( session ) ) + if( IsSingletonKernelLoggerSession( session ) ) { ULONGLONG EnableFlags = session.properties.EnableFlags; EnableFlags |= EVENT_TRACE_FLAG_CSWITCH; EnableFlags |= EVENT_TRACE_FLAG_DISPATCHER; ULONG status = UpdateSessionEnableFlags( session, EnableFlags ); - if ( status != ERROR_SUCCESS ) + if( status != ERROR_SUCCESS ) return status; } else From 839b38d2ec51100e31d20c6143caa46115b0cbcc Mon Sep 17 00:00:00 2001 From: Marcos Slomp Date: Thu, 15 Jan 2026 11:29:49 -0800 Subject: [PATCH 3/3] removing implicit/default argument value --- public/client/TracySysTrace.cpp | 2 +- public/client/windows/TracyETW.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/public/client/TracySysTrace.cpp b/public/client/TracySysTrace.cpp index b0cd5df3..d012c417 100644 --- a/public/client/TracySysTrace.cpp +++ b/public/client/TracySysTrace.cpp @@ -191,7 +191,7 @@ bool SysTraceStart( int64_t& samplingPeriod ) if( !etw::CheckAdminPrivilege() ) return false; - session_kernel = etw::StartSingletonKernelLoggerSession(); + session_kernel = etw::StartSingletonKernelLoggerSession( 0 ); if( session_kernel.handle == 0 ) return false; diff --git a/public/client/windows/TracyETW.cpp b/public/client/windows/TracyETW.cpp index e9651713..f20e9829 100644 --- a/public/client/windows/TracyETW.cpp +++ b/public/client/windows/TracyETW.cpp @@ -326,7 +326,7 @@ static ULONG SetCPUProfilingInterval( int microseconds ) return ETWError( status ); } -static Session StartSingletonKernelLoggerSession( ULONGLONG EnableFlags = 0 ) +static Session StartSingletonKernelLoggerSession( ULONGLONG EnableFlags ) { Session session = {};