/// <summary> /// Sets the Profile Sources (CPU machine counters) that will be used if PMC (Precise Machine Counters) /// are turned on. Each CPU counter is given a id (the profileSourceID) and has an interval /// (the number of counts you skip for each event you log). You can get the human name for /// all the supported CPU counters by calling GetProfileSourceInfo. Then choose the ones you want /// and configure them here (the first array indicating the CPU counters to enable, and the second /// array indicating the interval. The second array can be shorter then the first, in which case /// the existing interval is used (it persists and has a default on boot). /// </summary> public static unsafe void SetProfileSources(int[] profileSourceIDs, int[] profileSourceIntervals) { var version = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor; if (version < 62) throw new ApplicationException("Profile source only availabe on Win8 and beyond."); TraceEventNativeMethods.SetSystemProfilePrivilege(); var interval = new TraceEventNativeMethods.TRACE_PROFILE_INTERVAL(); for (int i = 0; i < profileSourceIntervals.Length; i++) { interval.Source = profileSourceIDs[i]; interval.Interval = profileSourceIntervals[i]; var result = TraceEventNativeMethods.TraceSetInformation(0, TraceEventNativeMethods.TRACE_INFO_CLASS.TraceSampledProfileIntervalInfo, &interval, sizeof(TraceEventNativeMethods.TRACE_PROFILE_INTERVAL)); if (result != 0) Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(result)); } fixed (int* sourcesPtr = profileSourceIDs) { var result = TraceEventNativeMethods.TraceSetInformation(0, TraceEventNativeMethods.TRACE_INFO_CLASS.TraceProfileSourceConfigInfo, sourcesPtr, profileSourceIDs.Length * sizeof(int)); if (result != 0) Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(result)); } }
/// <summary> /// Returns a ditionary of keyed by name of ProfileSourceInfo structures for all the CPU counters available on the machine. /// TODO FIX NOW remove log parameter. /// </summary> public static unsafe Dictionary<string, ProfileSourceInfo> GetProfileSourceInfo() { var version = Environment.OSVersion.Version.Major * 10 + Environment.OSVersion.Version.Minor; if (version < 62) throw new ApplicationException("Profile source only availabe on Win8 and beyond."); var ret = new Dictionary<string, ProfileSourceInfo>(StringComparer.OrdinalIgnoreCase); // Figure out how much space we need. int retLen = 0; var result = TraceEventNativeMethods.TraceQueryInformation(0, TraceEventNativeMethods.TRACE_INFO_CLASS.TraceProfileSourceListInfo, null, 0, ref retLen); Debug.Assert(result == 24); // Not enough space. if (retLen != 0) { // Do it for real. byte* buffer = stackalloc byte[retLen]; result = TraceEventNativeMethods.TraceQueryInformation(0, TraceEventNativeMethods.TRACE_INFO_CLASS.TraceProfileSourceListInfo, buffer, retLen, ref retLen); if (result == 0) { var interval = new TraceEventNativeMethods.TRACE_PROFILE_INTERVAL(); var profileSource = (TraceEventNativeMethods.PROFILE_SOURCE_INFO*)buffer; for (int i = 0; i < 10; i++) { char* namePtr = (char*)&profileSource[1]; // points off the end of the array; interval.Source = profileSource->Source; interval.Interval = 0; result = TraceEventNativeMethods.TraceQueryInformation(0, TraceEventNativeMethods.TRACE_INFO_CLASS.TraceSampledProfileIntervalInfo, &interval, sizeof(TraceEventNativeMethods.TRACE_PROFILE_INTERVAL), ref retLen); if (result != 0) Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(result)); var name = new string(namePtr); ret.Add(name, new ProfileSourceInfo() { Name = name, ID = profileSource->Source, Interval = interval.Interval, MinInterval = profileSource->MinInterval, MaxInterval = profileSource->MaxInterval, }); if (profileSource->NextEntryOffset == 0) break; profileSource = (TraceEventNativeMethods.PROFILE_SOURCE_INFO*)(profileSource->NextEntryOffset + (byte*)profileSource); } } else Marshal.ThrowExceptionForHR(TraceEventNativeMethods.GetHRFromWin32(result)); } return ret; }