public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable<string> executionArguments = null) { var process = new DifferentUserProcessExecutor(fileName, Environment.UserDomainName, UserName, Password); process.SetTextToWrite(inputData); var executorInfo = process.Start(timeLimit, memoryLimit); var result = new ProcessExecutionResult { ReceivedOutput = executorInfo.StandardOutputContent, ErrorOutput = executorInfo.StandardErrorContent, ExitCode = process.Process.ExitCode, Type = ProcessExecutionResultType.Success, TimeWorked = process.Process.ExitTime - process.Process.StartTime, MemoryUsed = executorInfo.MaxMemoryUsed, PrivilegedProcessorTime = process.Process.PrivilegedProcessorTime, UserProcessorTime = process.Process.UserProcessorTime, }; if (executorInfo.ProcessKilledBecauseOfTimeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(executorInfo.StandardErrorContent)) { result.Type = ProcessExecutionResultType.RunTimeError; } return result; }
protected TestResult ExecuteAndCheckTest(TestContext test, ProcessExecutionResult processExecutionResult, IChecker checker, string receivedOutput) { var testResult = new TestResult { Id = test.Id, TimeUsed = (int)processExecutionResult.TimeWorked.TotalMilliseconds, MemoryUsed = (int)processExecutionResult.MemoryUsed, }; if (processExecutionResult.Type == ProcessExecutionResultType.RunTimeError) { testResult.ResultType = TestRunResultType.RunTimeError; testResult.ExecutionComment = processExecutionResult.ErrorOutput.MaxLength(2048); // Trimming long error texts } else if (processExecutionResult.Type == ProcessExecutionResultType.TimeLimit) { testResult.ResultType = TestRunResultType.TimeLimit; } else if (processExecutionResult.Type == ProcessExecutionResultType.MemoryLimit) { testResult.ResultType = TestRunResultType.MemoryLimit; } else if (processExecutionResult.Type == ProcessExecutionResultType.Success) { var checkerResult = checker.Check(test.Input, receivedOutput, test.Output, test.IsTrialTest); if (checkerResult.IsCorrect) { testResult.ResultType = TestRunResultType.CorrectAnswer; } else { testResult.ResultType = TestRunResultType.WrongAnswer; } // TODO: Do something with checkerResult.ResultType testResult.CheckerComment = checkerResult.CheckerDetails; } else { throw new ArgumentOutOfRangeException("processExecutionResult", "Invalid ProcessExecutionResultType value."); } return testResult; }
private static void UpdateExecutionTime(string timeMeasurementFilePath, ProcessExecutionResult processExecutionResult, int timeLimit) { if (File.Exists(timeMeasurementFilePath)) { long timeInNanoseconds; var timeMeasurementFileContent = File.ReadAllText(timeMeasurementFilePath); if (long.TryParse(timeMeasurementFileContent, out timeInNanoseconds)) { processExecutionResult.TimeWorked = TimeSpan.FromMilliseconds((double)timeInNanoseconds / 1000000); if (processExecutionResult.Type == ProcessExecutionResultType.TimeLimit && processExecutionResult.TimeWorked.TotalMilliseconds <= timeLimit) { // The time from the time measurement file is under the time limit processExecutionResult.Type = ProcessExecutionResultType.Success; } } File.Delete(timeMeasurementFilePath); } }
// TODO: double check and maybe change order of parameters public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable<string> executionArguments = null) { var result = new ProcessExecutionResult { Type = ProcessExecutionResultType.Success }; var workingDirectory = new FileInfo(fileName).DirectoryName; using (var restrictedProcess = new RestrictedProcess(fileName, workingDirectory, executionArguments, Math.Max(4096, (inputData.Length * 2) + 4))) { // Write to standard input using another thread restrictedProcess.StandardInput.WriteLineAsync(inputData).ContinueWith( delegate { // ReSharper disable once AccessToDisposedClosure if (!restrictedProcess.IsDisposed) { // ReSharper disable once AccessToDisposedClosure restrictedProcess.StandardInput.FlushAsync().ContinueWith( delegate { restrictedProcess.StandardInput.Close(); }); } }); // Read standard output using another thread to prevent process locking (waiting us to empty the output buffer) var processOutputTask = restrictedProcess.StandardOutput.ReadToEndAsync().ContinueWith( x => { result.ReceivedOutput = x.Result; }); // Read standard error using another thread var errorOutputTask = restrictedProcess.StandardError.ReadToEndAsync().ContinueWith( x => { result.ErrorOutput = x.Result; }); // Read memory consumption every few milliseconds to determine the peak memory usage of the process const int TimeIntervalBetweenTwoMemoryConsumptionRequests = 45; var memoryTaskCancellationToken = new CancellationTokenSource(); var memoryTask = Task.Run( () => { while (true) { // ReSharper disable once AccessToDisposedClosure var peakWorkingSetSize = restrictedProcess.PeakWorkingSetSize; result.MemoryUsed = Math.Max(result.MemoryUsed, peakWorkingSetSize); if (memoryTaskCancellationToken.IsCancellationRequested) { return; } Thread.Sleep(TimeIntervalBetweenTwoMemoryConsumptionRequests); } }, memoryTaskCancellationToken.Token); // Start the process restrictedProcess.Start(timeLimit, memoryLimit); // Wait the process to complete. Kill it after (timeLimit * 1.5) milliseconds if not completed. // We are waiting the process for more than defined time and after this we compare the process time with the real time limit. var exited = restrictedProcess.WaitForExit((int)(timeLimit * 1.5)); if (!exited) { restrictedProcess.Kill(); result.Type = ProcessExecutionResultType.TimeLimit; } // Close the memory consumption check thread memoryTaskCancellationToken.Cancel(); try { // To be sure that memory consumption will be evaluated correctly memoryTask.Wait(TimeIntervalBetweenTwoMemoryConsumptionRequests); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process error output try { errorOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process output try { processOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } Debug.Assert(restrictedProcess.HasExited, "Restricted process didn't exit!"); // Report exit code and total process working time result.ExitCode = restrictedProcess.ExitCode; result.TimeWorked = restrictedProcess.ExitTime - restrictedProcess.StartTime; result.PrivilegedProcessorTime = restrictedProcess.PrivilegedProcessorTime; result.UserProcessorTime = restrictedProcess.UserProcessorTime; } if (result.TotalProcessorTime.TotalMilliseconds > timeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(result.ErrorOutput)) { result.Type = ProcessExecutionResultType.RunTimeError; } if (result.MemoryUsed > memoryLimit) { result.Type = ProcessExecutionResultType.MemoryLimit; } return result; }
private void ProcessTests(ProcessExecutionResult processExecutionResult, ExecutionContext executionContext, ExecutionResult result) { var jsonResult = JsonExecutionResult.Parse(processExecutionResult.ReceivedOutput, true, true); var index = 0; result.TestResults = new List<TestResult>(); foreach (var test in executionContext.Tests) { var testResult = new TestResult { Id = test.Id, TimeUsed = (int)processExecutionResult.TimeWorked.TotalMilliseconds, MemoryUsed = (int)processExecutionResult.MemoryUsed, }; if (jsonResult.PassingIndexes.Contains(index)) { testResult.ResultType = TestRunResultType.CorrectAnswer; } else { testResult.ResultType = TestRunResultType.WrongAnswer; testResult.CheckerDetails = new CheckerDetails { Comment = "Test failed." }; } result.TestResults.Add(testResult); index++; } }
public ProcessExecutionResult Execute(string fileName, string inputData, int timeLimit, int memoryLimit, IEnumerable<string> executionArguments = null) { var result = new ProcessExecutionResult { Type = ProcessExecutionResultType.Success }; var workingDirectory = new FileInfo(fileName).DirectoryName; var processStartInfo = new ProcessStartInfo(fileName) { Arguments = executionArguments == null ? string.Empty : string.Join(" ", executionArguments), WindowStyle = ProcessWindowStyle.Hidden, CreateNoWindow = true, ErrorDialog = false, UseShellExecute = false, RedirectStandardError = true, RedirectStandardInput = true, RedirectStandardOutput = true, WorkingDirectory = workingDirectory }; using (var process = System.Diagnostics.Process.Start(processStartInfo)) { if (process == null) { throw new Exception($"Could not start process: {fileName}!"); } process.PriorityClass = ProcessPriorityClass.High; // Write to standard input using another thread process.StandardInput.WriteLineAsync(inputData).ContinueWith( delegate { // ReSharper disable once AccessToDisposedClosure process.StandardInput.FlushAsync().ContinueWith( delegate { process.StandardInput.Close(); }); }); // Read standard output using another thread to prevent process locking (waiting us to empty the output buffer) var processOutputTask = process.StandardOutput.ReadToEndAsync().ContinueWith( x => { result.ReceivedOutput = x.Result; }); // Read standard error using another thread var errorOutputTask = process.StandardError.ReadToEndAsync().ContinueWith( x => { result.ErrorOutput = x.Result; }); // Read memory consumption every few milliseconds to determine the peak memory usage of the process const int TimeIntervalBetweenTwoMemoryConsumptionRequests = 45; var memoryTaskCancellationToken = new CancellationTokenSource(); var memoryTask = Task.Run( () => { while (true) { // ReSharper disable once AccessToDisposedClosure if (process.HasExited) { return; } // ReSharper disable once AccessToDisposedClosure var peakWorkingSetSize = process.PeakWorkingSet64; result.MemoryUsed = Math.Max(result.MemoryUsed, peakWorkingSetSize); if (memoryTaskCancellationToken.IsCancellationRequested) { return; } Thread.Sleep(TimeIntervalBetweenTwoMemoryConsumptionRequests); } }, memoryTaskCancellationToken.Token); // Wait the process to complete. Kill it after (timeLimit * 1.5) milliseconds if not completed. // We are waiting the process for more than defined time and after this we compare the process time with the real time limit. var exited = process.WaitForExit((int)(timeLimit * 1.5)); if (!exited) { // Double check if the process has exited before killing it if (!process.HasExited) { process.Kill(); // Approach: https://msdn.microsoft.com/en-us/library/system.diagnostics.process.kill(v=vs.110).aspx#Anchor_2 process.WaitForExit(); } result.Type = ProcessExecutionResultType.TimeLimit; } // Close the memory consumption check thread memoryTaskCancellationToken.Cancel(); try { // To be sure that memory consumption will be evaluated correctly memoryTask.Wait(TimeIntervalBetweenTwoMemoryConsumptionRequests); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process error output try { errorOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } // Close the task that gets the process output try { processOutputTask.Wait(100); } catch (AggregateException ex) { logger.Warn("AggregateException caught.", ex.InnerException); } Debug.Assert(process.HasExited, "Standard process didn't exit!"); // Report exit code and total process working time result.ExitCode = process.ExitCode; result.TimeWorked = process.ExitTime - process.StartTime; result.PrivilegedProcessorTime = process.PrivilegedProcessorTime; result.UserProcessorTime = process.UserProcessorTime; } if (result.TotalProcessorTime.TotalMilliseconds > timeLimit) { result.Type = ProcessExecutionResultType.TimeLimit; } if (!string.IsNullOrEmpty(result.ErrorOutput)) { result.Type = ProcessExecutionResultType.RunTimeError; } if (result.MemoryUsed > memoryLimit) { result.Type = ProcessExecutionResultType.MemoryLimit; } return result; }