ProcessPerformanceCounterHelper.cs 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading;
  7. using SuperSocket.Common;
  8. using SuperSocket.SocketBase;
  9. using SuperSocket.SocketBase.Metadata;
  10. namespace SuperSocket.SocketEngine
  11. {
  12. class ProcessPerformanceCounterHelper : IDisposable
  13. {
  14. private PerformanceCounter m_CpuUsagePC;
  15. private PerformanceCounter m_ThreadCountPC;
  16. private PerformanceCounter m_WorkingSetPC;
  17. private int m_CpuCores = 1;
  18. private Process m_Process;
  19. public ProcessPerformanceCounterHelper(Process process)
  20. {
  21. m_Process = process;
  22. m_CpuCores = Environment.ProcessorCount;
  23. //Windows .Net, to avoid same name process issue
  24. if (!Platform.IsMono)
  25. RegisterSameNameProcesses(process);
  26. SetupPerformanceCounters();
  27. }
  28. private void RegisterSameNameProcesses(Process process)
  29. {
  30. foreach (var p in Process.GetProcessesByName(process.ProcessName).Where(x => x.Id != process.Id))
  31. {
  32. p.EnableRaisingEvents = true;
  33. p.Exited += new EventHandler(SameNameProcess_Exited);
  34. }
  35. }
  36. //When find a same name process exit, re-initialize the performance counters
  37. //because the performance counters' instance names could have been changed
  38. void SameNameProcess_Exited(object sender, EventArgs e)
  39. {
  40. SetupPerformanceCounters();
  41. }
  42. private void SetupPerformanceCounters()
  43. {
  44. var isUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX;
  45. var instanceName = string.Empty;
  46. if (isUnix || Platform.IsMono)
  47. instanceName = string.Format("{0}/{1}", m_Process.Id, m_Process.ProcessName);
  48. else
  49. instanceName = GetPerformanceCounterInstanceName(m_Process);
  50. // the process has exited
  51. if (string.IsNullOrEmpty(instanceName))
  52. return;
  53. SetupPerformanceCounters(instanceName);
  54. }
  55. private void SetupPerformanceCounters(string instanceName)
  56. {
  57. m_CpuUsagePC = new PerformanceCounter("Process", "% Processor Time", instanceName);
  58. m_ThreadCountPC = new PerformanceCounter("Process", "Thread Count", instanceName);
  59. m_WorkingSetPC = new PerformanceCounter("Process", "Working Set", instanceName);
  60. }
  61. //This method is only used in windows
  62. private static string GetPerformanceCounterInstanceName(Process process)
  63. {
  64. var processId = process.Id;
  65. var processCategory = new PerformanceCounterCategory("Process");
  66. var runnedInstances = processCategory.GetInstanceNames();
  67. foreach (string runnedInstance in runnedInstances)
  68. {
  69. if (!runnedInstance.StartsWith(process.ProcessName, StringComparison.OrdinalIgnoreCase))
  70. continue;
  71. if (process.HasExited)
  72. return string.Empty;
  73. using (var performanceCounter = new PerformanceCounter("Process", "ID Process", runnedInstance, true))
  74. {
  75. var counterProcessId = 0;
  76. try
  77. {
  78. counterProcessId = (int)performanceCounter.RawValue;
  79. }
  80. catch //that process has been shutdown
  81. {
  82. continue;
  83. }
  84. if (counterProcessId == processId)
  85. {
  86. return runnedInstance;
  87. }
  88. }
  89. }
  90. return process.ProcessName;
  91. }
  92. public void Collect(StatusInfoCollection statusCollection)
  93. {
  94. int availableWorkingThreads, availableCompletionPortThreads;
  95. ThreadPool.GetAvailableThreads(out availableWorkingThreads, out availableCompletionPortThreads);
  96. int maxWorkingThreads;
  97. int maxCompletionPortThreads;
  98. ThreadPool.GetMaxThreads(out maxWorkingThreads, out maxCompletionPortThreads);
  99. var retry = false;
  100. while (true)
  101. {
  102. try
  103. {
  104. statusCollection[StatusInfoKeys.AvailableWorkingThreads] = availableWorkingThreads;
  105. statusCollection[StatusInfoKeys.AvailableCompletionPortThreads] = availableCompletionPortThreads;
  106. statusCollection[StatusInfoKeys.MaxCompletionPortThreads] = maxCompletionPortThreads;
  107. statusCollection[StatusInfoKeys.MaxWorkingThreads] = maxWorkingThreads;
  108. statusCollection[StatusInfoKeys.TotalThreadCount] = (int)m_ThreadCountPC.NextValue();
  109. statusCollection[StatusInfoKeys.CpuUsage] = m_CpuUsagePC.NextValue() / m_CpuCores;
  110. statusCollection[StatusInfoKeys.MemoryUsage] = (long)m_WorkingSetPC.NextValue();
  111. break;
  112. }
  113. catch (InvalidOperationException e)
  114. {
  115. //Only re-get performance counter one time
  116. if (retry)
  117. throw e;
  118. //Only re-get performance counter for .NET/Windows
  119. if (Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX || Platform.IsMono)
  120. throw e;
  121. //If a same name process exited, this process's performance counters instance name could be changed,
  122. //so if the old performance counter cannot be access, get the performance counter's name again
  123. var newInstanceName = GetPerformanceCounterInstanceName(m_Process);
  124. if (string.IsNullOrEmpty(newInstanceName))
  125. break;
  126. SetupPerformanceCounters(newInstanceName);
  127. retry = true;
  128. }
  129. }
  130. }
  131. public void Dispose()
  132. {
  133. if (m_CpuUsagePC != null)
  134. {
  135. m_CpuUsagePC.Close();
  136. m_CpuUsagePC = null;
  137. }
  138. if (m_ThreadCountPC != null)
  139. {
  140. m_ThreadCountPC.Close();
  141. m_ThreadCountPC = null;
  142. }
  143. if (m_WorkingSetPC != null)
  144. {
  145. m_WorkingSetPC.Close();
  146. m_WorkingSetPC = null;
  147. }
  148. }
  149. }
  150. }