private void ContextChangedHandler(AsyncLocalValueChangedArgs <object> args) { // if (!args.ThreadContextChanged) return; if (!IsRunning) { return; } long tid = GetThreadId(); if (args.PreviousValue == null) { ContextItem.Value = new ContextSwitchInfo() { ThreadId = tid, StartAt = Stopwatch.StartNew(), UsageOnStart = CpuUsageReader.GetByThread().Value, }; } else if (args.CurrentValue == null) { var contextOnStart = ContextItem.Value; ContextItem.Value = null; if (contextOnStart == null) { throw new InvalidOperationException( "CpuUsageAsyncWatcher.OnEnd: Missing contextOnStart. Please report"); } if (tid != contextOnStart.ThreadId) { throw new InvalidOperationException( $"CpuUsageAsyncWatcher.OnEnd: ContextItem.Value.ThreadId is not as expected." + $"Thread.CurrentThread.ManagedThreadId is {tid}. " + $"contextOnStart.ThreadId is {contextOnStart.ThreadId}. Please report"); } var ticks = contextOnStart.StartAt.ElapsedTicks; var duration = ticks / (double)Stopwatch.Frequency; var usageOnEnd = CpuUsageReader.GetByThread().Value; var cpuUsage = CpuUsage.Substruct(usageOnEnd, contextOnStart.UsageOnStart); ContextSwitchMetrics logRow = new ContextSwitchMetrics() { Duration = duration, CpuUsage = cpuUsage }; lock (_Log) _Log.Add(logRow); } #if DEBUG Console.ForegroundColor = ConsoleColor.Cyan; string AsString(object value) => value == null ? "off" : Convert.ToString(value); Console.WriteLine($"Value Changed {(args.ThreadContextChanged ? $"WITH context #{tid}" : $"WITHOUT context #{tid}")}: {AsString(args.PreviousValue)} => {AsString(args.CurrentValue)}");
// for intellisense public static CpuUsage?Get(CpuUsageScope scope) { return(CpuUsageReader.Get(scope)); }