зеркало из https://github.com/microsoft/Tx.git
Performance counters real time probe
This commit is contained in:
Родитель
e0627df659
Коммит
107d7f1fa2
|
@ -0,0 +1,92 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Tx.Windows
|
||||
{
|
||||
public abstract class PerfCounterReader : IDisposable
|
||||
{
|
||||
internal readonly List<PerfCounterInfo> _counters = new List<PerfCounterInfo>();
|
||||
internal readonly IObserver<PerformanceSample> _observer;
|
||||
internal PdhQueryHandle _query;
|
||||
|
||||
public PerfCounterReader(IObserver<PerformanceSample> observer)
|
||||
{
|
||||
_observer = observer;
|
||||
}
|
||||
|
||||
internal void ProduceCounterSamples(PerfCounterInfo counterInfo, DateTime timestamp)
|
||||
{
|
||||
uint bufferSize = 0;
|
||||
uint bufferCount;
|
||||
|
||||
PdhStatus status = PdhNativeMethods.PdhGetFormattedCounterArray(
|
||||
counterInfo.Handle,
|
||||
PdhFormat.PDH_FMT_DOUBLE,
|
||||
ref bufferSize,
|
||||
out bufferCount,
|
||||
IntPtr.Zero);
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_MORE_DATA);
|
||||
|
||||
var buffer = new byte[bufferSize];
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* pb = buffer)
|
||||
{
|
||||
status = PdhNativeMethods.PdhGetFormattedCounterArray(
|
||||
counterInfo.Handle,
|
||||
PdhFormat.PDH_FMT_DOUBLE,
|
||||
ref bufferSize,
|
||||
out bufferCount,
|
||||
(IntPtr) pb);
|
||||
if (status == PdhStatus.PDH_INVALID_DATA
|
||||
|| status == PdhStatus.PDH_CALC_NEGATIVE_VALUE
|
||||
|| status == PdhStatus.PDH_CALC_NEGATIVE_DENOMINATOR
|
||||
|| status == PdhStatus.PDH_CALC_NEGATIVE_TIMEBASE)
|
||||
{
|
||||
var sample = new PerformanceSample(counterInfo, counterInfo.Instance, timestamp, double.NaN);
|
||||
_observer.OnNext(sample);
|
||||
return;
|
||||
}
|
||||
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_CSTATUS_VALID_DATA);
|
||||
|
||||
var items = (PDH_FMT_COUNTERVALUE_ITEM*) pb;
|
||||
for (int i = 0; i < bufferCount; i++)
|
||||
{
|
||||
PDH_FMT_COUNTERVALUE_ITEM* item = items + i;
|
||||
var instanceName = new string((char*)item->szName);
|
||||
var sample = new PerformanceSample(counterInfo, instanceName, timestamp, item->FmtValue.doubleValue);
|
||||
|
||||
_observer.OnNext(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void AddCounter(string counterPath)
|
||||
{
|
||||
PdhCounterHandle counter;
|
||||
PdhStatus status = PdhNativeMethods.PdhAddCounter(_query, counterPath, IntPtr.Zero, out counter);
|
||||
if (status == PdhStatus.PDH_ENTRY_NOT_IN_LOG_FILE)
|
||||
return;
|
||||
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_CSTATUS_VALID_DATA);
|
||||
|
||||
var counterInfo = new PerfCounterInfo(counterPath, counter);
|
||||
_counters.Add(counterInfo);
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
foreach (PerfCounterInfo counterInfo in _counters)
|
||||
{
|
||||
counterInfo.Dispose();
|
||||
}
|
||||
|
||||
_query.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,14 @@ namespace Tx.Windows
|
|||
typeof (PerfCounterTypeMap));
|
||||
}
|
||||
|
||||
public static void AddPerfCounterProbe(this IPlaybackConfiguration playback, TimeSpan samplingRate, params string[] counterPaths)
|
||||
{
|
||||
playback.AddInput(
|
||||
() => PerfCounterObservable.FromRealTime(samplingRate, counterPaths),
|
||||
typeof(PerfCounterPartitionTypeMap),
|
||||
typeof(PerfCounterTypeMap));
|
||||
}
|
||||
|
||||
public static IObservable<PerformanceSample> GetPerformanceCounter(this IPlaybackConfiguration playback,
|
||||
string counterPath)
|
||||
{
|
||||
|
|
|
@ -1,22 +1,18 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Tx.Windows
|
||||
{
|
||||
public sealed class PerfCounterFileReader : IDisposable
|
||||
public sealed class PerfCounterFileReader : PerfCounterReader
|
||||
{
|
||||
private readonly bool _binaryLog;
|
||||
private readonly List<PerfCounterInfo> _counters = new List<PerfCounterInfo>();
|
||||
private readonly IObserver<PerformanceSample> _observer;
|
||||
private readonly PdhQueryHandle _query;
|
||||
private bool _firstMove = true;
|
||||
|
||||
public PerfCounterFileReader(IObserver<PerformanceSample> observer, string file)
|
||||
: base(observer)
|
||||
{
|
||||
_observer = observer;
|
||||
string extension = Path.GetExtension(file);
|
||||
if (extension != null) _binaryLog = extension.ToLowerInvariant() == ".blg";
|
||||
|
||||
|
@ -33,16 +29,6 @@ namespace Tx.Windows
|
|||
Read();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (PerfCounterInfo counterInfo in _counters)
|
||||
{
|
||||
counterInfo.Dispose();
|
||||
}
|
||||
|
||||
_query.Dispose();
|
||||
}
|
||||
|
||||
public void Read()
|
||||
{
|
||||
try
|
||||
|
@ -85,67 +71,6 @@ namespace Tx.Windows
|
|||
}
|
||||
}
|
||||
|
||||
private void ProduceCounterSamples(PerfCounterInfo counterInfo, DateTime timestamp)
|
||||
{
|
||||
uint bufferSize = 0;
|
||||
uint bufferCount;
|
||||
|
||||
PdhStatus status = PdhNativeMethods.PdhGetFormattedCounterArray(
|
||||
counterInfo.Handle,
|
||||
PdhFormat.PDH_FMT_DOUBLE,
|
||||
ref bufferSize,
|
||||
out bufferCount,
|
||||
IntPtr.Zero);
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_MORE_DATA);
|
||||
|
||||
var buffer = new byte[bufferSize];
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* pb = buffer)
|
||||
{
|
||||
status = PdhNativeMethods.PdhGetFormattedCounterArray(
|
||||
counterInfo.Handle,
|
||||
PdhFormat.PDH_FMT_DOUBLE,
|
||||
ref bufferSize,
|
||||
out bufferCount,
|
||||
(IntPtr) pb);
|
||||
if (status == PdhStatus.PDH_INVALID_DATA
|
||||
|| status == PdhStatus.PDH_CALC_NEGATIVE_VALUE
|
||||
|| status == PdhStatus.PDH_CALC_NEGATIVE_DENOMINATOR
|
||||
|| status == PdhStatus.PDH_CALC_NEGATIVE_TIMEBASE)
|
||||
{
|
||||
var sample = new PerformanceSample(counterInfo, timestamp, double.NaN);
|
||||
_observer.OnNext(sample);
|
||||
return;
|
||||
}
|
||||
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_CSTATUS_VALID_DATA);
|
||||
|
||||
var items = (PDH_FMT_COUNTERVALUE_ITEM*) pb;
|
||||
for (int i = 0; i < bufferCount; i++)
|
||||
{
|
||||
PDH_FMT_COUNTERVALUE_ITEM* item = items + i;
|
||||
var sample = new PerformanceSample(counterInfo, timestamp, item->FmtValue.doubleValue);
|
||||
|
||||
_observer.OnNext(sample);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AddCounter(string counterPath)
|
||||
{
|
||||
PdhCounterHandle counter;
|
||||
PdhStatus status = PdhNativeMethods.PdhAddCounter(_query, counterPath, IntPtr.Zero, out counter);
|
||||
if (status == PdhStatus.PDH_ENTRY_NOT_IN_LOG_FILE)
|
||||
return;
|
||||
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_CSTATUS_VALID_DATA);
|
||||
|
||||
var counterInfo = new PerfCounterInfo(counterPath, counter);
|
||||
_counters.Add(counterInfo);
|
||||
}
|
||||
|
||||
~PerfCounterFileReader()
|
||||
{
|
||||
Dispose();
|
||||
|
|
|
@ -11,5 +11,10 @@ namespace Tx.Windows
|
|||
{
|
||||
return Observable.Create<PerformanceSample>(o => new PerfCounterFileReader(o, perfTrace));
|
||||
}
|
||||
|
||||
public static IObservable<PerformanceSample> FromRealTime(TimeSpan samplingRate, params string[] counterPaths)
|
||||
{
|
||||
return Observable.Create<PerformanceSample>(o => new PerfCounterRealTimeProbe(o, samplingRate, counterPaths));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Tx.Windows
|
||||
{
|
||||
public sealed class PerfCounterRealTimeProbe : PerfCounterReader
|
||||
{
|
||||
private bool _firstMove = true;
|
||||
private readonly Timer _timer;
|
||||
|
||||
public PerfCounterRealTimeProbe(IObserver<PerformanceSample> observer, TimeSpan samplingRate, params string[] counterPaths)
|
||||
: base(observer)
|
||||
{
|
||||
PdhStatus status = PdhNativeMethods.PdhOpenQuery(null, IntPtr.Zero, out _query);
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_CSTATUS_VALID_DATA);
|
||||
|
||||
foreach (string counter in counterPaths)
|
||||
{
|
||||
AddCounter(counter);
|
||||
}
|
||||
|
||||
_timer = new Timer(OnTimer, null, TimeSpan.Zero, samplingRate);
|
||||
}
|
||||
|
||||
public void OnTimer(object state)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_firstMove)
|
||||
{
|
||||
// some counters need two samples to calculate their value
|
||||
// so skip a sample to make sure there are no further complications
|
||||
PdhNativeMethods.PdhCollectQueryData(_query);
|
||||
_firstMove = false;
|
||||
return;
|
||||
}
|
||||
|
||||
long time;
|
||||
PdhStatus status = PdhNativeMethods.PdhCollectQueryDataWithTime(_query, out time);
|
||||
PdhUtils.CheckStatus(status, PdhStatus.PDH_CSTATUS_VALID_DATA);
|
||||
DateTime timestamp = DateTime.FromFileTimeUtc(time);
|
||||
|
||||
foreach (PerfCounterInfo counterInfo in _counters)
|
||||
{
|
||||
ProduceCounterSamples(counterInfo, timestamp);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_observer.OnError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
_timer.Dispose();
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
~PerfCounterRealTimeProbe()
|
||||
{
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,12 +7,14 @@ namespace Tx.Windows
|
|||
public class PerformanceSample
|
||||
{
|
||||
private readonly PerfCounterInfo _counterInfo;
|
||||
private readonly string _instanceName;
|
||||
private readonly DateTime _timestamp;
|
||||
private readonly double _value;
|
||||
|
||||
internal PerformanceSample(PerfCounterInfo counterInfo, DateTime timestamp, double value)
|
||||
internal PerformanceSample(PerfCounterInfo counterInfo, string instanceName, DateTime timestamp, double value)
|
||||
{
|
||||
_counterInfo = counterInfo;
|
||||
_instanceName = instanceName;
|
||||
_timestamp = timestamp;
|
||||
_value = value;
|
||||
}
|
||||
|
@ -20,6 +22,7 @@ namespace Tx.Windows
|
|||
public PerformanceSample(PerformanceSample other)
|
||||
{
|
||||
_counterInfo = other._counterInfo;
|
||||
_instanceName = other._instanceName;
|
||||
_timestamp = other._timestamp;
|
||||
_value = other._value;
|
||||
}
|
||||
|
@ -36,7 +39,7 @@ namespace Tx.Windows
|
|||
|
||||
public string Instance
|
||||
{
|
||||
get { return _counterInfo.Instance; }
|
||||
get { return _instanceName; }
|
||||
}
|
||||
|
||||
public string Machine
|
||||
|
|
|
@ -75,6 +75,8 @@
|
|||
<Compile Include="EtwNative\EtwNativeMethods.cs" />
|
||||
<Compile Include="EtwNative\EtwObservable.cs" />
|
||||
<Compile Include="InternalsVisibleTo.cs" />
|
||||
<Compile Include="PerfCounters\PerfCounteReader.cs" />
|
||||
<Compile Include="PerfCounters\PerfCounterRealTimeProbe.cs" />
|
||||
<Compile Include="PerfCounters\PerfCounterInfo.cs" />
|
||||
<Compile Include="PerfCounters\PdhNativeMethods.cs" />
|
||||
<Compile Include="PerfCounters\PerfCounterExtensions.cs" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче