/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.IO; using System.Threading; using System.Reflection; using QuantConnect.Util; using System.Diagnostics; using System.Collections.Generic; using static QuantConnect.StringExtensions; namespace QuantConnect { /// /// Operating systems class for managing anything that is operation system specific. /// /// Good design should remove the need for this function. Over time it should disappear. public static class OS { /// /// CPU performance counter measures percentage of CPU used in a background thread. /// private static CpuPerformance CpuPerformanceCounter; /// /// Global Flag :: Operating System /// public static bool IsLinux { get { var p = (int)Environment.OSVersion.Platform; return (p == 4) || (p == 6) || (p == 128); } } /// /// Global Flag :: Operating System /// public static bool IsWindows => !IsLinux; /// /// Character Separating directories in this OS: /// public static string PathSeparation => Path.DirectorySeparatorChar.ToStringInvariant(); /// /// Get the drive space remaining on windows and linux in MB /// public static long DriveSpaceRemaining { get { var d = GetDrive(); return d.AvailableFreeSpace / (1024 * 1024); } } /// /// Get the drive space remaining on windows and linux in MB /// public static long DriveSpaceUsed { get { var d = GetDrive(); return (d.TotalSize - d.AvailableFreeSpace) / (1024 * 1024); } } /// /// Total space on the drive /// public static long DriveTotalSpace { get { var d = GetDrive(); return d.TotalSize / (1024 * 1024); } } /// /// Get the drive. /// /// private static DriveInfo GetDrive() { var assembly = Assembly.GetExecutingAssembly(); var drive = Path.GetPathRoot(assembly.Location); return new DriveInfo(drive); } /// /// Gets the amount of private memory allocated for the current process (includes both managed and unmanaged memory). /// public static long ApplicationMemoryUsed { get { var proc = Process.GetCurrentProcess(); return proc.PrivateMemorySize64 / (1024 * 1024); } } /// /// Get the RAM used on the machine: /// public static long TotalPhysicalMemoryUsed => GC.GetTotalMemory(false) / (1024 * 1024); /// /// Total CPU usage as a percentage /// public static decimal CpuUsage { get { if(CpuPerformanceCounter != null) { return (decimal)CpuPerformanceCounter.CpuPercentage; } return 0m; } } /// /// Gets the statistics of the machine, including CPU% and RAM /// public static Dictionary GetServerStatistics() { return new Dictionary { { Messages.OS.CPUUsageKey, Invariant($"{CpuUsage:0.0}%")}, { Messages.OS.UsedRAMKey, TotalPhysicalMemoryUsed.ToStringInvariant() }, { Messages.OS.TotalRAMKey, "" }, { Messages.OS.HostnameKey, Environment.MachineName }, { Messages.OS.LEANVersionKey, $"v{Globals.Version}"} }; } /// /// Initializes the OS internal resources /// public static void Initialize() { CpuPerformanceCounter = new CpuPerformance(); } /// /// Disposes of the OS internal resources /// public static void Dispose() { CpuPerformanceCounter.DisposeSafely(); } /// /// Calculates the CPU usage in a background thread /// private class CpuPerformance : IDisposable { private readonly CancellationTokenSource _cancellationToken; private readonly Thread _cpuThread; /// /// CPU usage as a percentage (0-100) /// /// Float to avoid any atomicity issues public float CpuPercentage { get; private set; } /// /// Initializes an instance of the class and starts a new thread. /// public CpuPerformance() { _cancellationToken = new CancellationTokenSource(); _cpuThread = new Thread(CalculateCpu) { IsBackground = true, Name = "CpuPerformance" }; _cpuThread.Start(); } /// /// Event loop that calculates the CPU percentage the process is using /// private void CalculateCpu() { var process = Process.GetCurrentProcess(); while (!_cancellationToken.IsCancellationRequested) { var startTime = DateTime.UtcNow; var startCpuUsage = process.TotalProcessorTime; if (_cancellationToken.Token.WaitHandle.WaitOne(startTime.GetSecondUnevenWait(5000))) { return; } var endTime = DateTime.UtcNow; var endCpuUsage = process.TotalProcessorTime; var cpuUsedMs = (endCpuUsage - startCpuUsage).TotalMilliseconds; var totalMsPassed = (endTime - startTime).TotalMilliseconds; var cpuUsageTotal = cpuUsedMs / totalMsPassed; CpuPercentage = (float)cpuUsageTotal * 100; } } /// /// Stops the execution of the task /// public void Dispose() { _cpuThread.StopSafely(TimeSpan.FromSeconds(5), _cancellationToken); _cancellationToken.DisposeSafely(); } } } }