using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.Core; using Tango.Core.DI; using Tango.Integration.ExternalBridge; using Tango.PPC.Common.ExternalBridge; using Tango.PPC.Shared.Performance; namespace Tango.PPC.Common.Performance { [TangoCreateWhenRegistered] public class DefaultPerformanceService : ExtendedObject, IPerformanceService { #region Nested Classes public static class PerformanceInfo { [DllImport("psapi.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetPerformanceInfo([Out] out PerformanceInformation PerformanceInformation, [In] int Size); [StructLayout(LayoutKind.Sequential)] public struct PerformanceInformation { public int Size; public IntPtr CommitTotal; public IntPtr CommitLimit; public IntPtr CommitPeak; public IntPtr PhysicalTotal; public IntPtr PhysicalAvailable; public IntPtr SystemCache; public IntPtr KernelTotal; public IntPtr KernelPaged; public IntPtr KernelNonPaged; public IntPtr PageSize; public int HandlesCount; public int ProcessCount; public int ThreadCount; } public static Int64 GetPhysicalAvailableMemoryInMiB() { PerformanceInformation pi = new PerformanceInformation(); if (GetPerformanceInfo(out pi, Marshal.SizeOf(pi))) { return Convert.ToInt64((pi.PhysicalAvailable.ToInt64() * pi.PageSize.ToInt64() / 1048576)); } else { return -1; } } public static Int64 GetTotalMemoryInMiB() { PerformanceInformation pi = new PerformanceInformation(); if (GetPerformanceInfo(out pi, Marshal.SizeOf(pi))) { return Convert.ToInt64((pi.PhysicalTotal.ToInt64() * pi.PageSize.ToInt64() / 1048576)); } else { return -1; } } } #endregion private class PerformanceClient { public ExternalBridgeReceiver Receiver { get; set; } public String Token { get; set; } } private List _clients; private PerformancePackage _package; private bool _isStarted; private Thread _performanceThread; public bool Enabled { get; set; } = true; public DefaultPerformanceService(IPPCExternalBridgeService externalBridge) { _package = new PerformancePackage(); _clients = new List(); externalBridge.RegisterRequestHandler(this); } [ExternalBridgeRequestHandlerMethod(typeof(StartPerformanceUpdatesRequest), RequestHandlerLoggingMode.LogRequestNameAndContent)] public async Task OnStartPerformanceUpdatesRequest(StartPerformanceUpdatesRequest request, String token, ExternalBridgeReceiver receiver) { this.ThrowIfDisabled(); if (!_clients.Exists(x => x.Receiver == receiver)) { _clients.Add(new PerformanceClient() { Receiver = receiver, Token = token }); OnReceiversChanged(); } await receiver.SendGenericResponse(new StartPerformanceUpdatesResponse() { Package = _package }, token); } public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) { _clients.RemoveAll(x => x.Receiver == receiver); OnReceiversChanged(); } private void OnReceiversChanged() { if (_clients.Count > 0 && !_isStarted) { _isStarted = true; _performanceThread = new Thread(PerformanceThreadMethod); _performanceThread.IsBackground = true; _performanceThread.Start(); } else if (_clients.Count == 0 && _isStarted) { _isStarted = false; } } private async void PerformanceThreadMethod() { while (_isStarted) { try { _package.ApplicationCPU = (int)GetAppCPU(); _package.CPU = (int)GetTotalCPU(); _package.ApplicationRAM = (int)BytesToMegaBytes(GetAppRam()); _package.MaxRAM = (int)BytesToMegaBytes((long)new Microsoft.VisualBasic.Devices.ComputerInfo().TotalPhysicalMemory); _package.RAM = _package.MaxRAM - (int)PerformanceInfo.GetPhysicalAvailableMemoryInMiB(); DriveInfo info = new DriveInfo("C"); _package.DiskCapacity = (int)BytesToMegaBytes(info.TotalSize); _package.AvailableDiskSpace = (int)BytesToMegaBytes(info.AvailableFreeSpace); _package.DateTime = DateTime.Now; foreach (var client in _clients.ToList().Where(x => x.Receiver.State == Transport.TransportComponentState.Connected)) { try { await client.Receiver.SendGenericResponse(new StartPerformanceUpdatesResponse() { Package = _package }, client.Token); } catch (Exception ex) { LogManager.Log(ex, "Error sending performance package."); } } } catch (Exception ex) { LogManager.Log(ex, "Error creating performance package."); } Thread.Sleep(200); } } #region Helpers private float BytesToMegaBytes(long bytes) { return bytes / 1024f / 1024f; } public float GetAppCPU() { PerformanceCounter cpuCounter = new PerformanceCounter(); cpuCounter.CategoryName = "Process"; cpuCounter.CounterName = "% Processor Time"; cpuCounter.InstanceName = Process.GetCurrentProcess().ProcessName; // will always start at 0 float firstValue = cpuCounter.NextValue(); System.Threading.Thread.Sleep(1000); // now matches task manager reading float secondValue = cpuCounter.NextValue(); return secondValue / Environment.ProcessorCount; } public float GetTotalCPU() { PerformanceCounter cpuCounter = new PerformanceCounter(); cpuCounter.CategoryName = "Processor"; cpuCounter.CounterName = "% Processor Time"; cpuCounter.InstanceName = "_Total"; // will always start at 0 float firstValue = cpuCounter.NextValue(); System.Threading.Thread.Sleep(1000); // now matches task manager reading float secondValue = cpuCounter.NextValue(); return secondValue; } public long GetAppRam() { Process proc = Process.GetCurrentProcess(); return proc.PrivateMemorySize64; } #endregion } }