//******************************************************************************************************
// ProcessUtilizationCalculator.cs - Gbtc
//
// Copyright © 2018, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this
// file except in compliance with the License. You may obtain a copy of the License at:
//
// http://opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 02/05/2018 - J. Ritchie Carroll
// Generated original version of source code.
//
//******************************************************************************************************
using System;
using System.Diagnostics;
using System.Timers;
namespace GSF.Diagnostics
{
///
/// Represents a utilization calculator for a .
///
public sealed class ProcessUtilizationCalculator : IDisposable
{
#region [ Members ]
// Constants
///
/// Default value for the property.
///
public const int DefaultUpdateInterval = 5000;
// Fields
private readonly Timer m_updateUtilizationTimer;
private WeakReference m_processReference;
private int m_updateInterval;
private TimeSpan m_startTime;
private TimeSpan m_lastProcessorTime;
private DateTime m_lastMonitorTime;
private bool m_disposed;
#endregion
#region [ Constructors ]
///
/// Creates a new .
///
public ProcessUtilizationCalculator()
{
m_updateInterval = DefaultUpdateInterval;
m_lastProcessorTime = new TimeSpan(0L);
m_updateUtilizationTimer = new Timer(m_updateInterval)
{
AutoReset = true,
Enabled = false
};
m_updateUtilizationTimer.Elapsed += UpdateUtilizationTimerElapsed;
}
#endregion
#region [ Properties ]
///
/// Gets the current processor utilization of the associated .
///
public double Utilization { get; private set; }
///
/// Gets or sets the interval, in milliseconds, over which will be calculated.
///
public int UpdateInterval
{
get
{
return m_updateInterval;
}
set
{
m_updateInterval = value;
if (m_updateInterval > 0)
m_updateUtilizationTimer.Interval = m_updateInterval;
}
}
///
/// Gets associated process for this .
///
///
/// The maintains a to the associated
/// so this property can be null if the process is no longer available.
///
public Process AssociatedProcess
{
get
{
Process process = null;
m_processReference?.TryGetTarget(out process);
return process;
}
}
#endregion
#region [ Methods ]
///
/// Releases all the resources used by the object.
///
public void Dispose()
{
if (m_disposed)
return;
try
{
m_updateUtilizationTimer.Stop();
m_updateUtilizationTimer.Elapsed -= UpdateUtilizationTimerElapsed;
m_updateUtilizationTimer.Dispose();
}
finally
{
m_disposed = true; // Prevent duplicate dispose.
}
}
///
/// Starts calculating the processor utilization of the specified .
///
/// The to monitor for processor utilization.
public void Initialize(Process process)
{
m_processReference = new WeakReference(process);
m_startTime = process.TotalProcessorTime;
m_lastMonitorTime = DateTime.UtcNow;
if (m_updateInterval > 0)
m_updateUtilizationTimer.Start();
}
private void UpdateUtilizationTimerElapsed(object sender, ElapsedEventArgs e)
{
try
{
Process process;
if ((object)m_processReference != null && m_processReference.TryGetTarget(out process) && !process.HasExited)
{
DateTime currentTime = DateTime.UtcNow;
TimeSpan processorTime = process.TotalProcessorTime - m_startTime;
Utilization = (processorTime - m_lastProcessorTime).TotalSeconds / (Environment.ProcessorCount * currentTime.Subtract(m_lastMonitorTime).TotalSeconds);
m_lastMonitorTime = currentTime;
m_lastProcessorTime = processorTime;
}
else
{
Utilization = 0.0D;
m_updateUtilizationTimer.Enabled = false;
}
}
catch
{
Utilization = 0.0D;
m_updateUtilizationTimer.Enabled = false;
}
}
#endregion
}
}