2
0

ThreadTrace.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel
  5. {
  6. using System;
  7. using System.IO;
  8. using System.Threading;
  9. using System.Security;
  10. using System.Runtime.InteropServices;
  11. using System.Collections.Generic;
  12. using System.Runtime.CompilerServices;
  13. using System.Runtime.Versioning;
  14. // Enable this code to track which thread operations occur on
  15. #if false
  16. static class ThreadTrace
  17. {
  18. static LocalDataStoreSlot slot;
  19. static List<ThreadLog> logs;
  20. static string logFileName;
  21. static bool isEnabled;
  22. static long frequency;
  23. static ThreadTrace()
  24. {
  25. logFileName = Environment.GetEnvironmentVariable("ThreadTrace");
  26. if (logFileName == null)
  27. logFileName = "";
  28. isEnabled = logFileName.Length > 0;
  29. if (isEnabled)
  30. {
  31. slot = Thread.AllocateDataSlot();
  32. logs = new List<ThreadLog>();
  33. NativeMethods.QueryPerformanceFrequency(out frequency);
  34. Console.WriteLine("ThreadTrace: enabled");
  35. new Thread(ThreadProc).Start();
  36. }
  37. }
  38. static bool stopTracing;
  39. public static void StopTracing()
  40. {
  41. stopTracing = true;
  42. }
  43. static void ThreadProc()
  44. {
  45. while (!stopTracing)
  46. {
  47. Thread.Sleep(20000);
  48. WriteLogFile();
  49. Console.WriteLine("ThreadTrace: " + logFileName + " saved.");
  50. }
  51. }
  52. static object ThisLock
  53. {
  54. get { return logs; }
  55. }
  56. public static void Trace(string operation)
  57. {
  58. if (isEnabled)
  59. {
  60. TraceInternal(operation);
  61. }
  62. }
  63. [MethodImpl(MethodImplOptions.NoInlining)]
  64. static void TraceInternal(string operation)
  65. {
  66. long time;
  67. NativeMethods.QueryPerformanceCounter(out time);
  68. ThreadLog log = (ThreadLog)Thread.GetData(slot);
  69. if (log == null)
  70. {
  71. Thread currentThread = Thread.CurrentThread;
  72. log = new ThreadLog(currentThread);
  73. lock (ThisLock)
  74. {
  75. logs.Add(log);
  76. }
  77. Thread.SetData(slot, log);
  78. }
  79. log.Append(time, operation);
  80. }
  81. static void WriteLogFile()
  82. {
  83. Trace("ThreadTrace.Save");
  84. TextWriter writer = File.CreateText(logFileName);
  85. using (writer)
  86. {
  87. ThreadLogSnapshot[] logSnapshots = new ThreadLogSnapshot[logs.Count];
  88. writer.Write("Time");
  89. for (int i = 0; i < logs.Count; i++)
  90. {
  91. logSnapshots[i] = logs[i].GetSnapshot();
  92. writer.Write(", Thread ");
  93. writer.Write(i.ToString());
  94. }
  95. writer.WriteLine();
  96. writer.Write("(Ms)");
  97. foreach (ThreadLog log in logs)
  98. {
  99. if (log.IsThreadPoolThread)
  100. writer.Write(", (ThreadPool)");
  101. else if (log.IsBackgroundThread)
  102. writer.Write(", (Background)");
  103. else
  104. writer.Write(", (Main)");
  105. }
  106. writer.WriteLine();
  107. int[] indices = new int[logs.Count];
  108. int count = 0;
  109. for (int i = 0; i < logs.Count; i++)
  110. count += logSnapshots[i].Count;
  111. for (int j = 0; j < count; j++)
  112. {
  113. int earliestIndex = -1;
  114. long earliestTime = long.MaxValue;
  115. for (int i = 0; i < logs.Count; i++)
  116. {
  117. ThreadLogSnapshot logSnapshot = logSnapshots[i];
  118. int index = indices[i];
  119. if (index >= logSnapshot.Count)
  120. continue;
  121. long time = logSnapshot[index].time;
  122. if (time < earliestTime)
  123. {
  124. earliestIndex = i;
  125. earliestTime = time;
  126. }
  127. }
  128. ThreadLogEntry entry = logSnapshots[earliestIndex][indices[earliestIndex]];
  129. double timeInMilliseconds = (entry.time * 1000) / (double)frequency;
  130. writer.Write(timeInMilliseconds);
  131. for (int i = 0; i < logs.Count; i++)
  132. {
  133. writer.Write(", ");
  134. if (i == earliestIndex)
  135. {
  136. writer.Write('\"');
  137. writer.Write(entry.operation);
  138. writer.Write('\"');
  139. }
  140. }
  141. writer.WriteLine();
  142. indices[earliestIndex]++;
  143. }
  144. }
  145. }
  146. struct ThreadLogEntry
  147. {
  148. public long time;
  149. public string operation;
  150. public ThreadLogEntry(long time, string operation)
  151. {
  152. this.time = time;
  153. this.operation = operation;
  154. }
  155. }
  156. class ThreadLogSnapshot
  157. {
  158. ThreadLogEntry[] entries;
  159. public ThreadLogSnapshot(ThreadLogEntry[] entries)
  160. {
  161. this.entries = entries;
  162. }
  163. public int Count
  164. {
  165. get
  166. {
  167. return this.entries.Length;
  168. }
  169. }
  170. public ThreadLogEntry this[int index]
  171. {
  172. get
  173. {
  174. return this.entries[index];
  175. }
  176. }
  177. }
  178. class ThreadLog
  179. {
  180. int count;
  181. ThreadLogEntry[] buffer;
  182. const int bufferSize = 5000;
  183. const int maxBuffers = 4096;
  184. bool isThreadPoolThread;
  185. bool isBackgroundThread;
  186. ThreadLogEntry[][] buffers;
  187. int bufferCount;
  188. public ThreadLog(Thread thread)
  189. {
  190. this.isThreadPoolThread = thread.IsThreadPoolThread;
  191. this.isBackgroundThread = thread.IsBackground;
  192. this.buffer = new ThreadLogEntry[bufferSize];
  193. this.buffers = new ThreadLogEntry[maxBuffers][];
  194. }
  195. object ThisLock
  196. {
  197. get { return this; }
  198. }
  199. public bool IsThreadPoolThread
  200. {
  201. get { return this.isThreadPoolThread; }
  202. }
  203. public bool IsBackgroundThread
  204. {
  205. get { return this.isBackgroundThread; }
  206. }
  207. public void Append(long time, string operation)
  208. {
  209. if (this.count == bufferSize)
  210. {
  211. lock (ThisLock)
  212. {
  213. this.buffers[bufferCount++] = this.buffer;
  214. this.buffer = new ThreadLogEntry[bufferSize];
  215. this.count = 0;
  216. }
  217. }
  218. this.buffer[this.count++] = new ThreadLogEntry(time, operation);
  219. }
  220. public ThreadLogSnapshot GetSnapshot()
  221. {
  222. int currentBufferCount;
  223. int currentCount;
  224. ThreadLogEntry[] currentBuffer;
  225. lock (ThisLock)
  226. {
  227. currentBufferCount = this.bufferCount;
  228. currentCount = this.count;
  229. currentBuffer = this.buffer;
  230. }
  231. ThreadLogEntry[] entries = new ThreadLogEntry[currentBufferCount * bufferSize + currentCount];
  232. int index = 0;
  233. for (int i = 0; i < currentBufferCount; i++)
  234. {
  235. Array.Copy(buffers[i], 0, entries, index, bufferSize);
  236. index += bufferSize;
  237. }
  238. Array.Copy(currentBuffer, 0, entries, index, currentCount);
  239. return new ThreadLogSnapshot(entries);
  240. }
  241. }
  242. [SuppressUnmanagedCodeSecurity]
  243. static class NativeMethods
  244. {
  245. [DllImport("kernel32.dll")]
  246. [ResourceExposure(ResourceScope.None)]
  247. public static extern int QueryPerformanceCounter(out long time);
  248. [DllImport("kernel32.dll")]
  249. [ResourceExposure(ResourceScope.None)]
  250. public static extern int QueryPerformanceFrequency(out long frequency);
  251. }
  252. }
  253. #else
  254. static class ThreadTrace
  255. {
  256. public static void Trace(string operation)
  257. {
  258. }
  259. public static void StopTracing()
  260. {
  261. }
  262. public static void Save()
  263. {
  264. }
  265. }
  266. #endif
  267. }