Skip to content

Commit

Permalink
[C# backend] Enforce memory limit
Browse files Browse the repository at this point in the history
Track memory usage and enforce memory limit using CLI option --memout <double>
  • Loading branch information
aman-goel committed May 20, 2024
1 parent 43a9803 commit e30dd73
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ private void EmitTestReport()
}

Console.WriteLine(GlobalTestReport.GetText(_checkerConfiguration, "..."));
Console.WriteLine($"... Elapsed {Profiler.Results()} sec.");
Console.WriteLine($"... Elapsed {Profiler.GetElapsedTime():0.##} sec and used {Profiler.GetMaxMemoryUsage():0.##} GB.");

if (GlobalTestReport.InternalErrors.Count > 0)
{
Expand Down
42 changes: 28 additions & 14 deletions Src/PChecker/CheckerCore/SystematicTesting/TestingEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -362,20 +362,28 @@ public void Run()
}
catch (AggregateException aex)
{
aex.Handle((ex) =>
if (aex.InnerException is OutOfMemoryException)
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.StackTrace);
return true;
});

if (aex.InnerException is FileNotFoundException)
{
Error.ReportAndExit($"{aex.InnerException.Message}");
Logger.WriteLine("... Checker ran out of memory.");
}
else
{
aex.Handle((ex) =>
{
Debug.WriteLine(ex.Message);
Debug.WriteLine(ex.StackTrace);
return true;
});

if (aex.InnerException is FileNotFoundException)
{
Error.ReportAndExit($"{aex.InnerException.Message}");
}

Error.ReportAndExit("Exception thrown during testing outside the context of an actor, " +
"possibly in a test method. Please use /debug /v:2 to print more information.");

Error.ReportAndExit("Exception thrown during testing outside the context of an actor, " +
"possibly in a test method. Please use /debug /v:2 to print more information.");
}
}
catch (Exception ex)
{
Expand Down Expand Up @@ -422,11 +430,17 @@ _checkerConfiguration.SchedulingStrategy is "probabilistic" ||
break;
}

if (Profiler.GetCurrentMemoryUsage() > _checkerConfiguration.MemoryLimit)
{
throw new OutOfMemoryException();
}

// Runs a new testing schedule.
RunNextIteration(i);

if (IsReplayModeEnabled || (!_checkerConfiguration.PerformFullExploration &&
TestReport.NumOfFoundBugs > 0) || !Strategy.PrepareForNextIteration())
TestReport.NumOfFoundBugs > 0) ||
!Strategy.PrepareForNextIteration())
{
break;
}
Expand Down Expand Up @@ -620,7 +634,7 @@ public string GetReport()
report.AppendFormat("... Reproduced {0} bug{1}.", TestReport.NumOfFoundBugs,
TestReport.NumOfFoundBugs == 1 ? string.Empty : "s");
report.AppendLine();
report.Append($"... Elapsed {Profiler.Results()} sec.");
report.Append($"... Elapsed {Profiler.GetElapsedTime():0.##} sec and used {Profiler.GetMaxMemoryUsage():0.##} GB.");
return report.ToString();
}

Expand Down Expand Up @@ -744,7 +758,7 @@ public void TryEmitTraces(string directory, string file)
}
}

Logger.WriteLine($"... Elapsed {Profiler.Results()} sec.");
Logger.WriteLine($"... Elapsed {Profiler.GetElapsedTime():0.##} sec and used {Profiler.GetMaxMemoryUsage():0.##} GB.");
}

/// <summary>
Expand Down
26 changes: 24 additions & 2 deletions Src/PChecker/CheckerCore/Utilities/Profiler.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Diagnostics;
using PChecker.IO.Logging;

namespace PChecker.Utilities
{
Expand All @@ -11,6 +13,7 @@ namespace PChecker.Utilities
public class Profiler
{
private Stopwatch StopWatch;
private static double maxMemoryUsed = 0.0;

/// <summary>
/// Starts measuring execution time.
Expand All @@ -33,9 +36,28 @@ public void StopMeasuringExecutionTime()
}

/// <summary>
/// Returns profilling results.
/// Returns profiling results.
/// </summary>
public double Results() =>
public double GetElapsedTime() =>
StopWatch != null ? StopWatch.Elapsed.TotalSeconds : 0;

/// <summary>
/// Get memory usage in gigabytes.
/// </summary>
public double GetCurrentMemoryUsage()
{
double memUsed = GC.GetTotalMemory(false) / 1024.0 / 1024.0 / 1024.0;
if (memUsed > maxMemoryUsed)
maxMemoryUsed = memUsed;
return memUsed;
}

/// <summary>
/// Get max memory usage in gigabytes.
/// </summary>
public static double GetMaxMemoryUsage()
{
return maxMemoryUsed;
}
}
}
2 changes: 1 addition & 1 deletion Src/PCompiler/PCommandLine/Options/PCheckerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ internal PCheckerOptions()

var basicGroup = Parser.GetOrCreateGroup("Basic", "Basic options");
basicGroup.AddArgument("timeout", "t", "Timeout in seconds (disabled by default)", typeof(uint));
basicGroup.AddArgument("memout", null, "Memory limit in Giga bytes (disabled by default)", typeof(double)).IsHidden = true;
basicGroup.AddArgument("memout", "m", "Memory limit in Giga bytes (disabled by default)", typeof(double));
basicGroup.AddArgument("outdir", "o", "Dump output to directory (absolute or relative path)");
basicGroup.AddArgument("verbose", "v", "Enable verbose log output during exploration", typeof(bool));
basicGroup.AddArgument("debug", "d", "Enable debugging", typeof(bool)).IsHidden = true;
Expand Down

0 comments on commit e30dd73

Please sign in to comment.