/// <summary> /// Keep track of thread statistics, mainly timing, can be created outside the thread to be tracked. /// </summary> /// <param name="threadName">Name used for logging the collected stastistics</param> /// <param name="storage"></param> public ThreadTrackingStatistic(string threadName) { ExecutingCpuCycleTime = new TimeIntervalThreadCycleCounterBased(); ExecutingWallClockTime = TimeIntervalFactory.CreateTimeInterval(true); ProcessingCpuCycleTime = new TimeIntervalThreadCycleCounterBased(); ProcessingWallClockTime = TimeIntervalFactory.CreateTimeInterval(true); NumRequests = 0; firstStart = true; Name = threadName; CounterStorage storage = StatisticsCollector.ReportDetailedThreadTimeTrackingStats ? CounterStorage.LogOnly : CounterStorage.DontStore; CounterStorage aggrCountersStorage = CounterStorage.LogOnly; // 4 direct counters allExecutingCpuCycleTime.Add( FloatValueStatistic.FindOrCreate(new StatisticName(StatisticNames.THREADS_EXECUTION_TIME_TOTAL_CPU_CYCLES, threadName), () => (float)ExecutingCpuCycleTime.Elapsed.TotalMilliseconds, storage)); allExecutingWallClockTime.Add( FloatValueStatistic.FindOrCreate(new StatisticName(StatisticNames.THREADS_EXECUTION_TIME_TOTAL_WALL_CLOCK, threadName), () => (float)ExecutingWallClockTime.Elapsed.TotalMilliseconds, storage)); allProcessingCpuCycleTime.Add( FloatValueStatistic.FindOrCreate(new StatisticName(StatisticNames.THREADS_PROCESSING_TIME_TOTAL_CPU_CYCLES, threadName), () => (float)ProcessingCpuCycleTime.Elapsed.TotalMilliseconds, storage)); allProcessingWallClockTime.Add( FloatValueStatistic.FindOrCreate(new StatisticName(StatisticNames.THREADS_PROCESSING_TIME_TOTAL_WALL_CLOCK, threadName), () => (float)ProcessingWallClockTime.Elapsed.TotalMilliseconds, storage)); // numRequests allNumProcessedRequests.Add( FloatValueStatistic.FindOrCreate(new StatisticName(StatisticNames.THREADS_PROCESSED_REQUESTS_PER_THREAD, threadName), () => (float)NumRequests, storage)); // aggregate stats if (totalExecutingCpuCycleTime == null) { totalExecutingCpuCycleTime = FloatValueStatistic.FindOrCreate( new StatisticName(StatisticNames.THREADS_EXECUTION_TIME_AVERAGE_CPU_CYCLES, "AllThreads"), () => CalculateTotalAverage(allExecutingCpuCycleTime, totalNumProcessedRequests), aggrCountersStorage); } if (totalExecutingWallClockTime == null) { totalExecutingWallClockTime = FloatValueStatistic.FindOrCreate( new StatisticName(StatisticNames.THREADS_EXECUTION_TIME_AVERAGE_WALL_CLOCK, "AllThreads"), () => CalculateTotalAverage(allExecutingWallClockTime, totalNumProcessedRequests), aggrCountersStorage); } if (totalProcessingCpuCycleTime == null) { totalProcessingCpuCycleTime = FloatValueStatistic.FindOrCreate( new StatisticName(StatisticNames.THREADS_PROCESSING_TIME_AVERAGE_CPU_CYCLES, "AllThreads"), () => CalculateTotalAverage(allProcessingCpuCycleTime, totalNumProcessedRequests), aggrCountersStorage); } if (totalProcessingWallClockTime == null) { totalProcessingWallClockTime = FloatValueStatistic.FindOrCreate( new StatisticName(StatisticNames.THREADS_PROCESSING_TIME_AVERAGE_WALL_CLOCK, "AllThreads"), () => CalculateTotalAverage(allProcessingWallClockTime, totalNumProcessedRequests), aggrCountersStorage); } if (totalNumProcessedRequests == null) { totalNumProcessedRequests = FloatValueStatistic.FindOrCreate( new StatisticName(StatisticNames.THREADS_PROCESSED_REQUESTS_PER_THREAD, "AllThreads"), () => (float)allNumProcessedRequests.Select(cs => cs.GetCurrentValue()).Sum(), aggrCountersStorage); } if (StatisticsCollector.PerformStageAnalysis) { globalStageAnalyzer.AddTracking(this); } }
internal void Start() { if (!countersAvailable) { logger.Warn(ErrorCode.PerfCounterNotRegistered, "CPU & Memory perf counters did not initialize correctly - try repairing Windows perf counter config on this machine with 'lodctr /r' command"); } if (cpuCounterPF != null) { cpuUsageTimer = new SafeTimer(CheckCpuUsage, null, CPU_CHECK_PERIOD, CPU_CHECK_PERIOD); } try { if (cpuCounterPF != null) { // Read initial value of CPU Usage counter CpuUsage = cpuCounterPF.NextValue(); } } catch (InvalidOperationException) { // Can sometimes get exception accessing CPU Usage counter for first time in some runtime environments CpuUsage = 0; } FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_CPUUSAGE, () => CpuUsage); IntValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_TOTALMEMORYKB, () => (long)((MemoryUsage + KB - 1.0) / KB)); // Round up #if LOG_MEMORY_PERF_COUNTERS // print GC stats in the silo log file. StringValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_GENCOLLECTIONCOUNT, () => GCGenCollectionCount); StringValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_GENSIZESKB, () => GCGenSizes); if (timeInGCPF != null) { FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_PERCENTOFTIMEINGC, () => timeInGCPF.NextValue()); } if (allocatedBytesPerSecPF != null) { FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_ALLOCATEDBYTESINKBPERSEC, () => allocatedBytesPerSecPF.NextValue() / KB); } if (promotedMemoryFromGen1PF != null) { FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_PROMOTEDMEMORYFROMGEN1KB, () => promotedMemoryFromGen1PF.NextValue() / KB); } if (largeObjectHeapSizePF != null) { FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_LARGEOBJECTHEAPSIZEKB, () => largeObjectHeapSizePF.NextValue() / KB); } if (promotedFinalizationMemoryFromGen0PF != null) { FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_PROMOTEDMEMORYFROMGEN0KB, () => promotedFinalizationMemoryFromGen0PF.NextValue() / KB); } if (numberOfInducedGCsPF != null) { FloatValueStatistic.FindOrCreate(StatisticNames.RUNTIME_GC_NUMBEROFINDUCEDGCS, () => numberOfInducedGCsPF.NextValue()); } IntValueStatistic.FindOrCreate(StatisticNames.RUNTIME_MEMORY_TOTALPHYSICALMEMORYMB, () => (long)((TotalPhysicalMemory / KB) / KB)); if (availableMemoryCounterPF != null) { IntValueStatistic.FindOrCreate(StatisticNames.RUNTIME_MEMORY_AVAILABLEMEMORYMB, () => (long)((AvailableMemory / KB) / KB)); // Round up } #endif IntValueStatistic.FindOrCreate(StatisticNames.RUNTIME_DOT_NET_THREADPOOL_INUSE_WORKERTHREADS, () => { int maXworkerThreads; int maXcompletionPortThreads; ThreadPool.GetMaxThreads(out maXworkerThreads, out maXcompletionPortThreads); int workerThreads; int completionPortThreads; // GetAvailableThreads Retrieves the difference between the maximum number of thread pool threads // and the number currently active. // So max-Available is the actual number in use. If it goes beyond min, it means we are stressing the thread pool. ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); return(maXworkerThreads - workerThreads); }); IntValueStatistic.FindOrCreate(StatisticNames.RUNTIME_DOT_NET_THREADPOOL_INUSE_COMPLETIONPORTTHREADS, () => { int maXworkerThreads; int maXcompletionPortThreads; ThreadPool.GetMaxThreads(out maXworkerThreads, out maXcompletionPortThreads); int workerThreads; int completionPortThreads; ThreadPool.GetAvailableThreads(out workerThreads, out completionPortThreads); return(maXcompletionPortThreads - completionPortThreads); }); }
private float CalculateTotalAverage(List <FloatValueStatistic> allthreasCounters, FloatValueStatistic allNumRequestsCounter) { float allThreads = allthreasCounters.Select(cs => cs.GetCurrentValue()).Sum(); float numRequests = allNumRequestsCounter.GetCurrentValue(); if (numRequests == 0) { return(0); } return(allThreads / numRequests); }
static public void Delete(StatisticName name) { FloatValueStatistic.Delete(name); }