-
Notifications
You must be signed in to change notification settings - Fork 0
/
Profiler.cs
192 lines (167 loc) · 6.5 KB
/
Profiler.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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
namespace Auto_Statistic
{
partial class Profiler
{
private readonly Process curProcess;
private const int startInterval = 10;
private const int interval = 100;
private readonly int timeLimit = 0;
private readonly bool prohibitUsePageFile;
private readonly string historySavePath;
private static readonly double criticalAvailableMemSizeMB = 0.05 * FullSystemInfo.GeneralRamInfo.totalRamSizeMB;
private const int maxMemHistorySize = 1024 * 32; // по 32Б
private readonly ConcurrentQueue<StatisticUnit> History = new ConcurrentQueue<StatisticUnit>();
private ProfilerResultStatistic evalStat;
private bool processRunning = false;
private long statCount;
private bool processCanceled = false;
private bool exceededMemory = false;
private float curProcMem = 0;
private float curProcCPU = 0;
private double lastProc = 0;
private double lastTotal = 0;
public Profiler(string path, string args, string historySavePath, bool prohibitUsePageFile = true, int timeLimit = 0)
{
curProcess = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = path,
Arguments = args,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
},
EnableRaisingEvents = true
};
curProcess.ErrorDataReceived += ErrorReceived;
curProcess.OutputDataReceived += DataReceived;
this.historySavePath = historySavePath;
this.prohibitUsePageFile = prohibitUsePageFile;
if (timeLimit == 0) this.timeLimit = -1;
else this.timeLimit = 1000 * timeLimit;
}
public ProfilerResultStatistic StartProcess()
{
processCanceled = false;
processRunning = true;
exceededMemory = false;
statCount = 0;
evalStat = new ProfilerResultStatistic();
if (File.Exists(historySavePath)) File.SetAttributes(historySavePath, FileAttributes.Normal);
using (StreamWriter fs = new StreamWriter(File.Create(historySavePath), Encoding.GetEncoding(1251)))
{
fs.WriteLine("Time;CPU usage;RAM usage");
}
Timer statTimer = new Timer(GetCurStat, null, 0, startInterval);
curProcess.Start();
curProcess.BeginErrorReadLine();
curProcess.BeginOutputReadLine();
curProcess.PriorityClass = ProcessPriorityClass.BelowNormal;
curProcess.WaitForExit(500);
statTimer.Change(0, interval);
curProcess.WaitForExit(timeLimit);
if (!curProcess.HasExited)
{
CancelProcess();
}
evalStat.execTime = (curProcess.ExitTime - curProcess.StartTime).TotalSeconds;
statTimer.Dispose();
SaveStoredStats();
processRunning = false;
return evalStat;
}
void DataReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
evalStat.programResult.AppendLine(e.Data);
}
void ErrorReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data != null)
evalStat.programResult.AppendLine(e.Data);
}
public bool IsProcessRunning()
{
return processRunning;
}
public bool IsProcessCanceled()
{
return processCanceled;
}
public bool IsExceededMemory()
{
return exceededMemory;
}
public void CancelProcess()
{
try
{
curProcess.Kill();
processCanceled = true;
}
catch (Exception exc)
{
// Process already stop.
Debug.WriteLine(exc.ToString());
}
}
private void GetCurStat(object obj = null)
{
try
{
curProcess.Refresh();
var newProcessTime = curProcess.TotalProcessorTime.TotalSeconds;
var newTotalTime = (DateTime.Now - curProcess.StartTime).TotalSeconds;
if (prohibitUsePageFile && SystemStateInfo.AvailableRamSize() < criticalAvailableMemSizeMB)
{
CancelProcess();
exceededMemory = true;
return;
}
curProcMem = (float)((double)curProcess.WorkingSet64 / 1024 / 1024);
curProcCPU = (float)((newProcessTime - lastProc) / Environment.ProcessorCount / (newTotalTime - lastTotal));
lastTotal = newTotalTime;
lastProc = newProcessTime;
if (curProcCPU < 0 || curProcCPU > 1 || double.IsNaN(curProcCPU)) curProcCPU = evalStat.avgCpuUsage;
if (curProcCPU > evalStat.maxCpuUsage) evalStat.maxCpuUsage = curProcCPU;
statCount++;
evalStat.avgCpuUsage += (curProcCPU - evalStat.avgCpuUsage) / statCount;
if (curProcMem > evalStat.maxMemUsage) evalStat.maxMemUsage = curProcMem;
History.Enqueue(new StatisticUnit(curProcCPU, curProcMem, newTotalTime));
if (History.Count >= maxMemHistorySize) SaveStoredStats();
}
catch (Exception exc)
{
// Process not running.
Debug.WriteLine(exc.ToString());
}
}
private void SaveStoredStats()
{
using (StreamWriter fs = new StreamWriter(File.Open(historySavePath, FileMode.Append), Encoding.GetEncoding(1251)))
{
while (History.TryDequeue(out var stat))
{
fs.WriteLine(stat.time.ToString("F") + ";" + stat.cpuUsage.ToString("P2") + ";" + stat.ramUsage.ToString("F"));
}
}
}
public float GetCurProcCpuUsage()
{
return curProcCPU;
}
public float GetCurProcMemUsage()
{
return curProcMem;
}
}
}