예제 #1
0
        /// <summary>
        /// Enable the PMC machine wide, for ETW capture.
        /// </summary>
        /// <param name="profileSourceInfos">Collection of PMC to be enabled.</param>
        public static void SetPreciseMachineCounters(IReadOnlyCollection <ProfileSourceInfo> profileSourceInfos)
        {
            if (profileSourceInfos == null)
            {
                throw new ArgumentNullException(nameof(profileSourceInfos));
            }
            if (!Kernel32.IsWindows8OrGreater())
            {
                throw new InvalidOperationException("System Tracing is only supported on Windows 8 and above.");
            }

            var profileSourceIDs       = new List <int>();
            var profileSourceIntervals = new List <int>();

            foreach (var psi in profileSourceInfos)
            {
                if (AvailablePreciseMachineCounters.TryGetValue(psi.Name, out var profInfo))
                {
                    profileSourceIDs.Add(profInfo.ID);
                    profileSourceIntervals.Add(Math.Min(profInfo.MaxInterval, Math.Max(profInfo.MinInterval, psi.Interval)));
                }
            }

            if (profileSourceIDs.Count > 0)
            {
                //
                // FIXME: This function changes the -pmcsources intervals machine wide.
                //  Maybe we should undo/revert these changes!
                //
                TraceEventProfileSources.Set(profileSourceIDs.ToArray(), profileSourceIntervals.ToArray());
            }
        }
예제 #2
0
        private static void SetPreciseMachineCounters(IEnumerable <ProviderInfo> providers)
        {
            if (IsWindows8OrGreater)
            {
                var availableCpuCounters   = TraceEventProfileSources.GetInfo();
                var profileSourceIDs       = new List <int>();
                var profileSourceIntervals = new List <int>();

                foreach (var cpuInfo in providers.OfType <CpuCounterInfo>())
                {
                    if (availableCpuCounters.TryGetValue(cpuInfo.CounterName, out var profInfo))
                    {
                        profileSourceIDs.Add(profInfo.ID);
                        profileSourceIntervals.Add(Math.Min(profInfo.MaxInterval, Math.Max(profInfo.MinInterval, cpuInfo.Interval)));
                    }
                }

                if (profileSourceIDs.Count > 0)
                {
                    //
                    // FIXME: This function changes the -pmcsources intervals machine wide.
                    //  Maybe we should undo/revert these changes!
                    //
                    TraceEventProfileSources.Set(profileSourceIDs.ToArray(), profileSourceIntervals.ToArray());
                }
            }
        }
예제 #3
0
        public IEnumerable <ValidationError> Validate(ValidationParameters validationParameters)
        {
            if (TraceEventSession.IsElevated() != true)
            {
                yield return(new ValidationError(true, "Must be elevated (Admin) to use Hardware Counters to use ETW Kernel Session."));
            }

            var availableCpuCounters = TraceEventProfileSources.GetInfo();

            foreach (var benchmark in validationParameters.Benchmarks
                     .Where(benchmark => !benchmark.Job.Diagnoser.HardwareCounters.IsNullOrEmpty()))
            {
                foreach (var hardwareCounter in benchmark.Job.Diagnoser.HardwareCounters)
                {
                    if (!EtwTranslations.TryGetValue(hardwareCounter, out var counterName))
                    {
                        yield return(new ValidationError(true, $"Counter {hardwareCounter} not recognized. Please make sure that you are using counter supported on Windows", benchmark));
                    }

                    if (!availableCpuCounters.ContainsKey(counterName))
                    {
                        yield return(new ValidationError(true, $"The counter {counterName} is not available. Please make sure you are Windows 8+ without Hyper-V", benchmark));
                    }
                }
            }
        }
예제 #4
0
        private static PreciseMachineCounter FromCounter(HardwareCounter counter)
        {
            var profileSource = TraceEventProfileSources.GetInfo()[EtwTranslations[counter]]; // it can't fail, diagnoser validates that first

            return(new PreciseMachineCounter(profileSource.ID, profileSource.Name, counter,
                                             profileSource.MinInterval)); // we want the smallest interval to have best possible precision
        }
예제 #5
0
 public static int GetProfileSourceInfoId(string key)
 {
     if (IsWindowsPlatform && TraceEventProfileSources.GetInfo().TryGetValue(key, out ProfileSourceInfo profileSourceInfo))
     {
         return(profileSourceInfo.ID);
     }
     else
     {
         return(-1);
     }
 }
예제 #6
0
 public GenericPerformanceMonitorCounterDiscoverer()
 {
     _performanceMonitorCounter = new T();
     if (TraceEventProfileSources.GetInfo().TryGetValue(_performanceMonitorCounter.Name, out ProfileSourceInfo profileSourceInfo))
     {
         _pmcId = profileSourceInfo.ID;
     }
     else
     {
         _pmcId = -1;
     }
 }
예제 #7
0
 public BasePerformanceMonitorCounter(IPerformanceMonitorCounter pmc) : base(pmc.Name, pmc.DisplayName, pmc.Unit)
 {
     _interval = pmc.Interval;
     if (TraceEventProfileSources.GetInfo().TryGetValue(Id, out ProfileSourceInfo profileSourceInfo))
     {
         _profileSourceInfoID = profileSourceInfo.ID;
     }
     else
     {
         _profileSourceInfoID = -1;
     }
 }
예제 #8
0
        protected override PmcStats GetInitializedStats(Benchmark benchmark)
        {
            var stats = new PmcStats(benchmark.Job.Diagnoser.HardwareCounters);

            var counters = stats.Counters.Values;

            TraceEventProfileSources.Set( // it's a must have to get the events enabled!!
                counters.Select(counter => counter.ProfileSourceId).ToArray(),
                counters.Select(counter => counter.Interval).ToArray());

            return(stats);
        }
예제 #9
0
        protected override PmcStats GetInitializedStats(DiagnoserActionParameters parameters)
        {
            var stats = new PmcStats(parameters.Config.GetHardwareCounters().ToArray());

            var counters = stats.Counters.Values;

            TraceEventProfileSources.Set( // it's a must have to get the events enabled!!
                counters.Select(counter => counter.ProfileSourceId).ToArray(),
                counters.Select(counter => counter.Interval).ToArray());

            return(stats);
        }
예제 #10
0
        public InstructionsRetiredMetricDiscoverer()
        {
            ProfileSourceInfo info;

            if (TraceEventProfileSources.GetInfo().TryGetValue(CounterName, out info))
            {
                _profileSource = info.ID;
            }
            else
            {
                _profileSource = -1;
            }
        }
예제 #11
0
        private static void PrintAvailableProfileSources()
        {
            var availableProfileSources = TraceEventProfileSources.GetInfo();

            foreach (var kvp in availableProfileSources)
            {
                Debug.WriteLine("");
                Debug.WriteLine($"Profile name: {kvp.Key}");
                Debug.WriteLine($"  ID :          {kvp.Value.ID}");
                Debug.WriteLine($"  Interval :    {kvp.Value.Interval}");
                Debug.WriteLine($"  MaxInterval : {kvp.Value.MaxInterval}");
                Debug.WriteLine($"  MinInterval : {kvp.Value.MinInterval}");
                Debug.WriteLine("");
            }
        }
        public static IEnumerable <ValidationError> Validate(ValidationParameters validationParameters, bool mandatory)
        {
            if (!RuntimeInformation.IsWindows())
            {
                yield return(new ValidationError(true, "Hardware Counters and EtwProfiler are supported only on Windows"));

                yield break;
            }

            if (!validationParameters.Config.GetHardwareCounters().Any() && mandatory)
            {
                yield return(new ValidationError(true, "No Hardware Counters defined, probably a bug"));

                yield break;
            }

            if (TraceEventSession.IsElevated() != true)
            {
                yield return(new ValidationError(true, "Must be elevated (Admin) to use ETW Kernel Session (required for Hardware Counters and EtwProfiler)."));
            }

            var availableCpuCounters = TraceEventProfileSources.GetInfo();

            foreach (var hardwareCounter in validationParameters.Config.GetHardwareCounters())
            {
                if (!EtwTranslations.TryGetValue(hardwareCounter, out var counterName))
                {
                    yield return(new ValidationError(true, $"Counter {hardwareCounter} not recognized. Please make sure that you are using counter available on your machine. You can get the list of available counters by running `tracelog.exe -profilesources Help`"));
                }

                if (!availableCpuCounters.ContainsKey(counterName))
                {
                    yield return(new ValidationError(true, $"The counter {counterName} is not available. Please make sure you are Windows 8+ without Hyper-V"));
                }
            }

            foreach (var benchmark in validationParameters.Benchmarks)
            {
                if (benchmark.Job.Infrastructure.HasValue(InfrastructureMode.ToolchainCharacteristic) &&
                    (benchmark.Job.Infrastructure.Toolchain is InProcessToolchain || benchmark.Job.Infrastructure.Toolchain is InProcessEmitToolchain))
                {
                    yield return(new ValidationError(true, "Hardware Counters are not supported for InProcessToolchain.", benchmark));
                }
            }
        }
예제 #13
0
        private void DoCpuCountersListClick(object sender, RoutedEventArgs e)
        {
            var cpuCounterSpecs = new List <string>();
            var cpuCounters     = TraceEventProfileSources.GetInfo();

            foreach (var cpuCounter in cpuCounters.Values)
            {
                var defaultCount = Math.Max(100000, cpuCounter.MinInterval);
                if (cpuCounter.Name == "Timer")
                {
                    defaultCount = 10000;
                }
                var cpuCounterSpec = cpuCounter.Name + ":" + defaultCount.ToString();
                cpuCounterSpecs.Add(cpuCounterSpec);
            }
            CpuCountersListBox.ItemsSource = cpuCounterSpecs;
            CpuCountersPopup.IsOpen        = true;
        }
예제 #14
0
        protected override PmcStats GetInitializedStats(DiagnoserActionParameters parameters)
        {
            var stats = new PmcStats(parameters.Config.GetHardwareCounters().ToArray(), FromCounter);

            var counters = stats.Counters.Values;

            try
            {
                TraceEventProfileSources.Set( // it's a must have to get the events enabled!!
                    counters.Select(counter => counter.ProfileSourceId).ToArray(),
                    counters.Select(counter => counter.Interval).ToArray());
            }
            catch (System.Runtime.InteropServices.COMException ex) when(ex.Message.StartsWith("The WMI data block or event notification has already been enabled"))
            {
                // previous run was interrupted by ctrl+c and never stopped
            }

            return(stats);
        }
예제 #15
0
        private static void PrintAvailableProfileSources()
        {
            var availableProfileSources = TraceEventProfileSources.GetInfo();
            var cpuCounterIds           = new List <int>();
            var cpuCounterIntervals     = new List <int>();
            var sb = new StringBuilder();

            foreach (var kvp in availableProfileSources)
            {
                sb.AppendLine();
                sb.AppendLine($"Profile name: {kvp.Key}");
                sb.AppendLine($"  ID :          {kvp.Value.ID}");
                sb.AppendLine($"  Interval :    {kvp.Value.Interval}");
                sb.AppendLine($"  MaxInterval : {kvp.Value.MaxInterval}");
                sb.AppendLine($"  MinInterval : {kvp.Value.MinInterval}");
                sb.AppendLine();
            }

            WriteDebugLine(sb.ToString());
        }
예제 #16
0
 static Helper()
 {
     AvailablePreciseMachineCounters = TraceEventProfileSources.GetInfo();
     CanEnableKernelProvider         = TraceEventSession.IsElevated() == true;
 }
        internal static PreciseMachineCounter FromCounter(HardwareCounter counter, Func <ProfileSourceInfo, int> intervalSelector)
        {
            var profileSource = TraceEventProfileSources.GetInfo()[EtwTranslations[counter]]; // it can't fail, diagnoser validates that first

            return(new PreciseMachineCounter(profileSource.ID, profileSource.Name, counter, intervalSelector(profileSource)));
        }
 internal static void Enable(IEnumerable <PreciseMachineCounter> counters)
 {
     TraceEventProfileSources.Set( // it's a must have to get the events enabled!!
         counters.Select(counter => counter.ProfileSourceId).ToArray(),
         counters.Select(counter => counter.Interval).ToArray());
 }
예제 #19
0
        public static string Start(string etlPath, IEnumerable <ProviderInfo> providerInfo, int bufferSizeMB = 64)
        {
            EnsureUnloadHandlerRegistered();

            var      userSessionName = "xunit.performance.logger." + Guid.NewGuid().ToString();
            Sessions sessions        = new Sessions();

            sessions.UserFileName   = Path.ChangeExtension(etlPath, ".user.etl");
            sessions.KernelFileName = Path.ChangeExtension(etlPath, ".kernel.etl");
            sessions.MergedFileName = etlPath;

            var mergedProviderInfo = ProviderInfo.Merge(providerInfo);

            try
            {
                sessions.UserSession = new TraceEventSession(userSessionName, sessions.UserFileName);
                sessions.UserSession.BufferSizeMB = bufferSizeMB;

                var availableCpuCounters = TraceEventProfileSources.GetInfo();
                var cpuCounterIds        = new List <int>();
                var cpuCounterIntervals  = new List <int>();
                foreach (var cpuInfo in mergedProviderInfo.OfType <CpuCounterInfo>())
                {
                    ProfileSourceInfo profInfo;
                    if (availableCpuCounters.TryGetValue(cpuInfo.CounterName, out profInfo))
                    {
                        cpuCounterIds.Add(profInfo.ID);
                        cpuCounterIntervals.Add(Math.Min(profInfo.MaxInterval, Math.Max(profInfo.MinInterval, cpuInfo.Interval)));
                    }
                }

                if (cpuCounterIds.Count > 0)
                {
                    TraceEventProfileSources.Set(cpuCounterIds.ToArray(), cpuCounterIntervals.ToArray());
                }

                var kernelInfo = mergedProviderInfo.OfType <KernelProviderInfo>().FirstOrDefault();
                if (kernelInfo != null && NeedSeparateKernelSession(kernelInfo.Keywords))
                {
                    sessions.KernelSession = new TraceEventSession(KernelTraceEventParser.KernelSessionName, sessions.KernelFileName);
                    sessions.KernelSession.BufferSizeMB = bufferSizeMB;
                }
                else
                {
                    sessions.KernelFileName = sessions.UserFileName;
                    sessions.KernelSession  = sessions.UserSession;
                }

                if (kernelInfo != null)
                {
                    var kernelKeywords      = (KernelTraceEventParser.Keywords)kernelInfo.Keywords;
                    var kernelStackKeywords = (KernelTraceEventParser.Keywords)kernelInfo.StackKeywords;
                    sessions.KernelSession.EnableKernelProvider(kernelKeywords, kernelStackKeywords);
                }

                foreach (var userInfo in mergedProviderInfo.OfType <UserProviderInfo>())
                {
                    sessions.UserSession.EnableProvider(userInfo.ProviderGuid, userInfo.Level, userInfo.Keywords);
                }

                s_sessions[userSessionName] = sessions;
            }
            catch
            {
                sessions.Close();
                throw;
            }

            return(userSessionName);
        }