The Labs \ Source Viewer \ SSCLI \ System.Diagnostics \ CounterSampleCalculator

  1. //------------------------------------------------------------------------------
  2. // <copyright file="CounterSampleCalculator.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. namespace System.Diagnostics
  16. {
  17.     using System.Threading;
  18.     using System;
  19.     using System.ComponentModel;
  20.     using Microsoft.Win32;
  21.     using System.Text;
  22.     using System.IO;
  23.     using System.Runtime.InteropServices;
  24.     using System.Security.Permissions;
  25.     using System.Globalization;
  26.     using System.Runtime.Versioning;
  27.    
  28.     /// <devdoc>
  29.     /// Set of utility functions for interpreting the counter data
  30.     /// NOTE: most of this code was taken and ported from counters.c (PerfMon source code)
  31.     /// </devdoc>
  32.     public static class CounterSampleCalculator
  33.     {
  34.         static bool perfCounterDllLoaded = false;
  35.        
  36.         /// <devdoc>
  37.         /// Converts 100NS elapsed time to fractional seconds
  38.         /// </devdoc>
  39.         /// <internalonly/>
  40.         private static float GetElapsedTime(CounterSample oldSample, CounterSample newSample)
  41.         {
  42.             float eSeconds;
  43.             float eDifference;
  44.            
  45.             if (newSample.RawValue == 0) {
  46.                 // no data [start time = 0] so return 0
  47.                 return 0f;
  48.             }
  49.             else {
  50.                 float eFreq;
  51.                 eFreq = (float)(ulong)oldSample.CounterFrequency;
  52.                
  53.                 if (oldSample.UnsignedRawValue >= (ulong)newSample.CounterTimeStamp || eFreq <= 0f)
  54.                     return 0f;
  55.                
  56.                 // otherwise compute difference between current time and start time
  57.                 eDifference = (float)((ulong)newSample.CounterTimeStamp - oldSample.UnsignedRawValue);
  58.                
  59.                 // convert to fractional seconds using object counter
  60.                 eSeconds = eDifference / eFreq;
  61.                
  62.                 return eSeconds;
  63.             }
  64.         }
  65.        
  66.         /// <devdoc>
  67.         /// Computes the calculated value given a raw counter sample.
  68.         /// </devdoc>
  69.         public static float ComputeCounterValue(CounterSample newSample)
  70.         {
  71.             return ComputeCounterValue(CounterSample.Empty, newSample);
  72.         }
  73.        
  74.         /// <devdoc>
  75.         /// Computes the calculated value given a raw counter sample.
  76.         /// </devdoc>
  77.         public static float ComputeCounterValue(CounterSample oldSample, CounterSample newSample)
  78.         {
  79.             int newCounterType = (int)newSample.CounterType;
  80.             if (oldSample.SystemFrequency == 0) {
  81.                 if ((newCounterType != NativeMethods.PERF_RAW_FRACTION) && (newCounterType != NativeMethods.PERF_COUNTER_RAWCOUNT) && (newCounterType != NativeMethods.PERF_COUNTER_RAWCOUNT_HEX) && (newCounterType != NativeMethods.PERF_COUNTER_LARGE_RAWCOUNT) && (newCounterType != NativeMethods.PERF_COUNTER_LARGE_RAWCOUNT_HEX) && (newCounterType != NativeMethods.PERF_COUNTER_MULTI_BASE)) {
  82.                    
  83.                     // Since oldSample has a system frequency of 0, this means the newSample is the first sample
  84.                     // on a two sample calculation. Since we can't do anything with it, return 0.
  85.                     return 0f;
  86.                 }
  87.             }
  88.             else if (oldSample.CounterType != newSample.CounterType) {
  89.                 throw new InvalidOperationException(SR.GetString(SR.MismatchedCounterTypes));
  90.             }
  91.            
  92.             if (newCounterType == NativeMethods.PERF_ELAPSED_TIME)
  93.                 return (float)GetElapsedTime(oldSample, newSample);
  94.            
  95.             NativeMethods.PDH_RAW_COUNTER newPdhValue = new NativeMethods.PDH_RAW_COUNTER();
  96.             NativeMethods.PDH_RAW_COUNTER oldPdhValue = new NativeMethods.PDH_RAW_COUNTER();
  97.            
  98.             FillInValues(oldSample, newSample, oldPdhValue, newPdhValue);
  99.            
  100.             LoadPerfCounterDll();
  101.            
  102.             NativeMethods.PDH_FMT_COUNTERVALUE pdhFormattedValue = new NativeMethods.PDH_FMT_COUNTERVALUE();
  103.             long timeBase = newSample.SystemFrequency;
  104.             int result = SafeNativeMethods.FormatFromRawValue((uint)newCounterType, NativeMethods.PDH_FMT_DOUBLE | NativeMethods.PDH_FMT_NOSCALE | NativeMethods.PDH_FMT_NOCAP100, ref timeBase, newPdhValue, oldPdhValue, pdhFormattedValue);
  105.            
  106.             if (result != NativeMethods.ERROR_SUCCESS) {
  107.                 // If the numbers go negative, just return 0. This better matches the old behavior.
  108.                 if (result == NativeMethods.PDH_CALC_NEGATIVE_VALUE || result == NativeMethods.PDH_CALC_NEGATIVE_DENOMINATOR || result == NativeMethods.PDH_NO_DATA)
  109.                     return 0;
  110.                 else
  111.                     throw new Win32Exception(result, SR.GetString(SR.PerfCounterPdhError, result.ToString("x", CultureInfo.InvariantCulture)));
  112.             }
  113.            
  114.             return (float)pdhFormattedValue.data;
  115.            
  116.         }
  117.        
  118.        
  119.         // This method figures out which values are supposed to go into which structures so that PDH can do the
  120.         // calculation for us. This was ported from Window's cutils.c
  121.         private static void FillInValues(CounterSample oldSample, CounterSample newSample, NativeMethods.PDH_RAW_COUNTER oldPdhValue, NativeMethods.PDH_RAW_COUNTER newPdhValue)
  122.         {
  123.             int newCounterType = (int)newSample.CounterType;
  124.            
  125.             switch (newCounterType) {
  126.                 case NativeMethods.PERF_COUNTER_COUNTER:
  127.                 case NativeMethods.PERF_COUNTER_QUEUELEN_TYPE:
  128.                 case NativeMethods.PERF_SAMPLE_COUNTER:
  129.                 case NativeMethods.PERF_OBJ_TIME_TIMER:
  130.                 case NativeMethods.PERF_COUNTER_OBJ_TIME_QUEUELEN_TYPE:
  131.                     newPdhValue.FirstValue = newSample.RawValue;
  132.                     newPdhValue.SecondValue = newSample.TimeStamp;
  133.                    
  134.                     oldPdhValue.FirstValue = oldSample.RawValue;
  135.                     oldPdhValue.SecondValue = oldSample.TimeStamp;
  136.                     break;
  137.                 case NativeMethods.PERF_COUNTER_100NS_QUEUELEN_TYPE:
  138.                    
  139.                     newPdhValue.FirstValue = newSample.RawValue;
  140.                     newPdhValue.SecondValue = newSample.TimeStamp100nSec;
  141.                    
  142.                     oldPdhValue.FirstValue = oldSample.RawValue;
  143.                     oldPdhValue.SecondValue = oldSample.TimeStamp100nSec;
  144.                     break;
  145.                 case NativeMethods.PERF_COUNTER_TIMER:
  146.                 case NativeMethods.PERF_COUNTER_TIMER_INV:
  147.                 case NativeMethods.PERF_COUNTER_BULK_COUNT:
  148.                 case NativeMethods.PERF_COUNTER_LARGE_QUEUELEN_TYPE:
  149.                 case NativeMethods.PERF_COUNTER_MULTI_TIMER:
  150.                 case NativeMethods.PERF_COUNTER_MULTI_TIMER_INV:
  151.                    
  152.                     newPdhValue.FirstValue = newSample.RawValue;
  153.                     newPdhValue.SecondValue = newSample.TimeStamp;
  154.                    
  155.                     oldPdhValue.FirstValue = oldSample.RawValue;
  156.                     oldPdhValue.SecondValue = oldSample.TimeStamp;
  157.                     if (newCounterType == NativeMethods.PERF_COUNTER_MULTI_TIMER || newCounterType == NativeMethods.PERF_COUNTER_MULTI_TIMER_INV) {
  158.                         // this is to make PDH work like PERFMON for
  159.                         // this counter type
  160.                         newPdhValue.FirstValue *= (uint)newSample.CounterFrequency;
  161.                         if (oldSample.CounterFrequency != 0) {
  162.                             oldPdhValue.FirstValue *= (uint)oldSample.CounterFrequency;
  163.                         }
  164.                     }
  165.                    
  166.                     if ((newCounterType & NativeMethods.PERF_MULTI_COUNTER) == NativeMethods.PERF_MULTI_COUNTER) {
  167.                         newPdhValue.MultiCount = (int)newSample.BaseValue;
  168.                         oldPdhValue.MultiCount = (int)oldSample.BaseValue;
  169.                     }
  170.                    
  171.                    
  172.                     break;
  173.                 case NativeMethods.PERF_COUNTER_RAWCOUNT:
  174.                 case NativeMethods.PERF_COUNTER_RAWCOUNT_HEX:
  175.                 case NativeMethods.PERF_COUNTER_DELTA:
  176.                 case NativeMethods.PERF_COUNTER_LARGE_RAWCOUNT:
  177.                 case NativeMethods.PERF_COUNTER_LARGE_RAWCOUNT_HEX:
  178.                 case NativeMethods.PERF_COUNTER_LARGE_DELTA:
  179.                     //
  180.                     // These counters do not use any time reference
  181.                     //
  182.                     newPdhValue.FirstValue = newSample.RawValue;
  183.                     newPdhValue.SecondValue = 0;
  184.                    
  185.                     oldPdhValue.FirstValue = oldSample.RawValue;
  186.                     oldPdhValue.SecondValue = 0;
  187.                     break;
  188.                 case NativeMethods.PERF_100NSEC_TIMER:
  189.                 case NativeMethods.PERF_100NSEC_TIMER_INV:
  190.                 case NativeMethods.PERF_100NSEC_MULTI_TIMER:
  191.                 case NativeMethods.PERF_100NSEC_MULTI_TIMER_INV:
  192.                     //
  193.                     // These counters use the 100 Ns time base in thier calculation
  194.                     //
  195.                     newPdhValue.FirstValue = newSample.RawValue;
  196.                     newPdhValue.SecondValue = newSample.TimeStamp100nSec;
  197.                    
  198.                     oldPdhValue.FirstValue = oldSample.RawValue;
  199.                     oldPdhValue.SecondValue = oldSample.TimeStamp100nSec;
  200.                     if ((newCounterType & NativeMethods.PERF_MULTI_COUNTER) == NativeMethods.PERF_MULTI_COUNTER) {
  201.                         newPdhValue.MultiCount = (int)newSample.BaseValue;
  202.                         oldPdhValue.MultiCount = (int)oldSample.BaseValue;
  203.                     }
  204.                     break;
  205.                 case NativeMethods.PERF_SAMPLE_FRACTION:
  206.                 case NativeMethods.PERF_RAW_FRACTION:
  207.                 case NativeMethods.PERF_LARGE_RAW_FRACTION:
  208.                 case NativeMethods.PERF_PRECISION_SYSTEM_TIMER:
  209.                 case NativeMethods.PERF_PRECISION_100NS_TIMER:
  210.                 case NativeMethods.PERF_PRECISION_OBJECT_TIMER:
  211.                 case NativeMethods.PERF_AVERAGE_TIMER:
  212.                 case NativeMethods.PERF_AVERAGE_BULK:
  213.                     //
  214.                     // These counters use two data points
  215.                     //
  216.                     newPdhValue.FirstValue = newSample.RawValue;
  217.                     newPdhValue.SecondValue = newSample.BaseValue;
  218.                    
  219.                     oldPdhValue.FirstValue = oldSample.RawValue;
  220.                     oldPdhValue.SecondValue = oldSample.BaseValue;
  221.                     break;
  222.                 default:
  223.                    
  224.                     // an unidentified counter was returned so
  225.                     newPdhValue.FirstValue = 0;
  226.                     newPdhValue.SecondValue = 0;
  227.                    
  228.                     oldPdhValue.FirstValue = 0;
  229.                     oldPdhValue.SecondValue = 0;
  230.                     break;
  231.             }
  232.         }
  233.        
  234.         [ResourceExposure(ResourceScope.None)]
  235.         [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
  236.         private static void LoadPerfCounterDll()
  237.         {
  238.             if (perfCounterDllLoaded)
  239.                 return;
  240.            
  241.             new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
  242.            
  243.             // load perfcounter.dll manually, since it usually isn't on the path.
  244.             IntPtr mscorwksHandle = NativeMethods.GetModuleHandle("mscorwks.dll");
  245.             if (mscorwksHandle == IntPtr.Zero)
  246.                 throw new Win32Exception();
  247.            
  248.             int size = 132;
  249.             StringBuilder filename;
  250.             using (Process currentProc = Process.GetCurrentProcess()) {
  251.                 HandleRef procHandleRef = new HandleRef(null, currentProc.Handle);
  252.                 HandleRef mscorwksHandleRef = new HandleRef(null, mscorwksHandle);
  253.                 do {
  254.                     size *= 2;
  255.                     filename = new StringBuilder(size);
  256.                     size = NativeMethods.GetModuleFileNameEx(procHandleRef, mscorwksHandleRef, filename, size);
  257.                     if (size == 0)
  258.                         throw new Win32Exception();
  259.                 }
  260.                 while (size == filename.Capacity);
  261.             }
  262.            
  263.             string installPath = Path.GetDirectoryName(filename.ToString());
  264.             string perfcounterPath = Path.Combine(installPath, "perfcounter.dll");
  265.             if (SafeNativeMethods.LoadLibrary(perfcounterPath) == IntPtr.Zero)
  266.                 throw new Win32Exception();
  267.            
  268.             perfCounterDllLoaded = true;
  269.         }
  270.     }
  271. }

Developer Fusion