using Esiur.Core; using Esiur.Data; using Esiur.Resource; using Mono.Unix.Native; using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Management; using System.Net.NetworkInformation; using System.Net.Sockets; using System.Text; using System.Timers; namespace AZ.Compute.Agent { [Resource] public partial class Node { System.Timers.Timer timer; PerformanceCounter cpuCounter; PerformanceCounter ramCounter; NetworkInterface nic; ulong totalNetworkBytes; const double nicSpeed = 1 * 1024 * 1024; // 1 MBps // linux float prevCpuIdle = 0f; float prevCpuTotal = 0f; [Export] string id; [Export] string ip; [Export] float cpu; [Export] float ram; [Export] float network; [Export] uint tasks; [Export] uint cpuClock; [Export] uint cpuMaxClock; [Export] float networkSpeed; [Export] Job[] jobs = new Job[0]; [Export] public async AsyncReply Compute(string fileName, string arguments) { var psi = new ProcessStartInfo() { FileName = fileName, Arguments = arguments }; var p = Process.Start(psi); var job = await Warehouse.New(fileName, null, this); job.Process = p; Jobs = jobs.Append(job).ToArray(); return job; } ulong GetNetworkLinux() { var netLines = File .ReadAllLines("/proc/net/dev") .Skip(3) .First() .Split(' ', StringSplitOptions.RemoveEmptyEntries) .Skip(1) .Select(ulong.Parse) .ToArray(); return netLines[0] + netLines[8]; } float GetLinuxCPU(float interval = 5) { var cpuLine = File .ReadAllLines("/proc/stat") .First() .Split(' ', StringSplitOptions.RemoveEmptyEntries) .Skip(1) .Select(float.Parse) .ToArray(); var idle = cpuLine[3]; var total = cpuLine.Sum(); var percent = 100.0 * (1.0 - (idle - prevCpuIdle) / (total - prevCpuTotal)); //Console.WriteLine($"CPU {percent:0.00}%"); prevCpuIdle = idle; prevCpuTotal = total; return (float)percent / interval; } float GetLinuxRAM() { return File .ReadAllLines("/proc/meminfo") .Skip(1) .First() .Split(' ', StringSplitOptions.RemoveEmptyEntries) .Skip(1) .Select(ulong.Parse) .First() / 1024; //Console.WriteLine("Free " + freeMem); var pages = Syscall.sysconf(SysconfName._SC_PHYS_PAGES); var pageSize = Syscall.sysconf(SysconfName._SC_PAGESIZE); var ram = pages * pageSize / 1024.0f; Console.WriteLine($"RAM {ram:0.00}%"); return ram; } public Node() { Id = System.Environment.MachineName; nic = NetworkInterface.GetAllNetworkInterfaces().Where(x => x.OperationalStatus == OperationalStatus.Up).First(); networkSpeed = (float)(nic.Speed / 1048576.0); totalNetworkBytes = (ulong)nic.GetIPv4Statistics().BytesReceived + (ulong)nic.GetIPv4Statistics().BytesSent; Ip = nic.GetIPProperties().UnicastAddresses.First(x => x.Address.AddressFamily == AddressFamily.InterNetwork).Address.ToString(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { using (ManagementObject Mo = new ManagementObject("Win32_Processor.DeviceID='CPU0'")) { cpuClock = (uint)(Mo["CurrentClockSpeed"]); cpuMaxClock = (uint)(Mo["MaxClockSpeed"]); } cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total"); ramCounter = new PerformanceCounter("Memory", "Available MBytes"); } timer = new System.Timers.Timer(); timer.Elapsed += Timer_Elapsed; timer.Interval = 5000; timer.Start(); } private void Timer_Elapsed(object? sender, ElapsedEventArgs e) { try { ulong ntb = 0; if (Environment.OSVersion.Platform == PlatformID.Win32NT) { ntb = (ulong)nic.GetIPv4Statistics().BytesReceived + (ulong)nic.GetIPv4Statistics().BytesSent; Cpu = cpuCounter.NextValue(); Ram = ramCounter.NextValue(); } else { ntb = GetNetworkLinux(); Cpu = GetLinuxCPU(); Ram = GetLinuxRAM(); } Network = (float)(((ntb - totalNetworkBytes) / 5.0) / nicSpeed); totalNetworkBytes = ntb; //Console.WriteLine("Net " + Network + " " + ntb); foreach (Job job in jobs) { if (!job.Finished) { job.Start = job.Start; job.Ram = (float)(job.Process.PeakWorkingSet64 / 1048576.0); } } } catch (Exception ex) { Console.WriteLine(ex.ToString()); } } } }