forked from QuantConnect/Lean
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathIsolator.cs
139 lines (122 loc) · 5.31 KB
/
Isolator.cs
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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**********************************************************
* USING NAMESPACES
**********************************************************/
using System;
using System.Threading;
using System.Threading.Tasks;
using QuantConnect.Logging;
namespace QuantConnect
{
/********************************************************
* CLASS DEFINITIONS
*********************************************************/
/// <summary>
/// Isolator class - create a new instance of the algorithm and ensure it doesn't
/// exceed memory or time execution limits.
/// </summary>
public class Isolator
{
/********************************************************
* CLASS VARIABLES
*********************************************************/
/// <summary>
/// Algo cancellation controls - cancel source.
/// </summary>
public static CancellationTokenSource cancellation = new CancellationTokenSource();
/// <summary>
/// Algo cancellation controls - cancellation token for algorithm thread.
/// </summary>
public static CancellationToken cancelToken = new CancellationToken();
/********************************************************
* CLASS PROPERTIES
*********************************************************/
/// <summary>
/// Check if this task isolator is cancelled, and exit the analysis
/// </summary>
public static bool IsCancellationRequested
{
get
{
return cancelToken.IsCancellationRequested;
}
}
/********************************************************
* CLASS METHODS
*********************************************************/
/// <summary>
/// Reset the cancellation token variables for a new task:
/// </summary>
public static void ResetCancelToken()
{
cancellation = new CancellationTokenSource();
cancelToken = cancellation.Token;
}
/// <summary>
/// Execute a code block with a maximum limit on time and memory.
/// </summary>
/// <param name="timeSpan">Timeout in timespan</param>
/// <param name="codeBlock">Action codeblock to execute</param>
/// <param name="memoryCap">Maximum memory allocation, default 1024Mb</param>
/// <returns>True if algorithm exited successfully, false if cancelled because it exceeded limits.</returns>
public static bool ExecuteWithTimeLimit(TimeSpan timeSpan, Action codeBlock, long memoryCap = 1024)
{
var message = "";
var end = DateTime.Now + timeSpan;
var memoryLogger = DateTime.Now + TimeSpan.FromMinutes(1);
//Convert to bytes
memoryCap *= 1024 * 1024;
ResetCancelToken();
//Thread:
var task = Task.Factory.StartNew(codeBlock, cancelToken);
while (!task.IsCompleted && DateTime.Now < end)
{
var memoryUsed = GC.GetTotalMemory(false);
if (memoryUsed > memoryCap)
{
if (GC.GetTotalMemory(true) > memoryCap)
{
message = "Execution Security Error: Memory Usage Maxed Out - " + Math.Round(Convert.ToDouble(memoryCap / (1024 * 1024))) + "MB max.";
break;
}
}
if (DateTime.Now > memoryLogger)
{
if (memoryUsed > (memoryCap * 0.8))
{
memoryUsed = GC.GetTotalMemory(true);
Log.Error("Execution Security Error: Memory usage over 80% capacity.");
}
Console.WriteLine(DateTime.Now.ToString("u") + " Isolator.ExecuteWithTimeLimit(): Used: " + Math.Round(Convert.ToDouble(memoryUsed / (1024 * 1024))));
memoryLogger = DateTime.Now.AddMinutes(1);
}
Thread.Sleep(100);
}
if (task.IsCompleted == false && message == "")
{
message = "Execution Security Error: Operation timed out - " + timeSpan.TotalMinutes + " minutes max. Check for recursive loops.";
Console.WriteLine("Isolator.ExecuteWithTimeLimit(): " + message);
}
if (message != "")
{
cancellation.Cancel();
Log.Error("Security.ExecuteWithTimeLimit(): " + message);
throw new Exception(message);
}
return task.IsCompleted;
}
}
}