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; }