PerformanceMonitor.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. using Microsoft.Extensions.Logging;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading;
  8. namespace LiteFccCoreMain
  9. {
  10. public class PerformanceMonitor
  11. {
  12. //static System.Timers.Timer performanceLoggingTimer;
  13. public static ILogger Logger { get; set; }// = NLog.LogManager.LoadConfiguration("nlog.config").GetLogger("Performance");
  14. /// <summary>
  15. /// by seconds, default to 60, may get changed by different log level.
  16. /// </summary>
  17. static int samplingInterval = 60;
  18. private static TimeSpan? previousTotalCpuTime;
  19. private static void Linux_LoggingPerformanceCounter()
  20. {
  21. // list extra info only for RPi3B+
  22. //logger.Info(Bash("/opt/vc/bin/vcgencmd measure_temp"));
  23. //logger.Info(Bash("/opt/vc/bin/vcgencmd measure_clock arm"));
  24. //logger.Info(Bash("/opt/vc/bin/vcgencmd measure_volts core"));
  25. // list all processes in RPi3B+
  26. //logger.Info(Bash("/usr/bin/top -n 1"));
  27. double cpuUsage = 0;
  28. var proc = Process.GetCurrentProcess();
  29. if (previousTotalCpuTime.HasValue)
  30. {
  31. cpuUsage = proc.TotalProcessorTime
  32. .Subtract(previousTotalCpuTime.Value).TotalSeconds / samplingInterval;
  33. }
  34. previousTotalCpuTime = proc.TotalProcessorTime;
  35. var workingSet = proc.WorkingSet64;
  36. var npSystemMem = proc.NonpagedSystemMemorySize64;
  37. var pagedMem = proc.PagedMemorySize64;
  38. var pagedSysMem = proc.PagedSystemMemorySize64;
  39. var privateMem = proc.PrivateMemorySize64;
  40. var virMem = proc.VirtualMemorySize64;
  41. var cpu = proc.TotalProcessorTime;
  42. Logger.LogInformation("Proc: " + proc.ProcessName + "(Id: " + proc.Id + "), "
  43. + "CPU%: " + cpuUsage.ToString("0.##%")
  44. + ", workingSet: " + (workingSet / 1024.0) + "K, "
  45. + "nonPagedSysMem: " + (npSystemMem / 1024.0) + "K, "
  46. + "pagedMem: " + (pagedMem / 1024.0) + "K, "
  47. + "pagedSysMem: " + (pagedSysMem / 1024.0) + "K, "
  48. + "privateMem: " + (privateMem / 1024.0) + "K, "
  49. + "virMem: " + (virMem / 1024.0) + "K, "
  50. + "CPU total time(ms): " + cpu.TotalMilliseconds
  51. + ", handle: " + proc.HandleCount + ", thread: " + proc.Threads.Count);
  52. }
  53. private static void Windows_LoggingPerformanceCounter()
  54. {
  55. double cpuUsage = 0;
  56. var proc = Process.GetCurrentProcess();
  57. if (previousTotalCpuTime.HasValue)
  58. {
  59. cpuUsage = proc.TotalProcessorTime
  60. .Subtract(previousTotalCpuTime.Value).TotalSeconds / samplingInterval;
  61. }
  62. previousTotalCpuTime = proc.TotalProcessorTime;
  63. int availableThreads, availableIOThreads;
  64. ThreadPool.GetAvailableThreads(out availableThreads, out availableIOThreads);
  65. var currentProcessRunningInfo = Windows_GetProcessRunningInformation(proc.ProcessName);
  66. currentProcessRunningInfo.Add("CPU%", cpuUsage.ToString("0.##%"));
  67. currentProcessRunningInfo.Add("Avai Threads-IoThreads", availableThreads.ToString() + "-" + availableIOThreads.ToString());
  68. Logger.LogInformation(currentProcessRunningInfo.Select(s => s.Key + ": " + s.Value)
  69. .Aggregate((p, n) => p + ", " + n));
  70. }
  71. private static Dictionary<string, string> Windows_GetProcessRunningInformation(string processName)
  72. {
  73. var returnDic = new Dictionary<string, string>();
  74. Process operatedProcess = null;
  75. try
  76. {
  77. Process[] processes = System.Diagnostics.Process.GetProcessesByName(processName);
  78. // if process found, then only pick the first one as default, or set with default Null value
  79. if (processes.Length > 0)
  80. {
  81. operatedProcess = processes[0];
  82. }
  83. if (operatedProcess != null && !operatedProcess.HasExited)
  84. {
  85. returnDic.Add("ProcName", operatedProcess.ProcessName + "(Id:" + operatedProcess.Id + ")");
  86. returnDic.Add("VM", operatedProcess.VirtualMemorySize64.ToString());
  87. returnDic.Add("WS", operatedProcess.WorkingSet64.ToString());
  88. returnDic.Add("PM", operatedProcess.PrivateMemorySize64.ToString());
  89. returnDic.Add("Thread", operatedProcess.Threads.Count.ToString());
  90. returnDic.Add("Handle", operatedProcess.HandleCount.ToString());
  91. //returnDic.Add("Start time", operatedProcess.StartTime.ToString("HH:mm:ss dd-MM-yyyy"));
  92. }
  93. else
  94. {
  95. returnDic.Add("Process " + processName, "not existed");
  96. }
  97. }
  98. catch (Exception ex)
  99. {
  100. Logger.LogInformation("Exception occured in PerformanceMonitor, detail: " + ex.ToString());
  101. returnDic.Add("GetProcessRunningInformation error", ex.ToString());
  102. }
  103. return returnDic;
  104. }
  105. public static void Start()
  106. {
  107. /* as in some case of Threadpool drain out, the System.Timer for logging the counters may get paused,
  108. * so here using a dedicate thread to do it.
  109. *
  110. */
  111. Thread dedicatedLoopThread = new Thread(() =>
  112. {
  113. while (true)
  114. {
  115. try
  116. {
  117. if (Environment.OSVersion.Platform == PlatformID.Unix)
  118. Linux_LoggingPerformanceCounter();
  119. else
  120. Windows_LoggingPerformanceCounter();
  121. if (Logger.IsEnabled(LogLevel.Debug))
  122. samplingInterval = 2;
  123. else
  124. samplingInterval = 60;
  125. Thread.Sleep(1000 * samplingInterval);
  126. }
  127. catch (Exception exxx)
  128. {
  129. Logger.LogError("Unexpected exception: " + exxx);
  130. }
  131. }
  132. });
  133. int minThreads, minIoThreads, maxThreads, maxIoThreads;
  134. ThreadPool.GetMinThreads(out minThreads, out minIoThreads);
  135. ThreadPool.GetMaxThreads(out maxThreads, out maxIoThreads);
  136. Logger.LogInformation("Performance Logging is starting, ThreadPool MinThreads count: " + minThreads + ", MinIoThreads count: " + minIoThreads
  137. + ", MaxThreads count: " + maxThreads + ", MaxIoThreads count: " + maxIoThreads);
  138. dedicatedLoopThread.Start();
  139. }
  140. public static string Bash(string cmd)
  141. {
  142. var escapedArgs = cmd.Replace("\"", "\\\"");
  143. var process = new Process()
  144. {
  145. StartInfo = new ProcessStartInfo
  146. {
  147. FileName = "/bin/bash",
  148. Arguments = $"-c \"{escapedArgs}\"",
  149. RedirectStandardOutput = true,
  150. UseShellExecute = false,
  151. CreateNoWindow = true,
  152. }
  153. };
  154. process.Start();
  155. string result = process.StandardOutput.ReadToEnd();
  156. process.WaitForExit();
  157. return result;
  158. }
  159. }
  160. }