-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathProfilerResultQueue.cs
More file actions
94 lines (85 loc) · 3.12 KB
/
Copy pathProfilerResultQueue.cs
File metadata and controls
94 lines (85 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using NLog;
using Utils.General;
using VRage.Collections;
namespace Profiler.Core
{
/// <summary>
/// Receives ProfilerResults from patched methods & distributes them to multiple observers in a separate thread
/// </summary>
public static class ProfilerResultQueue
{
static readonly ILogger Log = LogManager.GetCurrentClassLogger();
static readonly ConcurrentQueue<ProfilerResult> _profilerResults;
static readonly ConcurrentCachingList<IProfiler> _profilers;
static ProfilerResultQueue()
{
_profilerResults = new ConcurrentQueue<ProfilerResult>();
_profilers = new ConcurrentCachingList<IProfiler>();
}
/// <summary>
/// Add an profiler and, when the returned IDisposable object is disposed, remove the profiler from the profiler.
/// </summary>
/// <param name="observer">Observer to add/remove.</param>
/// <returns>IDisposable object that, when disposed, removes the profiler from the profiler.</returns>
public static IDisposable Profile(IProfiler observer)
{
AddProfiler(observer);
return new ActionDisposable(() => RemoveProfiler(observer));
}
internal static void Enqueue(in ProfilerResult result)
{
_profilerResults.Enqueue(result);
}
internal static async Task Start(CancellationToken canceller)
{
while (!canceller.IsCancellationRequested)
{
try
{
_profilers.ApplyChanges();
var dequeued = false;
while (_profilerResults.TryDequeue(out var result))
{
dequeued = true;
foreach (var profiler in _profilers)
{
try
{
profiler.ReceiveProfilerResult(result);
}
catch (Exception e)
{
Log.Error($"{profiler}: {e.Message}");
}
}
}
if (!dequeued)
{
await Task.Delay(TimeSpan.FromSeconds(.1f), canceller);
}
}
catch (OperationCanceledException) when (canceller.IsCancellationRequested)
{
break;
}
catch (Exception e)
{
Log.Warn(e, "Profiler consumer loop crashed; restarting after delay");
await Task.Delay(TimeSpan.FromSeconds(1), canceller);
}
}
}
static void AddProfiler(IProfiler profiler)
{
_profilers.Add(profiler);
}
static void RemoveProfiler(IProfiler profiler)
{
_profilers.Remove(profiler);
}
}
}