private void Reset() { if (!CanReset) { throw new InvalidOperationException("Event stream is not resetable (e.g. real time)."); } for (int i = 0; i < handles.Length; i++) { if (handles[i] != TraceEventNativeMethods.INVALID_HANDLE_VALUE) { TraceEventNativeMethods.CloseTrace(handles[i]); handles[i] = TraceEventNativeMethods.INVALID_HANDLE_VALUE; } // Annoying. The OS resets the LogFileMode field, so I have to set it up again. if (!useClassicETW) { logFiles[i].LogFileMode = TraceEventNativeMethods.PROCESS_TRACE_MODE_EVENT_RECORD; logFiles[i].LogFileMode |= TraceEventNativeMethods.PROCESS_TRACE_MODE_RAW_TIMESTAMP; } handles[i] = TraceEventNativeMethods.OpenTrace(ref logFiles[i]); if (handles[i] == TraceEventNativeMethods.INVALID_HANDLE_VALUE) { Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRForLastWin32Error()); } } }
private void Reset() { if (!CanReset) { throw new InvalidOperationException("Event stream is not resetable (eg Real time)"); } // Annoying. The OS resets the LogFileMode field, so I have to set it up again. if (!useClassicETW) { primaryLogFile.LogFileMode = TraceEventNativeMethods.PROCESS_TRACE_MODE_EVENT_RECORD; } if (handles.Length > 1) { if (handles[1] != TraceEventNativeMethods.INVALID_HANDLE_VALUE) { TraceEventNativeMethods.CloseTrace(handles[1]); } kernelModeLogFile.LogFileMode = primaryLogFile.LogFileMode; handles[1] = TraceEventNativeMethods.OpenTrace(ref kernelModeLogFile); if (TraceEventNativeMethods.INVALID_HANDLE_VALUE == handles[1]) { Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRForLastWin32Error()); } } if (handles[0] != TraceEventNativeMethods.INVALID_HANDLE_VALUE) { TraceEventNativeMethods.CloseTrace(handles[0]); } handles[0] = TraceEventNativeMethods.OpenTrace(ref primaryLogFile); if (TraceEventNativeMethods.INVALID_HANDLE_VALUE == handles[0]) { Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRForLastWin32Error()); } }
public ETWTraceEventSource(string fileOrSessionName, TraceEventSourceType type) { long now = DateTime.Now.ToFileTime() - 100000; // subtract 10ms to avoid negative times. primaryLogFile = new TraceEventNativeMethods.EVENT_TRACE_LOGFILEW(); primaryLogFile.BufferCallback = this.TraceEventBufferCallback; useClassicETW = Environment.OSVersion.Version.Major < 6; if (useClassicETW) { IntPtr mem = TraceEventNativeMethods.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_RECORD)); TraceEventNativeMethods.ZeroMemory(mem, (uint)sizeof(TraceEventNativeMethods.EVENT_RECORD)); convertedHeader = (TraceEventNativeMethods.EVENT_RECORD *)mem; primaryLogFile.EventCallback = RawDispatchClassic; } else { primaryLogFile.LogFileMode = TraceEventNativeMethods.PROCESS_TRACE_MODE_EVENT_RECORD; primaryLogFile.EventCallback = RawDispatch; } if (type == TraceEventSourceType.Session) { primaryLogFile.LoggerName = fileOrSessionName; primaryLogFile.LogFileMode |= TraceEventNativeMethods.EVENT_TRACE_REAL_TIME_MODE; } else { if (type == TraceEventSourceType.UserAndKernelFile) { // See if we have also have kernel log moduleFile. if (fileOrSessionName.Length > 4 && string.Compare(fileOrSessionName, fileOrSessionName.Length - 4, ".etl", 0, 4, StringComparison.OrdinalIgnoreCase) == 0) { string kernelFileName = fileOrSessionName.Substring(0, fileOrSessionName.Length - 4) + ".kernel.etl"; if (File.Exists(kernelFileName)) { if (File.Exists(fileOrSessionName)) { handles = new ulong[2]; handles[0] = TraceEventNativeMethods.INVALID_HANDLE_VALUE; kernelModeLogFile = new TraceEventNativeMethods.EVENT_TRACE_LOGFILEW(); kernelModeLogFile.BufferCallback = primaryLogFile.BufferCallback; kernelModeLogFile.EventCallback = primaryLogFile.EventCallback; kernelModeLogFile.LogFileName = kernelFileName; kernelModeLogFile.LogFileMode = primaryLogFile.LogFileMode; handles[1] = TraceEventNativeMethods.OpenTrace(ref kernelModeLogFile); if (TraceEventNativeMethods.INVALID_HANDLE_VALUE == handles[1]) { Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRForLastWin32Error()); } } else { // we have ONLY a *.kernel.etl moduleFile, treat it as the primary moduleFile. fileOrSessionName = kernelFileName; } } } if (!File.Exists(fileOrSessionName)) { throw new FileNotFoundException("Unable to find the file " + fileOrSessionName); } } primaryLogFile.LogFileName = fileOrSessionName; } // Open the main data source if (handles == null) { handles = new ulong[1]; } handles[0] = TraceEventNativeMethods.OpenTrace(ref primaryLogFile); if (TraceEventNativeMethods.INVALID_HANDLE_VALUE == handles[0]) { Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRForLastWin32Error()); } // Session offset time is the minimum of all times. sessionStartTime100ns = primaryLogFile.LogfileHeader.StartTime; if (handles.Length == 2 && kernelModeLogFile.LogfileHeader.StartTime < sessionStartTime100ns) { sessionStartTime100ns = kernelModeLogFile.LogfileHeader.StartTime; } // Real time providers don't set this to something useful if (sessionStartTime100ns == 0) { sessionStartTime100ns = now; } sessionEndTime100ns = primaryLogFile.LogfileHeader.EndTime; if (handles.Length == 2 && sessionEndTime100ns < kernelModeLogFile.LogfileHeader.EndTime) { sessionEndTime100ns = kernelModeLogFile.LogfileHeader.EndTime; } if (sessionEndTime100ns == 0) { sessionEndTime100ns = sessionStartTime100ns; } pointerSize = (int)primaryLogFile.LogfileHeader.PointerSize; if (handles.Length == 2) { pointerSize = (int)kernelModeLogFile.LogfileHeader.PointerSize; } if (pointerSize == 0) { pointerSize = sizeof(IntPtr); Debug.Assert((primaryLogFile.LogFileMode & TraceEventNativeMethods.EVENT_TRACE_REAL_TIME_MODE) != 0); } Debug.Assert(pointerSize == 4 || pointerSize == 8); eventsLost = (int)primaryLogFile.LogfileHeader.EventsLost; cpuSpeedMHz = (int)primaryLogFile.LogfileHeader.CpuSpeedInMHz; numberOfProcessors = (int)primaryLogFile.LogfileHeader.NumberOfProcessors; // Logic for looking up process names processNameForID = new Dictionary <int, string>(); Kernel.ProcessStartGroup += delegate(ProcessTraceData data) { // Get just the file name without the extension. Can't use the 'Path' class because // it tests to make certain it does not have illegal chars etc. Since KernelImageFileName // is not a true user mode path, we can get failures. string path = data.KernelImageFileName; int startIdx = path.LastIndexOf('\\'); if (0 <= startIdx) { startIdx++; } else { startIdx = 0; } int endIdx = path.LastIndexOf('.', startIdx); if (endIdx < 0) { endIdx = path.Length; } processNameForID[data.ProcessID] = path.Substring(startIdx, endIdx - startIdx); }; }
/// <summary> /// Open a ETW event source for processing. This can either be a moduleFile or a real time ETW session /// </summary> /// <param name="fileOrSessionName"> /// If type == ModuleFile this is the name of the moduleFile to open. /// If type == Session this is the name of real time sessing to open.</param> /// <param name="type"></param> // [SecuritySafeCritical] public ETWTraceEventSource(string fileOrSessionName, TraceEventSourceType type) { long now = DateTime.Now.ToFileTime() - 100000; // used as the start time for real time sessions (sub 10msec to avoid negative times) // Allocate the LOGFILE and structures and arrays that hold them // Figure out how many log files we have if (type == TraceEventSourceType.MergeAll) { string fileBaseName = Path.GetFileNameWithoutExtension(fileOrSessionName); string dir = Path.GetDirectoryName(fileOrSessionName); if (dir.Length == 0) { dir = "."; } List <string> allLogFiles = new List <string>(); allLogFiles.AddRange(Directory.GetFiles(dir, fileBaseName + ".etl")); allLogFiles.AddRange(Directory.GetFiles(dir, fileBaseName + ".kernel.etl")); allLogFiles.AddRange(Directory.GetFiles(dir, fileBaseName + ".clr*.etl")); allLogFiles.AddRange(Directory.GetFiles(dir, fileBaseName + ".user*.etl")); if (allLogFiles.Count == 0) { throw new FileNotFoundException("Could not find file " + fileOrSessionName); } logFiles = new TraceEventNativeMethods.EVENT_TRACE_LOGFILEW[allLogFiles.Count]; for (int i = 0; i < allLogFiles.Count; i++) { logFiles[i].LogFileName = allLogFiles[i]; } } else { logFiles = new TraceEventNativeMethods.EVENT_TRACE_LOGFILEW[1]; if (type == TraceEventSourceType.FileOnly) { logFiles[0].LogFileName = fileOrSessionName; } else { Debug.Assert(type == TraceEventSourceType.Session); logFiles[0].LoggerName = fileOrSessionName; logFiles[0].LogFileMode |= TraceEventNativeMethods.EVENT_TRACE_REAL_TIME_MODE; } } handles = new ulong[logFiles.Length]; // Fill out the first log file information (we will clone it later if we have mulitple files). logFiles[0].BufferCallback = this.TraceEventBufferCallback; handles[0] = TraceEventNativeMethods.INVALID_HANDLE_VALUE; useClassicETW = Environment.OSVersion.Version.Major < 6; if (useClassicETW) { IntPtr mem = Marshal.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_RECORD)); TraceEventNativeMethods.ZeroMemory(mem, (uint)sizeof(TraceEventNativeMethods.EVENT_RECORD)); convertedHeader = (TraceEventNativeMethods.EVENT_RECORD *)mem; logFiles[0].EventCallback = RawDispatchClassic; } else { logFiles[0].LogFileMode |= TraceEventNativeMethods.PROCESS_TRACE_MODE_EVENT_RECORD; logFiles[0].EventCallback = RawDispatch; } // We want the raw timestamp because it is needed to match up stacks with the event they go with. logFiles[0].LogFileMode |= TraceEventNativeMethods.PROCESS_TRACE_MODE_RAW_TIMESTAMP; // Copy the information to any additional log files for (int i = 1; i < logFiles.Length; i++) { logFiles[i].BufferCallback = logFiles[0].BufferCallback; logFiles[i].EventCallback = logFiles[0].EventCallback; logFiles[i].LogFileMode = logFiles[0].LogFileMode; handles[i] = handles[0]; } sessionStartTime100ns = long.MaxValue; sessionEndTime100ns = long.MinValue; eventsLost = 0; // Open all the traces for (int i = 0; i < handles.Length; i++) { handles[i] = TraceEventNativeMethods.OpenTrace(ref logFiles[i]); if (handles[i] == TraceEventNativeMethods.INVALID_HANDLE_VALUE) { Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRForLastWin32Error()); } // Start time is minimum of all start times if (logFiles[i].LogfileHeader.StartTime < sessionStartTime100ns) { sessionStartTime100ns = logFiles[i].LogfileHeader.StartTime; } // End time is maximum of all start times if (logFiles[i].LogfileHeader.EndTime > sessionEndTime100ns) { sessionEndTime100ns = logFiles[i].LogfileHeader.EndTime; } // TODO do we even need log pointer size anymore? // We take the max pointer size. if ((int)logFiles[i].LogfileHeader.PointerSize > pointerSize) { pointerSize = (int)logFiles[i].LogfileHeader.PointerSize; } eventsLost += (int)logFiles[i].LogfileHeader.EventsLost; } // Real time providers don't set this to something useful if (sessionStartTime100ns == 0) { sessionStartTime100ns = now; } if (sessionEndTime100ns == 0) { sessionEndTime100ns = long.MaxValue; } if (pointerSize == 0) // Real time does not set this (grrr). { pointerSize = sizeof(IntPtr); Debug.Assert((logFiles[0].LogFileMode & TraceEventNativeMethods.EVENT_TRACE_REAL_TIME_MODE) != 0); } Debug.Assert(pointerSize == 4 || pointerSize == 8); cpuSpeedMHz = (int)logFiles[0].LogfileHeader.CpuSpeedInMHz; numberOfProcessors = (int)logFiles[0].LogfileHeader.NumberOfProcessors; _QPCFreq = logFiles[0].LogfileHeader.PerfFreq; if (_QPCFreq == 0) // Real time does not set this all the time { _QPCFreq = Stopwatch.Frequency; Debug.Assert((logFiles[0].LogFileMode & TraceEventNativeMethods.EVENT_TRACE_REAL_TIME_MODE) != 0); } Debug.Assert(_QPCFreq != 0); int ver = (int)logFiles[0].LogfileHeader.Version; osVersion = new Version((byte)ver, (byte)(ver >> 8)); // Logic for looking up process names processNameForID = new Dictionary <int, string>(); Kernel.ProcessStartGroup += delegate(ProcessTraceData data) { // Get just the file name without the extension. Can't use the 'Path' class because // it tests to make certain it does not have illegal chars etc. Since KernelImageFileName // is not a true user mode path, we can get failures. string path = data.KernelImageFileName; int startIdx = path.LastIndexOf('\\'); if (0 <= startIdx) { startIdx++; } else { startIdx = 0; } int endIdx = path.LastIndexOf('.'); if (endIdx <= startIdx) { endIdx = path.Length; } processNameForID[data.ProcessID] = path.Substring(startIdx, endIdx - startIdx); }; }