PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Microsoft.AspNet.SignalR.Stress/Program.cs

https://github.com/mip1983/SignalR
C# | 553 lines | 445 code | 96 blank | 12 comment | 38 complexity | 12372902e1047a535fc228bbeb7bf7dd MD5 | raw file
Possible License(s): Apache-2.0, CC-BY-SA-3.0
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.md in the project root for license information.
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading;
  9. using System.Threading.Tasks;
  10. using Microsoft.AspNet.SignalR.Client.Hubs;
  11. using Microsoft.AspNet.SignalR.Hosting.Memory;
  12. using Microsoft.AspNet.SignalR.Hubs;
  13. using Microsoft.AspNet.SignalR.Transports;
  14. namespace Microsoft.AspNet.SignalR.Stress
  15. {
  16. class Program
  17. {
  18. private static Timer _rateTimer;
  19. private static bool _measuringRate;
  20. private static Stopwatch _sw = Stopwatch.StartNew();
  21. private static double _receivesPerSecond;
  22. private static double _peakReceivesPerSecond;
  23. private static double _avgReceivesPerSecond;
  24. private static long _received;
  25. private static long _avgLastReceivedCount;
  26. private static long _lastReceivedCount;
  27. private static double _sendsPerSecond;
  28. private static double _peakSendsPerSecond;
  29. private static double _avgSendsPerSecond;
  30. private static long _sent;
  31. private static long _avgLastSendsCount;
  32. private static long _lastSendsCount;
  33. private static DateTime _avgCalcStart;
  34. private static long _rate = 1;
  35. private static int _runs = 0;
  36. private static int _step = 1;
  37. private static int _stepInterval = 10;
  38. private static int _clients = 5000;
  39. private static int _clientsRunning = 0;
  40. private static int _senders = 1;
  41. private static Exception _exception;
  42. public static long TotalRate
  43. {
  44. get
  45. {
  46. return _rate * _clients;
  47. }
  48. }
  49. static void Main(string[] args)
  50. {
  51. Debug.Listeners.Add(new ConsoleTraceListener());
  52. Debug.AutoFlush = true;
  53. while (true)
  54. {
  55. Console.WriteLine("==================================");
  56. Console.WriteLine("BEGIN RUN");
  57. Console.WriteLine("==================================");
  58. StressGroups();
  59. Console.WriteLine("==================================");
  60. Console.WriteLine("END RUN");
  61. Console.WriteLine("==================================");
  62. }
  63. //TaskScheduler.UnobservedTaskException += OnUnobservedTaskException;
  64. ThreadPool.SetMinThreads(32, 32);
  65. // RunBusTest();
  66. // RunConnectionTest();
  67. //RunConnectionReceiveLoopTest();
  68. var host = RunMemoryHost();
  69. Console.ReadLine();
  70. host.Dispose();
  71. }
  72. private static void Write(Stream stream, string raw)
  73. {
  74. var data = Encoding.Default.GetBytes(raw);
  75. stream.Write(data, 0, data.Length);
  76. }
  77. public static void StressGroups()
  78. {
  79. var host = new MemoryHost();
  80. host.HubPipeline.EnableAutoRejoiningGroups();
  81. host.MapHubs();
  82. int max = 15;
  83. var countDown = new CountDown(max);
  84. var list = Enumerable.Range(0, max).ToList();
  85. var connection = new Client.Hubs.HubConnection("http://foo");
  86. var proxy = connection.CreateHubProxy("MultGroupHub");
  87. var bus = (MessageBus)host.DependencyResolver.Resolve<IMessageBus>();
  88. proxy.On<int>("Do", i =>
  89. {
  90. lock (list)
  91. {
  92. if (!list.Remove(i))
  93. {
  94. Debugger.Break();
  95. }
  96. }
  97. countDown.Dec();
  98. });
  99. try
  100. {
  101. connection.Start(host).Wait();
  102. for (int i = 0; i < max; i++)
  103. {
  104. proxy.Invoke("Do", i).Wait();
  105. }
  106. int retry = 3;
  107. bool result = false;
  108. do
  109. {
  110. result = countDown.Wait(TimeSpan.FromSeconds(10));
  111. if (!result)
  112. {
  113. Console.WriteLine("Didn't receive " + max + " messages. Got " + (max - countDown.Count) + " missed (" + String.Join(",", list.Select(i => i.ToString())) + ")");
  114. Console.WriteLine("A=" + bus.AllocatedWorkers + " B=" + bus.BusyWorkers);
  115. countDown.Reset();
  116. }
  117. retry--;
  118. } while (retry > 0);
  119. if (!result)
  120. {
  121. Console.WriteLine("A=" + bus.AllocatedWorkers + " B=" + bus.BusyWorkers);
  122. Debugger.Break();
  123. }
  124. }
  125. finally
  126. {
  127. connection.Stop();
  128. host.Dispose();
  129. GC.Collect();
  130. GC.WaitForPendingFinalizers();
  131. }
  132. }
  133. private static void RunConnectionTest()
  134. {
  135. string payload = GetPayload();
  136. var dr = new DefaultDependencyResolver();
  137. MeasureStats((MessageBus)dr.Resolve<IMessageBus>());
  138. var connectionManager = new ConnectionManager(dr);
  139. var context = connectionManager.GetConnectionContext<StressConnection>();
  140. for (int i = 0; i < _clients; i++)
  141. {
  142. ThreadPool.QueueUserWorkItem(state =>
  143. {
  144. Interlocked.Increment(ref _clientsRunning);
  145. var transportConnection = (ITransportConnection)context.Connection;
  146. transportConnection.Receive(null, r =>
  147. {
  148. Interlocked.Add(ref _received, r.TotalCount);
  149. Interlocked.Add(ref _avgLastReceivedCount, r.TotalCount);
  150. return TaskAsyncHelper.True;
  151. },
  152. maxMessages: 10);
  153. }, i);
  154. }
  155. for (var i = 1; i <= _senders; i++)
  156. {
  157. ThreadPool.QueueUserWorkItem(_ =>
  158. {
  159. StartSendLoop(i.ToString(), (source, key, value) => context.Connection.Broadcast(value), payload);
  160. });
  161. }
  162. }
  163. private static MemoryHost RunMemoryHost()
  164. {
  165. var host = new MemoryHost();
  166. host.MapConnection<StressConnection>("/echo");
  167. string payload = GetPayload();
  168. MeasureStats((MessageBus)host.DependencyResolver.Resolve<IMessageBus>());
  169. Action<PersistentResponse> handler = (r) =>
  170. {
  171. Interlocked.Add(ref _received, r.TotalCount);
  172. Interlocked.Add(ref _avgLastReceivedCount, r.TotalCount);
  173. };
  174. LongPollingTransport.SendingResponse += handler;
  175. ForeverFrameTransport.SendingResponse += handler;
  176. for (int i = 0; i < _clients; i++)
  177. {
  178. ThreadPool.QueueUserWorkItem(state =>
  179. {
  180. Interlocked.Increment(ref _clientsRunning);
  181. string connectionId = state.ToString();
  182. //LongPollingLoop(host, connectionId);
  183. ProcessRequest(host, "serverSentEvents", connectionId);
  184. }, i);
  185. }
  186. for (var i = 1; i <= _senders; i++)
  187. {
  188. ThreadPool.QueueUserWorkItem(_ =>
  189. {
  190. var context = host.ConnectionManager.GetConnectionContext<StressConnection>();
  191. StartSendLoop(i.ToString(), (source, key, value) => context.Connection.Broadcast(value), payload);
  192. });
  193. }
  194. return host;
  195. }
  196. private static void LongPollingLoop(MemoryHost host, string connectionId)
  197. {
  198. LongPoll:
  199. var task = ProcessRequest(host, "longPolling", connectionId);
  200. if (task.IsCompleted)
  201. {
  202. task.Wait();
  203. goto LongPoll;
  204. }
  205. task.ContinueWith(t => LongPollingLoop(host, connectionId));
  206. }
  207. private static Task ProcessRequest(MemoryHost host, string transport, string connectionId)
  208. {
  209. return host.ProcessRequest("http://foo/echo/connect?transport=" + transport + "&connectionId=" + connectionId, request => { }, null);
  210. }
  211. private static void RunConnectionReceiveLoopTest()
  212. {
  213. string payload = GetPayload();
  214. var dr = new DefaultDependencyResolver();
  215. MeasureStats((MessageBus)dr.Resolve<IMessageBus>());
  216. var connectionManager = new ConnectionManager(dr);
  217. var context = connectionManager.GetConnectionContext<StressConnection>();
  218. for (int i = 0; i < _clients; i++)
  219. {
  220. ThreadPool.QueueUserWorkItem(state =>
  221. {
  222. Interlocked.Increment(ref _clientsRunning);
  223. var transportConnection = (ITransportConnection)context.Connection;
  224. ReceiveLoop(transportConnection, null);
  225. }, i);
  226. }
  227. for (var i = 1; i <= _senders; i++)
  228. {
  229. ThreadPool.QueueUserWorkItem(_ =>
  230. {
  231. StartSendLoop(i.ToString(), (source, key, value) => context.Connection.Broadcast(value), payload);
  232. });
  233. }
  234. }
  235. private static void ReceiveLoop(ITransportConnection connection, string messageId)
  236. {
  237. connection.ReceiveAsync(messageId, CancellationToken.None, maxMessages: 5000).Then(r =>
  238. {
  239. Interlocked.Add(ref _received, r.TotalCount);
  240. Interlocked.Add(ref _avgLastReceivedCount, r.TotalCount);
  241. ReceiveLoop(connection, r.MessageId);
  242. });
  243. }
  244. private static void RunBusTest()
  245. {
  246. var resolver = new DefaultDependencyResolver();
  247. var bus = new MessageBus(resolver);
  248. string payload = GetPayload();
  249. MeasureStats(bus);
  250. for (int i = 0; i < _clients; i++)
  251. {
  252. var subscriber = new Subscriber(i.ToString(), new[] { "a", "b", "c" });
  253. ThreadPool.QueueUserWorkItem(_ => StartClientLoop(bus, subscriber));
  254. }
  255. for (var i = 1; i <= _senders; i++)
  256. {
  257. ThreadPool.QueueUserWorkItem(_ => StartSendLoop(i.ToString(), bus.Publish, payload));
  258. }
  259. }
  260. private static void StartSendLoop(string clientId, Func<string, string, string, Task> publish, string payload)
  261. {
  262. while (_exception == null)
  263. {
  264. long old = _rate;
  265. var interval = TimeSpan.FromTicks((TimeSpan.TicksPerSecond / _rate) * _senders);
  266. while (Interlocked.Read(ref _rate) == old && _exception == null)
  267. {
  268. try
  269. {
  270. publish(clientId, "a", payload).Wait();
  271. Interlocked.Increment(ref _sent);
  272. Interlocked.Increment(ref _avgLastSendsCount);
  273. // Thread.Sleep(interval);
  274. }
  275. catch (Exception ex)
  276. {
  277. Interlocked.Exchange(ref _exception, ex);
  278. }
  279. }
  280. }
  281. }
  282. private static string GetPayload(int n = 32)
  283. {
  284. return new string('a', n);
  285. }
  286. static void OnUnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
  287. {
  288. Interlocked.Exchange(ref _exception, e.Exception);
  289. e.SetObserved();
  290. }
  291. private static void StartClientLoop(MessageBus bus, ISubscriber subscriber)
  292. {
  293. Interlocked.Increment(ref _clientsRunning);
  294. try
  295. {
  296. bus.Subscribe(subscriber, null, result =>
  297. {
  298. Interlocked.Add(ref _received, result.TotalCount);
  299. Interlocked.Add(ref _avgLastReceivedCount, result.TotalCount);
  300. return TaskAsyncHelper.True;
  301. },
  302. messageBufferSize: 10);
  303. }
  304. catch (Exception ex)
  305. {
  306. Interlocked.Exchange(ref _exception, ex);
  307. }
  308. }
  309. public static void MeasureStats(MessageBus bus)
  310. {
  311. _sw.Start();
  312. _avgCalcStart = DateTime.UtcNow;
  313. var resultsPath = Guid.NewGuid().ToString() + ".csv";
  314. // File.WriteAllText(resultsPath, "Target Rate, RPS, Peak RPS, Avg RPS\n");
  315. _rateTimer = new Timer(_ =>
  316. {
  317. if (_measuringRate)
  318. {
  319. return;
  320. }
  321. _measuringRate = true;
  322. try
  323. {
  324. var now = DateTime.UtcNow;
  325. var timeDiffSecs = _sw.Elapsed.TotalSeconds;
  326. _sw.Restart();
  327. if (timeDiffSecs <= 0)
  328. {
  329. return;
  330. }
  331. if (_exception != null)
  332. {
  333. Console.WriteLine("Failed With:\r\n {0}", _exception.GetBaseException());
  334. _rateTimer.Change(-1, -1);
  335. _rateTimer.Dispose();
  336. _rateTimer = null;
  337. return;
  338. }
  339. Console.Clear();
  340. Console.WriteLine("Started {0} of {1} clients", _clientsRunning, _clients);
  341. Console.WriteLine("Total Rate: {0} (mps) = {1} (mps) * {2} (clients)", TotalRate, _rate, _clients);
  342. Console.WriteLine();
  343. // Sends
  344. var sends = Interlocked.Read(ref _sent);
  345. var sendsDiff = sends - _lastSendsCount;
  346. var sendsPerSec = sendsDiff / timeDiffSecs;
  347. _sendsPerSecond = sendsPerSec;
  348. _lastSendsCount = sends;
  349. Console.WriteLine("----- SENDS -----");
  350. var s1 = Math.Max(0, _rate - _sendsPerSecond);
  351. Console.WriteLine("SPS: {0:N3} (diff: {1:N3}, {2:N2}%)", _sendsPerSecond, s1, s1 * 100.0 / _rate);
  352. var s2 = Math.Max(0, _rate - _peakSendsPerSecond);
  353. Console.WriteLine("Peak SPS: {0:N3} (diff: {1:N2} {2:N2}%)", _peakSendsPerSecond, s2, s2 * 100.0 / _rate);
  354. var s3 = Math.Max(0, _rate - _avgSendsPerSecond);
  355. Console.WriteLine("Avg SPS: {0:N3} (diff: {1:N3} {2:N2}%)", _avgSendsPerSecond, s3, s3 * 100.0 / _rate);
  356. Console.WriteLine();
  357. if (sendsPerSec < long.MaxValue && sendsPerSec > _peakSendsPerSecond)
  358. {
  359. Interlocked.Exchange(ref _peakSendsPerSecond, sendsPerSec);
  360. }
  361. _avgSendsPerSecond = _avgLastSendsCount / (now - _avgCalcStart).TotalSeconds;
  362. // Receives
  363. var recv = Interlocked.Read(ref _received);
  364. var recvDiff = recv - _lastReceivedCount;
  365. var recvPerSec = recvDiff / timeDiffSecs;
  366. _receivesPerSecond = recvPerSec;
  367. _lastReceivedCount = recv;
  368. Console.WriteLine("----- RECEIVES -----");
  369. var d1 = Math.Max(0, TotalRate - _receivesPerSecond);
  370. Console.WriteLine("RPS: {0:N3} (diff: {1:N3}, {2:N2}%)", _receivesPerSecond, d1, d1 * 100.0 / TotalRate);
  371. var d2 = Math.Max(0, TotalRate - _peakReceivesPerSecond);
  372. Console.WriteLine("Peak RPS: {0:N3} (diff: {1:N3} {2:N2}%)", _peakReceivesPerSecond, d2, d2 * 100.0 / TotalRate);
  373. var d3 = Math.Max(0, TotalRate - _avgReceivesPerSecond);
  374. Console.WriteLine("Avg RPS: {0:N3} (diff: {1:N3} {2:N2}%)", _avgReceivesPerSecond, d3, d3 * 100.0 / TotalRate);
  375. var d4 = Math.Max(0, _sendsPerSecond - _receivesPerSecond);
  376. Console.WriteLine("Actual RPS: {0:N3} (diff: {1:N3} {2:N2}%)", _receivesPerSecond, d4, d4 * 100.0 / _sendsPerSecond);
  377. if (bus != null)
  378. {
  379. Console.WriteLine();
  380. Console.WriteLine("----- MESSAGE BUS -----");
  381. Console.WriteLine("Allocated Workers: {0}", bus.AllocatedWorkers);
  382. Console.WriteLine("BusyWorkers Workers: {0}", bus.BusyWorkers);
  383. }
  384. if (recvPerSec < long.MaxValue && recvPerSec > _peakReceivesPerSecond)
  385. {
  386. Interlocked.Exchange(ref _peakReceivesPerSecond, recvPerSec);
  387. }
  388. _avgReceivesPerSecond = _avgLastReceivedCount / (now - _avgCalcStart).TotalSeconds;
  389. // File.AppendAllText(resultsPath, String.Format("{0}, {1}, {2}, {3}\n", TotalRate, _receivesPerSecond, _peakReceivesPerSecond, _avgReceivesPerSecond));
  390. if (_runs > 0 && _runs % _stepInterval == 0)
  391. {
  392. _avgCalcStart = DateTime.UtcNow;
  393. Interlocked.Exchange(ref _avgLastReceivedCount, 0);
  394. Interlocked.Exchange(ref _avgLastSendsCount, 0);
  395. long old = Interlocked.Read(ref _rate);
  396. long @new = old + _step;
  397. while (Interlocked.Exchange(ref _rate, @new) == old) { }
  398. }
  399. _runs++;
  400. }
  401. finally
  402. {
  403. _measuringRate = false;
  404. }
  405. }, null, 1000, 1000);
  406. }
  407. public class StressConnection : PersistentConnection
  408. {
  409. }
  410. }
  411. public class MultGroupHub : Hub
  412. {
  413. public Task Do(int index)
  414. {
  415. // Groups.Add(Context.ConnectionId, "one").Wait();
  416. Groups.Add(Context.ConnectionId, "one").Wait();
  417. return Clients.Group("one").Do(index);
  418. }
  419. }
  420. public class User
  421. {
  422. public int Index { get; set; }
  423. public string Name { get; set; }
  424. public string Room { get; set; }
  425. }
  426. public class CountDown
  427. {
  428. private int _count;
  429. private ManualResetEventSlim _wh = new ManualResetEventSlim(false);
  430. public int Count
  431. {
  432. get
  433. {
  434. return _count;
  435. }
  436. }
  437. public CountDown(int count)
  438. {
  439. _count = count;
  440. }
  441. public void Dec()
  442. {
  443. if (Interlocked.Decrement(ref _count) == 0)
  444. {
  445. _wh.Set();
  446. }
  447. }
  448. public bool Wait(TimeSpan timeout)
  449. {
  450. return _wh.Wait(timeout);
  451. }
  452. internal void Reset()
  453. {
  454. _wh.Reset();
  455. }
  456. }
  457. }