I would like to measure how much of system's memory is available in my C# code. I believe it is done something like this:
PerformanceCounter ramCounter = new PerformanceCounter(
"Memory"
, "Available MBytes"
, true
);
float availbleRam = ramCounter.NextValue();
The thing is Mono has no "Memmory" category. I iterated over the list of categories like this:
PerformanceCounterCategory[] cats = PerformanceCounterCategory.GetCategories();
string res = "";
foreach (PerformanceCounterCategory c in cats)
{
res += c.CategoryName + Environment.NewLine;
}
return res;
And closest category I found is "Mono Memory" which has no "Available MBytes" and keeps returning 0 on NextValue calls. Here's the complete list of categories mono returns:
Processor
Process
Mono Memory
ASP.NET
.NET CLR JIT
.NET CLR Exceptions
.NET CLR Memory
.NET CLR Remoting
.NET CLR Loading
.NET CLR LocksAndThreads
.NET CLR Interop
.NET CLR Security
Mono Threadpool
Network Interface
So does anyone know a way to measure the available memory in C# + Mono + Ubuntu?
[UPDATE]
I managed to do this in Ubuntu like this (using the external program free):
long GetFreeMemorySize()
{
Regex ram_regex = new Regex(#"[^\s]+\s+\d+\s+(\d+)$");
ProcessStartInfo ram_psi = new ProcessStartInfo("free");
ram_psi.RedirectStandardOutput = true;
ram_psi.RedirectStandardError = true;
ram_psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
ram_psi.UseShellExecute = false;
System.Diagnostics.Process free = System.Diagnostics.Process.Start(ram_psi);
using (System.IO.StreamReader myOutput = free.StandardOutput)
{
string output = myOutput.ReadToEnd();
string[] lines = output.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
lines[2] = lines[2].Trim();
Match match = ram_regex.Match(lines[2]);
if (match.Success)
{
try
{
return Convert.ToInt64(match.Groups[1].Value);
}
catch (Exception)
{
return 0L;
}
}
else
{
return 0L;
}
}
}
But the problem with this solution is that it works with Mono only if it is run within a Linux system. I would like to know if anyone can come up with a solution for Mono + Windows?
I realize this is an old question, but my answer might help someone.
You need to find out what performance categories and counters are available on your system.
foreach (var cat in PerformanceCounterCategory.GetCategories())
{
Console.WriteLine(cat.CategoryName + ":");
foreach (var co in cat.GetCounters())
{
Console.WriteLine(co.CounterName);
}
}
Then you will need to use the corresponding values for measuring the performance.
For Windows, those should be:
var memory = new PerformanceCounter("Memory", "Available MBytes");
For Linux (tested on Yogurt 0.2.3):
var memory = new PerformanceCounter("Mono Memory", "Available Physical Memory");
The values might be different depending on the operating system, but you will find the correct values by iterating the categories and the counters for each category.
Thread.Sleep(1000);
Place that after your first "NextValue" call (you can toss the very first NextValue return value) and follow it with your line:
float availbleRam = ramCounter.NextValue();
Performance counters need time to measure before they can return results.
Confirmed this works in Windows with .net 4.5, unsure about Linux with Mono.
Related
I'm using this right now: https://learn.microsoft.com/en-us/dotnet/api/system.diagnostics.process?view=net-6.0
but I cannot limit the process memory and CPU usage
public static void Launch(string[] args)
{
// make sure installPath is in double perentheses
string steamPath = config["steamPath"].ToString();
string arg = "";
foreach (string s in args){arg += $"{s} ";}
Process ExternalProcess = new Process();
ExternalProcess.StartInfo.FileName = steamPath;
ExternalProcess.StartInfo.Arguments = arg;
ExternalProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
ExternalProcess.Start();
ExternalProcess.WaitForExit();
ExternalProcess.Close();
}
If setting constraints on memory usage are crucial, you might look into github.com/lowleveldesign/process-governor. It's a commandline tool, so it should be relatively easy to be executed by your C# program. It also allows limiting of CPU usage as well, so might perhaps be a one-stop solution you might be looking for... –
MySkullCaveIsADarkPlace
I have following c# code running perfectly fine in visual studio but if want to compile it on mono it simply fails with error CmputerInfo doesn't exists are you missing assembly reference.
// Get Total Available Memory Percentage and if its below a threshhold then send ServiceUnavailable
ComputerInfo computerInfo = new ComputerInfo();
ulong totalPhysicalMemory = computerInfo.TotalPhysicalMemory;
ulong availablePhysicalMemory = computerInfo.AvailablePhysicalMemory;
ulong availablePhysicalMemoryPercentage = (availablePhysicalMemory * 100 / totalPhysicalMemory);
If the above dll doesn't supported by mono. Please tell me how to gather above information in linux.
Thanks
Use this as a replacement:
var pc = new System.Diagnostics.PerformanceCounter("Mono Memory", "Available Physical Memory");
long availableMemory = pc.RawValue;
var pc2 = new System.Diagnostics.PerformanceCounter("Mono Memory", "Total Physical Memory");
long physicalMemory = pc2.RawValue;
I am currently looking for a way to get the current CPU/RAM/Disk usage in a C# web application using .NET CORE.
For CPU and ram usage, I use PerformanceCounter Class from System.Diagnostics.
This is the codes:
PerformanceCounter cpuCounter;
PerformanceCounter ramCounter;
cpuCounter = new PerformanceCounter();
cpuCounter.CategoryName = "Processor";
cpuCounter.CounterName = "% Processor Time";
cpuCounter.InstanceName = "_Total";
ramCounter = new PerformanceCounter("Memory", "Available MBytes");
public string getCurrentCpuUsage(){
cpuCounter.NextValue()+"%";
}
public string getAvailableRAM(){
ramCounter.NextValue()+"MB";
}
For disk usage, I am using the DriveInfo class. This is the codes:
using System;
using System.IO;
class Info {
public static void Main() {
DriveInfo[] drives = DriveInfo.GetDrives();
foreach (DriveInfo drive in drives) {
//There are more attributes you can use.
//Check the MSDN link for a complete example.
Console.WriteLine(drive.Name);
if (drive.IsReady) Console.WriteLine(drive.TotalSize);
}
}
}
Unfortunately .NET Core does not support the DriveInfo and PerformanceCounter classes, hence the code above do not work.
Does anyone know how I can get the current CPU/RAM/Disk usage in a C# web application using .NET CORE?
You can use PerformnceCounter in the System.Diagnostics.PerformanceCounter package
for example, the next code will give you the total processor usage percent
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total",true);
var value = cpuCounter.NextValue();
//Note: In most cases you need to call .NextValue() twice to be able to get the real value
if (Math.Abs(value) <= 0.00)
value = cpuCounter.NextValue();
Console.WriteLine(value);
you can do the same for all OS registered Performance Counters.
Update:
I'm not sure if there is something I should do after creating a new instance of the PerformanceCounter class, but sometimes when I get the next value it comes as 0.
So I've decided to make one instance of PerformanceCounter in at the application level.
e.g.
public static class DiagnosticHelpers
{
static float _systemCPU;
public static float SystemCPU
{
get
{
lock (locker)
{
return _systemCPU;
}
}
}
private static readonly object locker = new object();
static DiagnosticHelpers()
{
SystemCPU = 0;
Task.Run(() =>
{
var cpuCounter = new PerformanceCounter("Processor", "% Processor Time", "_Total", true);
cpuCounter.NextValue(); //prime the counter
while (true)
{
Thread.Sleep(1000); /wait at least 1 second before the first real read
lock (locker)
{
_systemCPU = cpuCounter.NextValue();
}
}
});
}
}
Processor information is available via System.Diagnostics:
var proc = Process.GetCurrentProcess();
var mem = proc.WorkingSet64;
var cpu = proc.TotalProcessorTime;
Console.WriteLine("My process used working set {0:n3} K of working set and CPU {1:n} msec",
mem / 1024.0, cpu.TotalMilliseconds);
DriveInfo is available for Core by adding the System.IO.FileSystem.DriveInfo package
For Windows i'm using this
var memorieLines= GetWmicOutput("OS get FreePhysicalMemory,TotalVisibleMemorySize /Value").Split("\n");
var freeMemory= memorielines[0].Split("=", StringSplitOptions.RemoveEmptyEntries)[1];
var totalMemory = memorielines[1].Split("=", StringSplitOptions.RemoveEmptyEntries)[1];
var cpuLines = GetWmicOutput("CPU get Name,LoadPercentage /Value").Split("\n");
var CpuUse = cpuLines[0].Split("=", StringSplitOptions.RemoveEmptyEntries)[1];
var CpuName = cpuLines[1].Split("=", StringSplitOptions.RemoveEmptyEntries)[1];
private string GetWmicOutput(string query, bool redirectStandardOutput = true)
{
var info = new ProcessStartInfo("wmic");
info.Arguments = query;
info.RedirectStandardOutput = redirectStandardOutput;
var output = string.Empty;
using (var process = Process.Start(info))
{
output = process.StandardOutput.ReadToEnd();
}
return output.Trim();
}
For the disk infos you can use this query :
LOGICALDISK get Caption,DeviceID,FileSystem,FreeSpace,Size /Value
if you want a better output formatting give a look to this article : https://www.petri.com/command-line-wmi-part-3
Add this nuget package to your project by double clicking project.
<ItemGroup>
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="6.0.0" />
</ItemGroup>
When you run the code, you will get an error like below.
Performance counters cannot be initialized! System.UnauthorizedAccessException: Access to the registry key 'Global' is denied.
To solve this error, you have to add your application pool user to "Performance Monitor Users" group.
Open command line in administrator mode, then run this command.
net localgroup "Performance Monitor Users" "IIS APPPOOL\MYAPPPOOL" /add
MYAPPPOOL will be replaced with your real app pool name.
Then restart the machine if iis restart does not solve.
When is it an advantage/disadvantage to be using RDotNet for making statistical calculations as opposed to generating an R script text file and running it from the application using e.g. Process.Start? Or is there some other better way?
I need to execute a large number of commands and have a feeling that sending them one by one to R takes a lot of time.
I'd say the following two scenario's are stereotypical:
.NET code and R code are quite separate, not a lot of interaction is needed between the R code and the .NET code. For example, the .NET code gathers some information, and launches a processing script on that, after which the .NET code picks up the results. In this case spawning an R process (Process.Start) is a simple way to get this working.
A lot of interaction is needed between the .NET code and the R code, the workflow consists of going back and forth between .NET and R often. In this case, a more heavy weight, flexible solution such as RDotNet makes a lot of sense. RDotNet allows more easy integration of the .NET code and the R code, with the price being that it is often harder to learn, harder to debug, and often needs to be updated for new versions of R etc.
R.NET currently can initilize once. Parallel execution will be problematic.
Would suggest use RScript.
Our solution based on this answer on stackoverflow Call R (programming language) from .net
With monor change, we send R code from string and save it to temp file, since user run custom R code when needed.
public static void RunFromCmd(string batch, params string[] args)
{
// Not required. But our R scripts use allmost all CPU resources if run multiple instances
lock (typeof(REngineRunner))
{
string file = string.Empty;
string result = string.Empty;
try
{
// Save R code to temp file
file = TempFileHelper.CreateTmpFile();
using (var streamWriter = new StreamWriter(new FileStream(file, FileMode.Open, FileAccess.Write)))
{
streamWriter.Write(batch);
}
// Get path to R
var rCore = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\R-core") ??
Registry.CurrentUser.OpenSubKey(#"SOFTWARE\R-core");
var is64Bit = Environment.Is64BitProcess;
if (rCore != null)
{
var r = rCore.OpenSubKey(is64Bit ? "R64" : "R");
var installPath = (string)r.GetValue("InstallPath");
var binPath = Path.Combine(installPath, "bin");
binPath = Path.Combine(binPath, is64Bit ? "x64" : "i386");
binPath = Path.Combine(binPath, "Rscript");
string strCmdLine = #"/c """ + binPath + #""" " + file;
if (args.Any())
{
strCmdLine += " " + string.Join(" ", args);
}
var info = new ProcessStartInfo("cmd", strCmdLine);
info.RedirectStandardInput = false;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.CreateNoWindow = true;
using (var proc = new Process())
{
proc.StartInfo = info;
proc.Start();
result = proc.StandardOutput.ReadToEnd();
}
}
else
{
result += "R-Core not found in registry";
}
Console.WriteLine(result);
}
catch (Exception ex)
{
throw new Exception("R failed to compute. Output: " + result, ex);
}
finally
{
if (!string.IsNullOrWhiteSpace(file))
{
TempFileHelper.DeleteTmpFile(file, false);
}
}
}
}
Full blog post: http://kostylizm.blogspot.ru/2014/05/run-r-code-from-c-sharp.html
With Process.Start you will start up a new R session. This can take some time, especially if you are using different packages in your script which you need to load.
If you use R.NET, you can create an R instance, and keep on talking with it. So if you have created a webservice to connect R with ASP you don't want to start up R all the time as this will be very time costly. You need it just once and you can work with it interactively.
For a programming project I would like to access the temperature readings from my CPU and GPUs. I will be using C#. From various forums I get the impression that there is specific information and developer resources you need in order to access that information for various boards. I have a MSI NF750-G55 board. MSI's website does not have any of the information I am looking for. I tried their tech support and the rep I spoke with stated they do not have any such information. There must be a way to obtain that info.
Any thoughts?
For at least the CPU side of things, you could use WMI.
The namespace\object is root\WMI, MSAcpi_ThermalZoneTemperature
Sample Code:
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\WMI",
"SELECT * FROM MSAcpi_ThermalZoneTemperature");
ManagementObjectCollection collection =
searcher.Get();
foreach(ManagementBaseObject tempObject in collection)
{
Console.WriteLine(tempObject["CurrentTemperature"].ToString());
}
That will give you the temperature in a raw format. You have to convert from there:
kelvin = raw / 10;
celsius = (raw / 10) - 273.15;
fahrenheit = ((raw / 10) - 273.15) * 9 / 5 + 32;
The best way to go for hardware related coding on windows is by using WMI which is a Code Creator tool from Microsoft, the tool will create the code for you based on what you are looking for in hardware related data and what .Net language you want to use.
The supported langauges currently are: C#, Visual Basic, VB Script.
Note that MSAcpi_ThermalZoneTemperature does not give you the temperature of the CPU but rather the temperature of the motherboard. Also, note that most motherboards do not implement this via WMI.
You can give the Open Hardware Monitor a go, although it lacks support for the latest processors.
internal sealed class CpuTemperatureReader : IDisposable
{
private readonly Computer _computer;
public CpuTemperatureReader()
{
_computer = new Computer { CPUEnabled = true };
_computer.Open();
}
public IReadOnlyDictionary<string, float> GetTemperaturesInCelsius()
{
var coreAndTemperature = new Dictionary<string, float>();
foreach (var hardware in _computer.Hardware)
{
hardware.Update(); //use hardware.Name to get CPU model
foreach (var sensor in hardware.Sensors)
{
if (sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue)
coreAndTemperature.Add(sensor.Name, sensor.Value.Value);
}
}
return coreAndTemperature;
}
public void Dispose()
{
try
{
_computer.Close();
}
catch (Exception)
{
//ignore closing errors
}
}
}
Download the zip from the official source, extract and add a reference to OpenHardwareMonitorLib.dll in your project.