Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use large threads for processing Boogie programs #710

Merged
merged 10 commits into from
Mar 31, 2023
2 changes: 1 addition & 1 deletion Source/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<!-- Target framework and package configuration -->
<PropertyGroup>
<Version>2.16.3</Version>
<Version>2.16.4</Version>
<TargetFramework>net6.0</TargetFramework>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Authors>Boogie</Authors>
Expand Down
78 changes: 78 additions & 0 deletions Source/ExecutionEngine/CustomStackSizePoolTaskScheduler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace Microsoft.Boogie;

/// <summary>
/// Uses a thread pool of a configurable size, with threads with a configurable stack size,
/// to queue tasks.
/// </summary>
public class CustomStackSizePoolTaskScheduler : TaskScheduler, IDisposable
{
private readonly int threadCount;
private readonly ConcurrentQueue<Task> queue = new();
private readonly SemaphoreSlim isWorkAvailable = new(0);
private readonly Thread[] threads;

public static CustomStackSizePoolTaskScheduler Create(int stackSize, int threadCount)
{
return new CustomStackSizePoolTaskScheduler(stackSize, threadCount);
}

private CustomStackSizePoolTaskScheduler(int stackSize, int threadCount)
{
this.threadCount = threadCount;

threads = new Thread[this.threadCount];
for (int i = 0; i < threads.Length; i++)
{
threads[i] = new Thread(WorkLoop, stackSize) { IsBackground = true };
threads[i].Start();
}
}

protected override void QueueTask(Task task)
{
queue.Enqueue(task);
isWorkAvailable.Release(1);
}

protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
{
return TryExecuteTask(task);
}

public override int MaximumConcurrencyLevel => threadCount;

protected override IEnumerable<Task> GetScheduledTasks()
{
return queue;
}

private void WorkLoop()
{
while (true)
{
var task = BlockUntilTaskIsAvailable();
TryExecuteTask(task);
}
}

private Task BlockUntilTaskIsAvailable()
{
isWorkAvailable.Wait();
queue.TryDequeue(out var task);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth a comment saying we don't need to check the return value or if task is null because of the separate semaphore (too bad ConcurrentQueue doesn't have a plain blocking Dequeue method).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the implementation to use AsyncQueue, which has the behavior you were hoping for from ConcurrentQueue.

return task;
}

public void Dispose()
{
foreach (var thread in threads)
{
thread.Join();
}
}
}
10 changes: 7 additions & 3 deletions Source/ExecutionEngine/ExecutionEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,14 @@ public ProcessedProgram(Program program) : this(program, (_, _, _) => { }) {

public class ExecutionEngine : IDisposable
{
private static readonly CustomStackSizePoolTaskScheduler largeThreadScheduler = CustomStackSizePoolTaskScheduler.Create(16 * 1024 * 1024, Environment.ProcessorCount);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth a quick comment stating why we need such a deep stack, maybe point to #711

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

private static readonly TaskFactory largeThreadTaskFactory = new(
CancellationToken.None, TaskCreationOptions.DenyChildAttach,
TaskContinuationOptions.None, largeThreadScheduler);

static int autoRequestIdCount;

static readonly string AutoRequestIdPrefix = "auto_request_id_";
private const string AutoRequestIdPrefix = "auto_request_id_";

public static string FreshRequestId() {
var id = Interlocked.Increment(ref autoRequestIdCount);
Expand Down Expand Up @@ -870,7 +874,7 @@ private IObservable<IVerificationStatus> VerifyImplementationWithoutCaching(Proc
var verificationResult = new VerificationResult(impl, programId);

var batchCompleted = new Subject<(Split split, VCResult vcResult)>();
var completeVerification = Task.Run(async () =>
var completeVerification = largeThreadTaskFactory.StartNew(async () =>
{
var vcgen = new VCGen(processedProgram.Program, checkerPool);
vcgen.CachingActionCounts = stats.CachingActionCounts;
Expand Down Expand Up @@ -931,7 +935,7 @@ private IObservable<IVerificationStatus> VerifyImplementationWithoutCaching(Proc

batchCompleted.OnCompleted();
return new Completed(verificationResult);
}, cancellationToken);
}, cancellationToken).Unwrap();

return batchCompleted.Select(t => new BatchCompleted(t.split, t.vcResult)).Merge<IVerificationStatus>(Observable.FromAsync(() => completeVerification));
}
Expand Down
42 changes: 42 additions & 0 deletions Test/stackoverflow/nesting.bpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
// RUN: %parallel-boogie "%s" > "%t"
// RUN: %diff "%s.expect" "%t"

type Ref;
type Field A B;
type HeapType = <A, B> [Ref, Field A B]B; // Using type parameters and the ==> operator can trigger the OpTypeEraser visitor which can cause stack overflows.

procedure foo(n: int)
requires true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true
|| true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true ||
Expand All @@ -14,6 +19,43 @@ procedure foo(n: int)
true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true
|| true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true || true ||
n == 2;
requires true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==>
true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true
==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true ==> true;

{
if (n == 2) {
if (n == 2) {
Expand Down
36 changes: 18 additions & 18 deletions Test/stackoverflow/nesting.bpl.expect
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
nesting.bpl(46,35): Error: this assertion could not be proved
nesting.bpl(88,35): Error: this assertion could not be proved
Execution trace:
nesting.bpl(18,3): anon0
nesting.bpl(19,5): anon17_Then
nesting.bpl(20,7): anon18_Then
nesting.bpl(21,9): anon19_Then
nesting.bpl(22,11): anon20_Then
nesting.bpl(23,13): anon21_Then
nesting.bpl(24,15): anon22_Then
nesting.bpl(25,17): anon23_Then
nesting.bpl(26,19): anon24_Then
nesting.bpl(27,21): anon25_Then
nesting.bpl(28,23): anon26_Then
nesting.bpl(29,25): anon27_Then
nesting.bpl(30,27): anon28_Then
nesting.bpl(31,29): anon29_Then
nesting.bpl(32,31): anon30_Then
nesting.bpl(33,33): anon31_Then
nesting.bpl(46,35): anon32_Then
nesting.bpl(60,3): anon0
nesting.bpl(61,5): anon17_Then
nesting.bpl(62,7): anon18_Then
nesting.bpl(63,9): anon19_Then
nesting.bpl(64,11): anon20_Then
nesting.bpl(65,13): anon21_Then
nesting.bpl(66,15): anon22_Then
nesting.bpl(67,17): anon23_Then
nesting.bpl(68,19): anon24_Then
nesting.bpl(69,21): anon25_Then
nesting.bpl(70,23): anon26_Then
nesting.bpl(71,25): anon27_Then
nesting.bpl(72,27): anon28_Then
nesting.bpl(73,29): anon29_Then
nesting.bpl(74,31): anon30_Then
nesting.bpl(75,33): anon31_Then
nesting.bpl(88,35): anon32_Then

Boogie program verifier finished with 0 verified, 1 error