This option was a pseudo mechanism to fake "streaming" events out-of-proc.
The idea was to have EventPipe creating files every N seconds, with event data up to that point. Thus, external processes could read these files in an attempt to get "read-time" data.
Now, we actually have streaming of event through IPC channels, so this option is not needed.
private uint m_circularBufferSizeInMB;
private List<EventPipeProviderConfiguration> m_providers;
private TimeSpan m_minTimeBetweenSamples = TimeSpan.FromMilliseconds(1);
- private ulong m_multiFileTraceLengthInSeconds = 0;
internal EventPipeConfiguration(
string outputFile,
get { return m_circularBufferSizeInMB; }
}
- internal ulong MultiFileTraceLengthInSeconds
- {
- get { return m_multiFileTraceLengthInSeconds; }
- }
-
internal EventPipeProviderConfiguration[] Providers
{
get { return m_providers.ToArray(); }
m_minTimeBetweenSamples = minTimeBetweenSamples;
}
-
- internal void SetMultiFileTraceLength(ulong traceLengthInSeconds)
- {
- m_multiFileTraceLengthInSeconds = traceLengthInSeconds;
- }
}
internal static class EventPipe
configuration.CircularBufferSizeInMB,
(ulong)configuration.ProfilerSamplingRateInNanoseconds,
providers,
- (uint)providers.Length,
- configuration.MultiFileTraceLengthInSeconds);
+ (uint)providers.Length);
}
internal static void Disable()
uint circularBufferSizeInMB,
ulong profilerSamplingRateInNanoseconds,
EventPipeProviderConfiguration[] providers,
- uint numProviders,
- ulong multiFileTraceLengthInSeconds);
+ uint numProviders);
[DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
internal static extern void Disable(UInt64 sessionID);
private const string ConfigKey_CircularMB = "CircularMB";
private const string ConfigKey_OutputPath = "OutputPath";
private const string ConfigKey_ProcessID = "ProcessID";
- private const string ConfigKey_MultiFileSec = "MultiFileSec";
// The default set of providers/keywords/levels. Used if an alternative configuration is not specified.
private static EventPipeProviderConfiguration[] DefaultProviderConfiguration => new EventPipeProviderConfiguration[]
string strProviderConfig = null;
string strCircularMB = null;
string strProcessID = null;
- string strMultiFileSec = null;
// Split the configuration entries by line.
string[] configEntries = strConfigContents.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.RemoveEmptyEntries);
{
strProcessID = entryComponents[1];
}
- else if (key.Equals(ConfigKey_MultiFileSec))
- {
- strMultiFileSec = entryComponents[1];
- }
}
}
throw new ArgumentNullException(nameof(outputPath));
}
- // Check to see if MultiFileSec is specified.
- ulong multiFileSec = 0;
- if (!string.IsNullOrEmpty(strMultiFileSec))
- {
- multiFileSec = Convert.ToUInt64(strMultiFileSec);
- }
-
// Build the full path to the trace file.
string traceFileName = BuildTraceFileName();
string outputFile = Path.Combine(outputPath, traceFileName);
// Initialize a new configuration object.
EventPipeConfiguration config = new EventPipeConfiguration(outputFile, circularMB);
- config.SetMultiFileTraceLength(multiFileSec);
// Set the provider configuration if specified.
if (!string.IsNullOrEmpty(strProviderConfig))
new EventPipeProviderConfiguration(NativeRuntimeEventSource.EventSourceName, (ulong) aggregatedKeywords, (uint) highestLevel, null)
};
- m_sessionID = EventPipeInternal.Enable(null, 1024, 1, providerConfiguration, 1, 0);
+ m_sessionID = EventPipeInternal.Enable(null, 1024, 1, providerConfiguration, 1);
Debug.Assert(m_sessionID != 0);
// Get the session information that is required to properly dispatch events.
EventPipeConfiguration *EventPipe::s_pConfig = NULL;
EventPipeSession *EventPipe::s_pSession = NULL;
EventPipeBufferManager *EventPipe::s_pBufferManager = NULL;
-LPCWSTR EventPipe::s_pOutputPath = NULL;
EventPipeFile *EventPipe::s_pFile = NULL;
EventPipeEventSource *EventPipe::s_pEventSource = NULL;
LPCWSTR EventPipe::s_pCommandLine = NULL;
-unsigned long EventPipe::s_nextFileIndex;
HANDLE EventPipe::s_fileSwitchTimerHandle = NULL;
ULONGLONG EventPipe::s_lastFlushSwitchTime = 0;
-uint64_t EventPipe::s_multiFileTraceLengthInSeconds = 0;
#ifdef FEATURE_PAL
// This function is auto-generated from /src/scripts/genEventPipe.py
delete pBufferManager;
delete s_pEventSource;
s_pEventSource = NULL;
- delete[] s_pOutputPath;
- s_pOutputPath = NULL;
// On Windows, this is just a pointer to the return value from
// GetCommandLineW(), so don't attempt to free it.
uint32_t circularBufferSizeInMB,
uint64_t profilerSamplingRateInNanoseconds,
const EventPipeProviderConfiguration *pProviders,
- uint32_t numProviders,
- uint64_t multiFileTraceLengthInSeconds)
+ uint32_t numProviders)
{
CONTRACTL
{
// Take the lock before enabling tracing.
CrstHolder _crst(GetLock());
- s_multiFileTraceLengthInSeconds = multiFileTraceLengthInSeconds;
-
// Create a new session.
SampleProfiler::SetSamplingRate((unsigned long)profilerSamplingRateInNanoseconds);
EventPipeSession *pSession = s_pConfig->CreateSession(
pProviders,
numProviders);
- // Initialize the next file index.
- s_nextFileIndex = 1;
-
// Initialize the last file switch time.
s_lastFlushSwitchTime = CLRGetTickCount64();
// A NULL output path means that we should not write the results to a file.
// This is used in the EventListener streaming case.
if (strOutputPath != NULL)
- {
-
- // Save the output file path.
- SString outputPath(strOutputPath);
- SIZE_T outputPathLen = outputPath.GetCount();
- WCHAR *pOutputPath = new WCHAR[outputPathLen + 1];
- wcsncpy(pOutputPath, outputPath.GetUnicode(), outputPathLen);
- pOutputPath[outputPathLen] = '\0';
- s_pOutputPath = pOutputPath;
-
- SString nextTraceFilePath;
- GetNextFilePath(nextTraceFilePath);
-
- s_pFile = new EventPipeFile(new FileStreamWriter(nextTraceFilePath));
- }
-
- const DWORD FileSwitchTimerPeriodMS = 1000;
- return Enable(pSession, SwitchToNextFileTimerCallback, FileSwitchTimerPeriodMS, FileSwitchTimerPeriodMS);
+ s_pFile = new EventPipeFile(new FileStreamWriter(SString(strOutputPath)));
+ return Enable(pSession);
}
EventPipeSessionID EventPipe::Enable(
pProviders,
numProviders);
+ // Initialize the last file switch time.
+ s_lastFlushSwitchTime = CLRGetTickCount64();
+
// Reply back to client with the SessionId
uint32_t nBytesWritten = 0;
EventPipeSessionID sessionId = (EventPipeSessionID) pSession;
GC_TRIGGERS;
MODE_ANY;
PRECONDITION(pSession != nullptr);
- PRECONDITION(callback != nullptr);
- PRECONDITION(dueTime > 0);
- PRECONDITION(period > 0);
PRECONDITION(GetLock()->OwnedByCurrentThread());
}
CONTRACTL_END;
// Enable the sample profiler
SampleProfiler::Enable();
- CreateFlushTimerCallback(callback, dueTime, period);
+ if (callback != nullptr)
+ CreateFlushTimerCallback(callback, dueTime, period);
// Return the session ID.
return (EventPipeSessionID)s_pSession;
// Disable tracing.
s_pConfig->Disable(s_pSession);
- s_multiFileTraceLengthInSeconds = 0;
-
// Delete the session.
s_pConfig->DeleteSession(s_pSession);
s_pSession = NULL;
s_fileSwitchTimerHandle = NULL;
}
-void WINAPI EventPipe::SwitchToNextFileTimerCallback(PVOID parameter, BOOLEAN timerFired)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(timerFired);
- }
- CONTRACTL_END;
-
- // Take the lock control lock to make sure that tracing isn't disabled during this operation.
- CrstHolder _crst(GetLock());
-
- if (s_pSession == nullptr || s_pFile == nullptr)
- return;
-
- // Make sure that we should actually switch files.
- if (!Enabled() || s_pSession->GetSessionType() != EventPipeSessionType::File || s_multiFileTraceLengthInSeconds == 0)
- return;
-
- GCX_PREEMP();
-
- if (CLRGetTickCount64() > (s_lastFlushSwitchTime + (s_multiFileTraceLengthInSeconds * 1000)))
- {
- SwitchToNextFile();
- s_lastFlushSwitchTime = CLRGetTickCount64();
- }
-}
-
void WINAPI EventPipe::FlushTimer(PVOID parameter, BOOLEAN timerFired)
{
CONTRACTL
}
}
-void EventPipe::SwitchToNextFile()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- PRECONDITION(s_pFile != nullptr);
- PRECONDITION(GetLock()->OwnedByCurrentThread());
- }
- CONTRACTL_END
-
- // Get the current time stamp.
- // WriteAllBuffersToFile will use this to ensure that no events after the current timestamp are written into the file.
- LARGE_INTEGER stopTimeStamp;
- QueryPerformanceCounter(&stopTimeStamp);
- s_pBufferManager->WriteAllBuffersToFile(s_pFile, stopTimeStamp);
-
- // Open the new file.
- SString nextTraceFilePath;
- GetNextFilePath(nextTraceFilePath);
-
- StreamWriter *pStreamWriter = new (nothrow) FileStreamWriter(nextTraceFilePath);
- if (pStreamWriter == nullptr)
- {
- // TODO: Add error handling.
- return;
- }
-
- EventPipeFile *pFile = new (nothrow) EventPipeFile(pStreamWriter);
- if (pFile == NULL)
- {
- // TODO: Add error handling.
- return;
- }
-
- // Close the previous file.
- delete s_pFile;
-
- // Swap in the new file.
- s_pFile = pFile;
-}
-
-void EventPipe::GetNextFilePath(SString &nextTraceFilePath)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(GetLock()->OwnedByCurrentThread());
- }
- CONTRACTL_END;
-
- // Set the full path to the requested trace file as the next file path.
- nextTraceFilePath.Set(s_pOutputPath);
-
- // If multiple files have been requested, then add a sequence number to the trace file name.
- if (s_multiFileTraceLengthInSeconds > 0)
- {
- // Remove the ".netperf" file extension if it exists.
- SString::Iterator netPerfExtension = nextTraceFilePath.End();
- if (nextTraceFilePath.FindBack(netPerfExtension, W(".netperf")))
- {
- nextTraceFilePath.Truncate(netPerfExtension);
- }
-
- // Add the sequence number and the ".netperf" file extension.
- WCHAR strNextIndex[21];
- swprintf_s(strNextIndex, 21, W(".%u.netperf"), s_nextFileIndex++);
- nextTraceFilePath.Append(strNextIndex);
- }
-}
-
EventPipeSession *EventPipe::GetSession(EventPipeSessionID id)
{
LIMITED_METHOD_CONTRACT;
uint32_t circularBufferSizeInMB,
uint64_t profilerSamplingRateInNanoseconds,
const EventPipeProviderConfiguration *pProviders,
- uint32_t numProviders,
- uint64_t multiFileTraceLengthInSeconds);
+ uint32_t numProviders);
static EventPipeSessionID Enable(
IpcStream *pStream,
// Enable the specified EventPipe session.
static EventPipeSessionID Enable(
EventPipeSession *const pSession,
- WAITORTIMERCALLBACK callback,
- DWORD dueTime,
- DWORD period);
+ WAITORTIMERCALLBACK callback = nullptr,
+ DWORD dueTime = 0,
+ DWORD period = 0);
static void CreateFlushTimerCallback(WAITORTIMERCALLBACK Callback, DWORD DueTime, DWORD Period);
static void DeleteFlushTimerCallback();
- // Performs one polling operation to determine if it is necessary to switch to a new file.
- // If the polling operation decides it is time, it will perform the switch.
- // Called directly from the timer when the timer is triggered.
- static void WINAPI SwitchToNextFileTimerCallback(PVOID parameter, BOOLEAN timerFired);
-
static void WINAPI FlushTimer(PVOID parameter, BOOLEAN timerFired);
- // If event pipe has been configured to write multiple files, switch to the next file.
- static void SwitchToNextFile();
-
- // Generate the file path for the next trace file.
- // This is used when event pipe has been configured to create multiple trace files with a specified maximum length of time.
- static void GetNextFilePath(SString &nextTraceFilePath);
-
// Callback function for the stack walker. For each frame walked, this callback is invoked.
static StackWalkAction StackWalkCallback(CrawlFrame *pCf, StackContents *pData);
static EventPipeConfiguration *s_pConfig;
static EventPipeSession *s_pSession;
static EventPipeBufferManager *s_pBufferManager;
- static LPCWSTR s_pOutputPath;
- static unsigned long s_nextFileIndex;
static EventPipeFile *s_pFile;
static EventPipeEventSource *s_pEventSource;
static LPCWSTR s_pCommandLine;
static HANDLE s_fileSwitchTimerHandle;
static ULONGLONG s_lastFlushSwitchTime;
- static uint64_t s_multiFileTraceLengthInSeconds;
};
struct EventPipeProviderConfiguration
UINT32 circularBufferSizeInMB,
INT64 profilerSamplingRateInNanoseconds,
EventPipeProviderConfiguration *pProviders,
- UINT32 numProviders,
- UINT64 multiFileTraceLengthInSeconds)
+ UINT32 numProviders)
{
QCALL_CONTRACT;
circularBufferSizeInMB,
profilerSamplingRateInNanoseconds,
pProviders,
- numProviders,
- multiFileTraceLengthInSeconds);
+ numProviders);
}
END_QCALL;
UINT32 circularBufferSizeInMB,
INT64 profilerSamplingRateInNanoseconds,
EventPipeProviderConfiguration *pProviders,
- UINT32 numProviders,
- UINT64 multiFileTraceLengthInSeconds);
+ UINT32 numProviders);
//! TODO: Add a ListActiveSessions to get the live SessionID in order to Disable?
// The protocol buffer is defined as:
// X, Y, Z means encode bytes for X followed by bytes for Y followed by bytes for Z
- // message = uint circularBufferMB, ulong multiFileTraceLength, string outputPath, array<provider_config> providers
+ // message = uint circularBufferMB, string outputPath, array<provider_config> providers
// uint = 4 little endian bytes
// ulong = 8 little endian bytes
// wchar = 2 little endian bytes, UTF16 encoding
LPCWSTR strOutputPath;
uint32_t circularBufferSizeInMB = EventPipeProtocolHelper::DefaultCircularBufferMB;
- uint64_t multiFileTraceLengthInSeconds = EventPipeProtocolHelper::DefaultMultiFileTraceLengthInSeconds;
CQuickArray<EventPipeProviderConfiguration> providerConfigs;
uint8_t *pBufferCursor = buffer;
uint32_t bufferLen = nNumberOfBytesRead;
if (!TryParse(pBufferCursor, bufferLen, circularBufferSizeInMB) ||
- !TryParse(pBufferCursor, bufferLen, multiFileTraceLengthInSeconds) ||
!TryParseString(pBufferCursor, bufferLen, strOutputPath) ||
!TryParseProviderConfiguration(pBufferCursor, bufferLen, providerConfigs))
{
if (providerConfigs.Size() > 0)
{
sessionId = EventPipe::Enable(
- strOutputPath, // outputFile
- circularBufferSizeInMB, // circularBufferSizeInMB
- DefaultProfilerSamplingRateInNanoseconds, // ProfilerSamplingRateInNanoseconds
- providerConfigs.Ptr(), // pConfigs
- static_cast<uint32_t>(providerConfigs.Size()), // numConfigs
- multiFileTraceLengthInSeconds); // multiFileTraceLengthInSeconds
+ strOutputPath, // outputFile
+ circularBufferSizeInMB, // circularBufferSizeInMB
+ DefaultProfilerSamplingRateInNanoseconds, // ProfilerSamplingRateInNanoseconds
+ providerConfigs.Ptr(), // pConfigs
+ static_cast<uint32_t>(providerConfigs.Size())); // numConfigs
}
uint32_t nBytesWritten = 0;
// The protocol buffer is defined as:
// X, Y, Z means encode bytes for X followed by bytes for Y followed by bytes for Z
- // message = uint circularBufferMB, ulong multiFileTraceLength, string outputPath, array<provider_config> providers
+ // message = uint circularBufferMB, string outputPath, array<provider_config> providers
// uint = 4 little endian bytes
// wchar = 2 little endian bytes, UTF16 encoding
// array<T> = uint length, length # of Ts
LPCWSTR strOutputPath;
uint32_t circularBufferSizeInMB = EventPipeProtocolHelper::DefaultCircularBufferMB;
- uint64_t multiFileTraceLengthInSeconds = EventPipeProtocolHelper::DefaultMultiFileTraceLengthInSeconds;
CQuickArray<EventPipeProviderConfiguration> providerConfigs;
uint8_t *pBufferCursor = buffer;
uint32_t bufferLen = nNumberOfBytesRead;
if (!TryParse(pBufferCursor, bufferLen, circularBufferSizeInMB) ||
- !TryParse(pBufferCursor, bufferLen, multiFileTraceLengthInSeconds) ||
!TryParseString(pBufferCursor, bufferLen, strOutputPath) ||
!TryParseProviderConfiguration(pBufferCursor, bufferLen, providerConfigs))
{
private:
const static uint32_t DefaultCircularBufferMB = 1024; // 1 GB
- const static uint64_t DefaultMultiFileTraceLengthInSeconds = 0;
const static uint32_t DefaultProfilerSamplingRateInNanoseconds = 1000000; // 1 msec.
const static uint32_t IpcStreamReadBufferSize = 8192;