Guest User

Untitled

a guest
Feb 20th, 2018
81
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.51 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using log4net;
  5. using TicketmasterSystems.Configuration;
  6. using TicketmasterSystems.Shared.SSETI.Internals;
  7. using System.Threading;
  8.  
  9. namespace TicketmasterSystems.Shared.SSETI.Performance
  10. {
  11. public static class CounterNames
  12. {
  13. public const string CurrentConnections = "Current connections";
  14. public const string CurrentMessages = "Current messages";
  15. public const string CurrentTotalBaskets = "Current total baskets";
  16. public const string CurrentIdleBaskets = "Current idle baskets";
  17. public const string CurrentBusyBaskets = "Current busy baskets";
  18. public const string CurrentErroredBaskets = "Current errored baskets";
  19. public const string ConnectionsPerSecond = "# connections / second";
  20. public const string MessagesPerSecond = "# messages / second";
  21. public const string AverageMessageTime = "Average message duration";
  22. public const string AverageMessageTimeBase = "Average message duration base";
  23. }
  24.  
  25. /// <summary>
  26. /// Stores, updates and supplies performance metrics for SSETI.NET by storing metrics internally within this instance.
  27. /// </summary>
  28. public static class SSETIPerformanceMonitor
  29. {
  30. private static ILog log = LogManager.GetLogger("PERFORMANCE");
  31.  
  32. private static bool arecountersavailable = false;
  33.  
  34. private static DateTime startupTime = DateTime.Now;
  35. private static Dictionary<string, MessagePerformanceTracker> perfitems = new Dictionary<string, MessagePerformanceTracker>();
  36.  
  37. private static PerformanceCounter counterCurrentConnections = null;
  38. private static PerformanceCounter counterCurrentMessages = null;
  39. private static PerformanceCounter counterCurrentTotalBaskets = null;
  40. private static PerformanceCounter counterCurrentIdleBaskets = null;
  41. private static PerformanceCounter counterCurrentBusyBaskets = null;
  42. private static PerformanceCounter counterCurrentErroredBaskets = null;
  43. private static PerformanceCounter counterConnectionsPerSecond = null;
  44. private static PerformanceCounter counterMessagesPerSecond = null;
  45. private static PerformanceCounter counterAverageMessageTime = null;
  46. private static PerformanceCounter counterAverageMessageTimeBase = null;
  47.  
  48. public const string CategoryName = "SSETI.NET";
  49.  
  50. public static void Initialise()
  51. {
  52. // If we are running in mono, disable counters
  53. if(Config.IsMono)
  54. {
  55. log.Warn("PERFORMANCE: Performance counters are not available when running on Mono");
  56. return;
  57. }
  58.  
  59. // Create the performance counters to track global information
  60. CreateCounters();
  61.  
  62. // Register performance counters for use
  63. RegisterCounters();
  64. arecountersavailable = true;
  65. }
  66.  
  67. static SSETIPerformanceMonitor()
  68. {
  69. // Reset the performance monitor when apply changes is run
  70. Config.Reset += new EventHandler<ConfigResetEventArgs>(Reset);
  71. }
  72.  
  73. public static void Reset(object sender, EventArgs e)
  74. {
  75. // Add the performance items for each message type
  76. perfitems.Clear();
  77. foreach(Type t in MessageFactory.Current.AllMessageTypes) perfitems.Add(t.Name, new MessagePerformanceTracker(t.Name));
  78. }
  79.  
  80. private static void CreateCounters()
  81. {
  82. log.InfoFormat("PERFORMANCE: Binding/creating performance counters");
  83.  
  84. CounterCreationDataCollection counterdata = new CounterCreationDataCollection();
  85. counterdata.Add(new CounterCreationData(CounterNames.CurrentConnections, "", PerformanceCounterType.NumberOfItems32));
  86. counterdata.Add(new CounterCreationData(CounterNames.CurrentMessages, "", PerformanceCounterType.NumberOfItems32));
  87. counterdata.Add(new CounterCreationData(CounterNames.CurrentTotalBaskets, "", PerformanceCounterType.NumberOfItems32));
  88. counterdata.Add(new CounterCreationData(CounterNames.CurrentIdleBaskets, "", PerformanceCounterType.NumberOfItems32));
  89. counterdata.Add(new CounterCreationData(CounterNames.CurrentBusyBaskets, "", PerformanceCounterType.NumberOfItems32));
  90. counterdata.Add(new CounterCreationData(CounterNames.CurrentErroredBaskets, "", PerformanceCounterType.NumberOfItems32));
  91. counterdata.Add(new CounterCreationData(CounterNames.ConnectionsPerSecond, "", PerformanceCounterType.RateOfCountsPerSecond32));
  92. counterdata.Add(new CounterCreationData(CounterNames.MessagesPerSecond, "", PerformanceCounterType.RateOfCountsPerSecond32));
  93. counterdata.Add(new CounterCreationData(CounterNames.AverageMessageTime, "", PerformanceCounterType.AverageTimer32));
  94. counterdata.Add(new CounterCreationData(CounterNames.AverageMessageTimeBase, "", PerformanceCounterType.AverageBase));
  95.  
  96. // Check if all of these already exist
  97. int countexist = 0;
  98. if(PerformanceCounterCategory.Exists(CategoryName))
  99. {
  100. foreach(CounterCreationData ccd in counterdata)
  101. {
  102. if(PerformanceCounterCategory.CounterExists(ccd.CounterName, CategoryName)) countexist++;
  103. }
  104. }
  105.  
  106. // If some of the counters didnt exist, delete the category and recreate
  107. if(countexist != counterdata.Count)
  108. {
  109. if(PerformanceCounterCategory.Exists(CategoryName)) PerformanceCounterCategory.Delete(CategoryName);
  110. PerformanceCounterCategory.Create(CategoryName, "", PerformanceCounterCategoryType.MultiInstance, counterdata);
  111. log.InfoFormat("PERFORMANCE: Successfully created performance counters: Count = {0}", counterdata.Count);
  112. }
  113. else
  114. {
  115. log.InfoFormat("PERFORMANCE: Existing performance counters found: Count = {0}", countexist);
  116. }
  117. }
  118.  
  119. private static void RegisterCounters()
  120. {
  121. counterCurrentConnections = new PerformanceCounter(CategoryName, CounterNames.CurrentConnections, Config.ServiceName, false);
  122. counterCurrentMessages = new PerformanceCounter(CategoryName, CounterNames.CurrentMessages, Config.ServiceName, false);
  123. counterCurrentTotalBaskets = new PerformanceCounter(CategoryName, CounterNames.CurrentTotalBaskets, Config.ServiceName, false);
  124. counterCurrentIdleBaskets = new PerformanceCounter(CategoryName, CounterNames.CurrentIdleBaskets, Config.ServiceName, false);
  125. counterCurrentBusyBaskets = new PerformanceCounter(CategoryName, CounterNames.CurrentBusyBaskets, Config.ServiceName, false);
  126. counterCurrentErroredBaskets = new PerformanceCounter(CategoryName, CounterNames.CurrentErroredBaskets, Config.ServiceName, false);
  127. counterConnectionsPerSecond = new PerformanceCounter(CategoryName, CounterNames.ConnectionsPerSecond, Config.ServiceName, false);
  128. counterMessagesPerSecond = new PerformanceCounter(CategoryName, CounterNames.MessagesPerSecond, Config.ServiceName, false);
  129. counterAverageMessageTime = new PerformanceCounter(CategoryName, CounterNames.AverageMessageTime, Config.ServiceName, false);
  130. counterAverageMessageTimeBase = new PerformanceCounter(CategoryName, CounterNames.AverageMessageTimeBase, Config.ServiceName, false);
  131.  
  132. // Retrieve basket counts
  133. int openbaskets, idlebaskets, busybaskets, completedbaskets, erroredbaskets;
  134. Baskets.GetBasketCounts(out openbaskets, out idlebaskets, out busybaskets, out completedbaskets, out erroredbaskets);
  135.  
  136. counterCurrentConnections.RawValue = 0;
  137. counterCurrentMessages.RawValue = 0;
  138. counterCurrentTotalBaskets.RawValue = openbaskets;
  139. counterCurrentIdleBaskets.RawValue = idlebaskets;
  140. counterCurrentBusyBaskets.RawValue = busybaskets;
  141. counterCurrentErroredBaskets.RawValue = erroredbaskets;
  142. counterConnectionsPerSecond.RawValue = 0;
  143. counterMessagesPerSecond.RawValue = 0;
  144. counterAverageMessageTime.RawValue = 0;
  145. counterAverageMessageTimeBase.RawValue = 0;
  146. }
  147.  
  148. #region Performance Events
  149.  
  150. public static void NewConnection(SessionState state)
  151. {
  152. try
  153. {
  154. state.ConnectionTimer = new Stopwatch();
  155. state.ConnectionTimer.Start();
  156.  
  157. counterCurrentConnections.Increment();
  158. counterConnectionsPerSecond.Increment();
  159. }
  160. catch(Exception) { }
  161. }
  162.  
  163. /// <summary>
  164. /// Should be called when a new message is received and before any processing is done.
  165. /// </summary>
  166. public static void NewMessage(SessionState state)
  167. {
  168. try
  169. {
  170. state.Timer = new Stopwatch();
  171. state.Timer.Start();
  172.  
  173. counterCurrentMessages.Increment();
  174. }
  175. catch(Exception) { }
  176. }
  177.  
  178. /// <summary>
  179. /// Should be called after the response to a message has been transmitted.
  180. /// </summary>
  181. /// <param name="state"></param>
  182. public static void CloseMessage(SessionState state)
  183. {
  184. try
  185. {
  186. if(state != null && state.Timer != null)
  187. {
  188. state.Timer.Stop();
  189. if(state.Message != null)
  190. {
  191. perfitems[state.Message.GetType().Name].UpdateWithTimer(1, state.Timer.ElapsedMilliseconds / 1000d);
  192.  
  193. counterAverageMessageTime.IncrementBy(state.Timer.ElapsedTicks);
  194. counterAverageMessageTimeBase.Increment();
  195. }
  196. }
  197.  
  198. counterCurrentMessages.Decrement();
  199. counterMessagesPerSecond.Increment(); // Messages / sec is only updated upon message completion
  200. }
  201. catch(Exception) { }
  202. }
  203.  
  204. public static void CloseConnection(SessionState state)
  205. {
  206. try
  207. {
  208. if(state.ConnectionTimer != null) state.ConnectionTimer.Stop();
  209.  
  210. counterCurrentConnections.Decrement();
  211. }
  212. catch(Exception) { }
  213. }
  214.  
  215. /// <summary>
  216. /// Should be called when a new user session (a basket) is created.
  217. /// </summary>
  218. public static void NewBasket()
  219. {
  220. try
  221. {
  222. counterCurrentTotalBaskets.Increment();
  223. counterCurrentIdleBaskets.Increment();
  224. }
  225. catch(Exception) { }
  226. }
  227.  
  228. /// <summary>
  229. /// Should be called when a user session (a basket) is destroyed.
  230. /// </summary>
  231. public static void DeleteBasket()
  232. {
  233. try
  234. {
  235. counterCurrentTotalBaskets.Decrement();
  236. counterCurrentIdleBaskets.Decrement();
  237. }
  238. catch(Exception) { }
  239. }
  240.  
  241. #endregion
  242.  
  243. #region Statistics
  244.  
  245. public static long CurrentNumberConnections
  246. {
  247. get
  248. {
  249. if(!arecountersavailable) return 0;
  250. return counterCurrentConnections.RawValue;
  251. }
  252. }
  253.  
  254. public static long CurrentNumberMessages
  255. {
  256. get
  257. {
  258. if(!arecountersavailable) return 0;
  259. return counterCurrentMessages.RawValue;
  260. }
  261. }
  262.  
  263. public static long CurrentNumberMessagesPerSecond
  264. {
  265. get
  266. {
  267. if(!arecountersavailable) return 0;
  268. return counterMessagesPerSecond.RawValue;
  269. }
  270. }
  271.  
  272. public static long CurrentTotalBaskets
  273. {
  274. get
  275. {
  276. if(!arecountersavailable) return 0;
  277. return counterCurrentTotalBaskets.RawValue;
  278. }
  279. set
  280. {
  281. if(!arecountersavailable) return;
  282. counterCurrentTotalBaskets.RawValue = value;
  283. }
  284. }
  285.  
  286. public static long CurrentIdleBaskets
  287. {
  288. get
  289. {
  290. if(!arecountersavailable) return 0;
  291. return counterCurrentIdleBaskets.RawValue;
  292. }
  293. set
  294. {
  295. if(!arecountersavailable) return;
  296. counterCurrentIdleBaskets.RawValue = value;
  297. }
  298. }
  299.  
  300. public static long CurrentBusyBaskets
  301. {
  302. get
  303. {
  304. if(!arecountersavailable) return 0;
  305. return counterCurrentBusyBaskets.RawValue;
  306. }
  307. set
  308. {
  309. if(!arecountersavailable) return;
  310. counterCurrentBusyBaskets.RawValue = value;
  311. }
  312. }
  313.  
  314. public static long CurrentErroredBaskets
  315. {
  316. get
  317. {
  318. if(!arecountersavailable) return 0;
  319. return counterCurrentErroredBaskets.RawValue;
  320. }
  321. set
  322. {
  323. if(!arecountersavailable) return;
  324. counterCurrentErroredBaskets.RawValue = value;
  325. }
  326. }
  327.  
  328. public static long TotalNumberMessages
  329. {
  330. get
  331. {
  332. long tot = 0;
  333. foreach(KeyValuePair<string, MessagePerformanceTracker> pi in perfitems)
  334. {
  335. if(!pi.Value.Name.StartsWith(":")) tot += pi.Value.Count;
  336. }
  337. return tot;
  338. }
  339. }
  340.  
  341. public static DateTime StartupTime
  342. {
  343. get { return startupTime; }
  344. }
  345.  
  346. public static Dictionary<string, MessagePerformanceTracker> MessageStatistics
  347. {
  348. get { return perfitems; }
  349. }
  350.  
  351. #endregion
  352.  
  353. /// <summary>
  354. /// Dumps a list of SSETI messages and their runtime statistics.
  355. /// </summary>
  356. public static void DumpMessageStats()
  357. {
  358. log.DebugFormat("DUMPING MESSAGE STATISTICS");
  359. log.DebugFormat("(timings indicate only message processing - no network latency, deferred message pre-execution timings listed here only)");
  360.  
  361. int count = 0;
  362. foreach(KeyValuePair<string, MessagePerformanceTracker> mt in SSETIPerformanceMonitor.MessageStatistics)
  363. {
  364. if(mt.Value.Count == 0) continue;
  365. log.InfoFormat("{0} : {1}", mt.Key.PadRight(30).Substring(0, 30), mt.Value.ToString());
  366. count++;
  367. }
  368. if(count == 0) log.Info("- no message statistics logged yet -");
  369.  
  370. log.Debug("END");
  371. }
  372. }
  373. }
Add Comment
Please, Sign In to add comment