0

I have been following this stack overflow article : Accurate calculation of CPU usage given in percentage in Linux?

It is written in different language so I decided to follow the logic and convert it to C#.

   public class HardwareInfoManager : IHardwareInfoManager
    {
        private IConfiguration Configuration;

        private List<long> oldCpuStatistics;

        private List<long> newCpuStatistics;


        public HardwareInfoManager(IConfiguration Configuration)
        {
            this.Configuration = Configuration;
            oldCpuStatistics = new List<long>();
            newCpuStatistics = new List<long>();
        } 

        private decimal GetCPUUsage()
        {
            string cpuUsagePath = "//proc//stat";
            StringBuilder sb = new StringBuilder();
            if (File.Exists(cpuUsagePath) && oldCpuStatistics.IsNullOrEmpty())
            {
                SaveIntsFromFilePath(cpuUsagePath, oldCpuStatistics);
                Task.Delay(200);
                GetCPUUsage();
            }
            if (File.Exists(cpuUsagePath) && !oldCpuStatistics.IsNullOrEmpty())
            {
                SaveIntsFromFilePath(cpuUsagePath, newCpuStatistics);
                var prevIdle = oldCpuStatistics[3] + oldCpuStatistics[4];
                decimal idle = newCpuStatistics[3] + newCpuStatistics[4];

                var prevNonIdle = oldCpuStatistics[0] + oldCpuStatistics[1] + oldCpuStatistics[2] + oldCpuStatistics[5] + oldCpuStatistics[6] + oldCpuStatistics[7];
                decimal nonIdle = newCpuStatistics[0] + newCpuStatistics[1] + newCpuStatistics[2] + newCpuStatistics[5] + newCpuStatistics[6] + newCpuStatistics[7];

                var prevTotal = prevIdle + prevNonIdle;
                decimal total = idle + nonIdle;

                var totalDifference = total - prevTotal;
                var idleDifference = idle - prevIdle;

                decimal cpuPercentage = (totalDifference - idleDifference / totalDifference) * 100;
                cpuPercentage = Math.Round(cpuPercentage, 2);
                return cpuPercentage;
            }
            else
            {
                return 0;
            }
        }

        private List<long> SaveIntsFromFilePath(string path, List<long> longList)
        {
            var firstLineOfCPUFile = File.ReadAllLines(path).First();
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < firstLineOfCPUFile.Length; i++)
            {
                //take first index of a number until it reaches a whitespace, add to an int array
                if (Char.IsNumber(firstLineOfCPUFile[i]))
                {
                    sb.Append(firstLineOfCPUFile[i]);
                    //start with this index until it reaches whitespace
                }
                if (Char.IsWhiteSpace(firstLineOfCPUFile[i]) && i > 5)
                {
                    longList.Add(long.Parse(sb.ToString()));
                    sb.Clear();
                    //start with this index until it reaches whitespace
                }
            }
            sb.Clear();

            return longList;
        }
}

Unable to debug this as it runs on a remote raspberry machine , it throws this error:

Job HardwareInfo.HardwareInfo threw an exception.

Quartz.SchedulerException: Job threw an unhandled exception. --->

System.DivideByZeroException: Attempted to divide by zero.

95% of the time it throws the exception because of the totaldifference being 0. In the other cases it works and throws the whole info such as this:

"TenantId":null,"Hostname":"DEV1\n","Temperature":66.218,"MemoryStats":{"MemoryTotal":"1985984 kB","MemoryFree":"1072468 kB","MemoryAvailable":"1438552 kB"},"CPUUsage":0.0

Please advise, I am stuck for 2 days on this now.

grozdeto
  • 1,201
  • 1
  • 13
  • 34

1 Answers1

0

This is how I solved it.

public class HardwareInfoManager : IHardwareInfoManager
{
    private IConfiguration Configuration;

    private List<long> oldCpuStatistics;

    private List<long> newCpuStatistics;


    public HardwareInfoManager(IConfiguration Configuration)
    {
        this.Configuration = Configuration;
        oldCpuStatistics = new List<long>();
        newCpuStatistics = new List<long>();
    }

    public HardwareInfoDto GetHardWareInfo()
    {
        return new HardwareInfoDto()
        {
            TenantId = Configuration.GetValue<string>("TenantId"),
            Hostname = GetHostName(),
            Temperature = GetTemperature(),
            MemoryStats = GetMemoryStats(),
            CPUUsage = GetCPUUsage()
        };
    }

    private string GetHostName()
    {
        string hostNameFilePath = "//etc//hostname";
        if (File.Exists(hostNameFilePath))
        {
            return (File.ReadAllText(hostNameFilePath));
        }
        else
        {
            return "";
        }

    }

    private decimal GetTemperature()
    {
        string temperatureFilePath = "//sys//class//thermal//thermal_zone0//temp";
        if (File.Exists(temperatureFilePath))
        {
            decimal output = Convert.ToDecimal(File.ReadAllText(temperatureFilePath));
            output /= 1000;
            //string temperature = output.ToString() + "°C";
            return output;
            //var file= File.ReadAllLines();
        }
        else
        {
            return 0.00M;
        }
    }

    private MemoryStatsDto GetMemoryStats()
    {
        MemoryStatsDto memoryStatsDto = new MemoryStatsDto();
        string memoryStatsPath = "//proc//meminfo";
        if (File.Exists(memoryStatsPath))
        {
            var file = File.ReadAllLines(memoryStatsPath);

            //Skipping all lines we are not interested in
            for (int i = 0; i < 3; i++)
            {
                int firstOccurenceOfDigit = 0;
                var memoryLine = file[i];
                //index of first number , start the string until the end and store it
                for (int j = 0; j < memoryLine.Length; j++)
                {
                    if (Char.IsNumber(memoryLine[j]))
                    {
                        firstOccurenceOfDigit = j;
                        break;
                    }
                }

                var memoryValue = memoryLine.Substring(firstOccurenceOfDigit);

                switch (i)
                {
                    case 0:
                        memoryStatsDto.MemoryTotal = memoryValue;
                        break;
                    case 1:
                        memoryStatsDto.MemoryFree = memoryValue;
                        break;
                    case 2:
                        memoryStatsDto.MemoryAvailable = memoryValue;
                        break;
                    default: break;
                }
            }

            return memoryStatsDto;
        }
        else
        {
            memoryStatsDto.MemoryAvailable = "";
            memoryStatsDto.MemoryFree = "";
            memoryStatsDto.MemoryTotal = "";
            return memoryStatsDto;
        }
    }

    private decimal GetCPUUsage()
    {
        string cpuUsagePath = "//proc//stat";
        StringBuilder sb = new StringBuilder();
        if (File.Exists(cpuUsagePath) && oldCpuStatistics.IsNullOrEmpty())
        {
            oldCpuStatistics = SaveIntsFromFilePath(cpuUsagePath, oldCpuStatistics);
            Thread.Sleep(10000);
            GetCPUUsage();
        }
        if (File.Exists(cpuUsagePath) && !oldCpuStatistics.IsNullOrEmpty())
        {
            newCpuStatistics = SaveIntsFromFilePath(cpuUsagePath, newCpuStatistics);
            var prevIdle = oldCpuStatistics[3] + oldCpuStatistics[4];
            decimal idle = newCpuStatistics[3] + newCpuStatistics[4];

            var prevNonIdle = oldCpuStatistics[0] + oldCpuStatistics[1] + oldCpuStatistics[2] + oldCpuStatistics[5] + oldCpuStatistics[6] + oldCpuStatistics[7];
            decimal nonIdle = newCpuStatistics[0] + newCpuStatistics[1] + newCpuStatistics[2] + newCpuStatistics[5] + newCpuStatistics[6] + newCpuStatistics[7];

            var prevTotal = prevIdle + prevNonIdle;
            decimal total = idle + nonIdle;

            var totalDifference = total - prevTotal;
            var idleDifference = idle - prevIdle;

            decimal cpuPercentage = 0;
           
            Log.Logger.Information($"TotalDifference is {totalDifference}");
            Log.Logger.Information($"IdleDifference is {idleDifference}");

            cpuPercentage = (totalDifference - idleDifference) * 100M / (totalDifference);
            cpuPercentage = Math.Round(cpuPercentage, 2);
            return cpuPercentage;
        }
        else
        {
            return 0;
        }
    }

    private List<long> SaveIntsFromFilePath(string path, List<long> longList)
    {
        var firstLineOfCPUFile = File.ReadAllLines(path).First();
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < firstLineOfCPUFile.Length; i++)
        {
            //take first index of a number until it reaches a whitespace, add to an int array
            if (Char.IsNumber(firstLineOfCPUFile[i]))
            {
                sb.Append(firstLineOfCPUFile[i]);
                //start with this index until it reaches whitespace
            }
            if (Char.IsWhiteSpace(firstLineOfCPUFile[i]) && i > 5)
            {
                longList.Add(long.Parse(sb.ToString()));
                sb.Clear();
                //start with this index until it reaches whitespace
            }
        }
        sb.Clear();

        for (int i = 0; i < longList.Count; i++)
        {
            Log.Logger.Information($"LongList index {i}  value is {longList[i]}");
        }
        return longList;
    }
}
grozdeto
  • 1,201
  • 1
  • 13
  • 34