diff --git a/Hardware/Nic/Nic.cs b/Hardware/Nic/Nic.cs
index 0927620..1aa95e7 100644
--- a/Hardware/Nic/Nic.cs
+++ b/Hardware/Nic/Nic.cs
@@ -9,6 +9,7 @@
*/
using System;
+using System.Diagnostics;
using System.Globalization;
using System.Net.NetworkInformation;
@@ -21,14 +22,14 @@ namespace OpenHardwareMonitor.Hardware.Nic
private Sensor uploadSpeed;
private Sensor downloadSpeed;
private Sensor networkUtilization;
- private DateTime latesTime;
+ private long lastTick;
private long bytesUploaded;
private long bytesDownloaded;
private readonly NetworkInterface networkInterface;
- public Nic(NetworkInterface networkInterface, ISettings settings, int index)
- : base(networkInterface.Name, new Identifier("NIC",index.ToString(CultureInfo.InvariantCulture)), settings)
+ public Nic(NetworkInterface networkInterface, ISettings settings)
+ : base(networkInterface.Name, new Identifier("nic", networkInterface.Id), settings)
{
this.networkInterface = networkInterface;
dataUploaded = new Sensor("Data Uploaded", 2, SensorType.Data, this, settings);
@@ -43,7 +44,7 @@ namespace OpenHardwareMonitor.Hardware.Nic
ActivateSensor(networkUtilization);
bytesUploaded = NetworkInterface.GetIPStatistics().BytesSent;
bytesDownloaded = NetworkInterface.GetIPStatistics().BytesReceived;
- latesTime = DateTime.Now;
+ lastTick = Stopwatch.GetTimestamp();
}
public override HardwareType HardwareType
@@ -64,37 +65,49 @@ namespace OpenHardwareMonitor.Hardware.Nic
public override void Update()
{
- DateTime newTime = DateTime.Now;
- float dt = (float)(newTime - latesTime).TotalSeconds;
- latesTime = newTime;
- IPv4InterfaceStatistics interfaceStats = NetworkInterface.GetIPv4Statistics();
+ long newTick = Stopwatch.GetTimestamp();
+ double dt = new TimeSpan(newTick - lastTick).TotalSeconds;
+
+ IPv4InterfaceStatistics interfaceStats = NetworkInterface.GetIPv4Statistics();
+
+ // Report out the number of GB (2^30 Bytes) that this interface has up/downloaded. Note
+ // that these values can reset back at zero (eg: after waking from sleep).
+ dataUploaded.Value = (float)(interfaceStats.BytesSent / (double)0x40000000);
+ dataDownloaded.Value = (float)(interfaceStats.BytesReceived / (double)0x40000000);
+
+ // Detect a reset in interface stats if the new total is less than what was previously
+ // seen. While setting the previous values to zero doesn't encapsulate the value the
+ // instant before the reset, it is the best approximation we have.
+ if (interfaceStats.BytesSent < bytesUploaded || interfaceStats.BytesReceived < bytesDownloaded)
+ {
+ bytesUploaded = 0;
+ bytesDownloaded = 0;
+ }
+
long dBytesUploaded = interfaceStats.BytesSent - bytesUploaded;
long dBytesDownloaded = interfaceStats.BytesReceived - bytesDownloaded;
- uploadSpeed.Value = (float)dBytesUploaded / dt;
- downloadSpeed.Value = (float)dBytesDownloaded / dt;
- networkUtilization.Value = Clamp((float)Math.Max(dBytesUploaded, dBytesDownloaded) * 800 / NetworkInterface.Speed / dt, 0, 100);
+
+ // Upload and download speeds are reported as the number of bytes transfered over the
+ // time difference since the last report. In this way, the values represent the average
+ // number of bytes up/downloaded in a second.
+ uploadSpeed.Value = (float)(dBytesUploaded / dt);
+ downloadSpeed.Value = (float)(dBytesDownloaded / dt);
+
+ // Network speed is in bits per second, so when calculating the load on the NIC we first
+ // grab the total number of bits up/downloaded
+ long dbits = (dBytesUploaded + dBytesDownloaded) * 8;
+
+ // Converts the ratio of total bits transferred over time over theoretical max bits
+ // transfer rate into a percentage load
+ double load = (dbits / dt / NetworkInterface.Speed) * 100;
+
+ // Finally clamp the value between 0% and 100% to avoid reporting nonsensical numbers
+ networkUtilization.Value = (float)Math.Min(Math.Max(load, 0), 100);
+
+ // Store the recorded values and time, so they can be used in the next update
bytesUploaded = interfaceStats.BytesSent;
bytesDownloaded = interfaceStats.BytesReceived;
- dataUploaded.Value = ((float)bytesUploaded / 1073741824);
- dataDownloaded.Value = ((float)bytesDownloaded / 1073741824);
- }
-
- ///
- /// Clamps the specified value.
- ///
- /// The value.
- /// The minimum.
- /// The maximum.
- /// .
- private static float Clamp(float value, float min, float max)
- {
- if (value < min)
- return min;
-
- if (value > max)
- return max;
-
- return value;
+ lastTick = newTick;
}
}
}
diff --git a/Hardware/Nic/NicGroup.cs b/Hardware/Nic/NicGroup.cs
index 77e3c4c..3c16824 100644
--- a/Hardware/Nic/NicGroup.cs
+++ b/Hardware/Nic/NicGroup.cs
@@ -9,6 +9,8 @@ namespace OpenHardwareMonitor.Hardware.Nic
{
private readonly ISettings _settings;
private List _hardware = new List();
+ private readonly object _scanLock = new object();
+ private readonly Dictionary _nics = new Dictionary();
public NicGroup(ISettings settings)
{
@@ -20,10 +22,38 @@ namespace OpenHardwareMonitor.Hardware.Nic
private void ScanNics(ISettings settings)
{
- NetworkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
- _hardware = NetworkInterfaces.Where(DesiredNetworkType)
- .Select((x, i) => new Nic(x, settings, i))
- .ToList();
+ // If no network is marked up (excluding loopback and tunnel) then don't scan
+ // for interfaces.
+ if (!NetworkInterface.GetIsNetworkAvailable())
+ {
+ return;
+ }
+
+ // When multiple events fire concurrently, we don't want threads interferring
+ // with others as they manipulate non-thread safe state.
+ lock (_scanLock)
+ {
+ var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces()
+ .Where(DesiredNetworkType)
+ .OrderBy(x => x.Name);
+
+ var scanned = networkInterfaces.ToDictionary(x => x.Id, x => x);
+ var newNics = scanned.Where(x => !_nics.ContainsKey(x.Key));
+ var removedNics = _nics.Where(x => !scanned.ContainsKey(x.Key)).ToList();
+
+ foreach (var nic in removedNics)
+ {
+ nic.Value.Close();
+ _nics.Remove(nic.Key);
+ }
+
+ foreach (var nic in newNics)
+ {
+ _nics.Add(nic.Key, new Nic(nic.Value, settings));
+ }
+
+ _hardware = _nics.Values.OrderBy(x => x.Name).ToList();
+ }
}
private void NetworkChange_NetworkAddressChanged(object sender, System.EventArgs e)
@@ -46,9 +76,6 @@ namespace OpenHardwareMonitor.Hardware.Nic
public string GetReport()
{
- if (NetworkInterfaces == null)
- return null;
-
var report = new StringBuilder();
foreach (Nic hw in _hardware)
@@ -75,8 +102,6 @@ namespace OpenHardwareMonitor.Hardware.Nic
}
}
- public NetworkInterface[] NetworkInterfaces { get; set; }
-
public void Close()
{
NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged;