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

Support saturating the ForkJoinPool via a property #3026

Closed
2 tasks done
mpkorstanje opened this issue Sep 8, 2022 · 3 comments · Fixed by #3044
Closed
2 tasks done

Support saturating the ForkJoinPool via a property #3026

mpkorstanje opened this issue Sep 8, 2022 · 3 comments · Fixed by #3044

Comments

@mpkorstanje
Copy link
Contributor

mpkorstanje commented Sep 8, 2022

Currently JUnit Jupiter does not guarantee that the number of concurrently executing tests will not exceed the configured parallelism. The advice is to provide a custom ParallelExecutionConfigurationStrategy. And through #2792 it is now possible to configure whether or not the pool should be saturated.

However implementing a custom strategy to replicate the behaviour of the existing fixed or dynamic strategy with saturation is non-trivial. On the other hand, ensuring a maximum number of concurrent tests is a common need e.g: #2545, #1675, #1858, SeleniumHQ/selenium#10113, cucumber/cucumber-jvm#2512, cucumber/cucumber-jvm#2602.

We can stream line the experience for end-users by providing *.dynamic.saturate and *.fixed.saturate properties. When set to true the DefaultParallelExecutionConfiguration.getSaturatePredicate would return __ -> true and null otherwise.

Deliverables

  • Update DefaultParallelExecutionConfigurationStrategy to read *.dynamic.saturate and *.fixed.saturate properties.
  • Update the documentation to explain this.
@marcphilipp
Copy link
Member

Team Decision: Follow the proposal.

@marcphilipp
Copy link
Member

@mpkorstanje Thanks for bringing this up! Could you please add the missing documentation to the PR so we can include it in 5.9.1? 🙂

mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 9, 2022
The JUnit Platform now supports saturating the ForkJoinPool via a property.
Enabling this property will limit the number of concurrently executing tests
will to the configured parallelism even when some are blocked.

For JUnit Jupiter this can be enabled by through the
`junit.jupiter.execution.parallel.config.dynamic.saturate` and
`junit.jupiter.execution.parallel.config.fixed.saturate` configuration
properties.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 9, 2022
The JUnit Platform now supports saturating the ForkJoinPool via a property.
Enabling this property will limit the number of concurrently executing tests
will to the configured parallelism even when some are blocked.

For JUnit Jupiter this can be enabled by through the
`junit.jupiter.execution.parallel.config.dynamic.saturate` and
`junit.jupiter.execution.parallel.config.fixed.saturate` configuration
properties.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 9, 2022
The JUnit Platform now supports saturating the ForkJoinPool via a property.
Enabling this property will limit the number of concurrently executing tests
will to the configured parallelism even when some are blocked.

For JUnit Jupiter this can be enabled by through the
`junit.jupiter.execution.parallel.config.dynamic.saturate` and
`junit.jupiter.execution.parallel.config.fixed.saturate` configuration
properties.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
@marcphilipp marcphilipp removed this from the 5.9.1 milestone Sep 16, 2022
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
The JUnit Platform now supports saturating the ForkJoinPool via a property.
Enabling this property will limit the number of concurrently executing tests
will to the configured parallelism even when some are blocked.

For JUnit Jupiter this can be enabled by through the
`junit.jupiter.execution.parallel.config.dynamic.saturate` and
`junit.jupiter.execution.parallel.config.fixed.saturate` configuration
properties.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
The JUnit Platform now supports saturating the ForkJoinPool via a property.
Enabling this property will limit the number of concurrently executing tests
will to the configured parallelism even when some are blocked.

For JUnit Jupiter this can be enabled by through the
`junit.jupiter.execution.parallel.config.dynamic.saturate` and
`junit.jupiter.execution.parallel.config.fixed.saturate` configuration
properties.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
JUnit Jupiter (and The JUnit Platform) now support limiting the
maximum number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size` property.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum
pool size. While the number of concurrently executing tests may exceed the
configured parallelism when tests become blocked, it will not exceed the
maximum pool size.

With the following configuration:

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=2
```

This example will report between 2-5 tests running concurrently.

```java
class ExampleTest {

    private static final AtomicInteger running = new AtomicInteger();

    @beforeeach
    void increment() {
        System.out.println("Running " + running.incrementAndGet());
    }

    @AfterEach
    void decrement() {
        running.decrementAndGet();
    }

    static IntStream numbers() {
        return IntStream.range(0, 1000);
    }

    @ParameterizedTest
    @MethodSource("numbers")
    void test(int i) throws ExecutionException, InterruptedException {
        Runnable sleep = () -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        ForkJoinPool.commonPool().submit(sleep).get();
    }
}
```

By also configuring the `max-pool-size` we can ensure the concurrently
executing test does not exceed the configured 2.

```properties
junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
```

Additionally, because the `ForkJoinPool` will by default reject tasks that
would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has been
added and will default to `true`. There appears to be no reason to ever set
this `false` but it is there should someone depend on the old behaviour.

These changes were intentionally not made to the `dynamic` strategy to limit
the scope of this pull request. While I can reasonably predict what behaviour
users of the `fixed` strategy might expect, I can not say the same about the
`dynamic` strategy.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
JUnit Jupiter (and The JUnit Platform) now support limiting the
maximum number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size` property.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum
pool size. While the number of concurrently executing tests may exceed the
configured parallelism when tests become blocked, it will not exceed the
maximum pool size.

With the following configuration:

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=2
```

This example will report between 2-5 tests running concurrently.

```java
class ExampleTest {

    private static final AtomicInteger running = new AtomicInteger();

    @beforeeach
    void increment() {
        System.out.println("Running " + running.incrementAndGet());
    }

    @AfterEach
    void decrement() {
        running.decrementAndGet();
    }

    static IntStream numbers() {
        return IntStream.range(0, 1000);
    }

    @ParameterizedTest
    @MethodSource("numbers")
    void test(int i) throws ExecutionException, InterruptedException {
        Runnable sleep = () -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        ForkJoinPool.commonPool().submit(sleep).get();
    }
}
```

By also configuring the `max-pool-size` we can ensure the concurrently
executing test does not exceed the configured 2.

```properties
junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
```

Additionally, because the `ForkJoinPool` will by default reject tasks that
would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has been
added and will default to `true`. There appears to be no reason to ever set
this `false` but it is there should someone depend on the old behaviour.

These changes were intentionally not made to the `dynamic` strategy to limit
the scope of this pull request. While I can reasonably predict what behaviour
users of the `fixed` strategy might expect, I can not say the same about the
`dynamic` strategy.

Fixes: junit-team#2545
Fixes: junit-team#1858
Fixes: junit-team#3026
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
JUnit Jupiter (and The JUnit Platform) now support limiting the
maximum number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size` property.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum
pool size. While the number of concurrently executing tests may exceed the
configured parallelism when tests become blocked, it will not exceed the
maximum pool size.

With the following configuration:

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=2
```

This example will report between 2-5 tests running concurrently.

```java
class ExampleTest {

    private static final AtomicInteger running = new AtomicInteger();

    @beforeeach
    void increment() {
        System.out.println("Running " + running.incrementAndGet());
    }

    @AfterEach
    void decrement() {
        running.decrementAndGet();
    }

    static IntStream numbers() {
        return IntStream.range(0, 1000);
    }

    @ParameterizedTest
    @MethodSource("numbers")
    void test(int i) throws ExecutionException, InterruptedException {
        Runnable sleep = () -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        ForkJoinPool.commonPool().submit(sleep).get();
    }
}
```

By also configuring the `max-pool-size` we can ensure the concurrently
executing test does not exceed the configured 2.

```properties
junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
```

Additionally, because the `ForkJoinPool` will by default reject tasks that
would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has been
added and will default to `true`. There appears to be no reason to ever set
this `false` but it is there should someone depend on the old behaviour.

These changes were intentionally not made to the `dynamic` strategy to limit
the scope of this pull request. While I can reasonably predict what behaviour
users of the `fixed` strategy might expect, I can not say the same about the
`dynamic` strategy.

Fixes: junit-team#3026
Fixes: junit-team#2545
Fixes: junit-team#1858
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
JUnit Jupiter (and The JUnit Platform) now support limiting the
maximum number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size` property.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum
pool size. While the number of concurrently executing tests may exceed the
configured parallelism when tests become blocked, it will not exceed the
maximum pool size.

With the following configuration:

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=2
```

This example will report between 2-5 tests running concurrently.

```java
class ExampleTest {

    private static final AtomicInteger running = new AtomicInteger();

    @beforeeach
    void increment() {
        System.out.println("Running " + running.incrementAndGet());
    }

    @AfterEach
    void decrement() {
        running.decrementAndGet();
    }

    static IntStream numbers() {
        return IntStream.range(0, 1000);
    }

    @ParameterizedTest
    @MethodSource("numbers")
    void test(int i) throws ExecutionException, InterruptedException {
        Runnable sleep = () -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        ForkJoinPool.commonPool().submit(sleep).get();
    }
}
```

By also configuring the `max-pool-size` we can ensure the concurrently
executing test does not exceed the configured 2.

```properties
junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
```

Additionally, because the `ForkJoinPool` will by default reject tasks that
would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has been
added and will default to `true`. There appears to be no reason to ever set
this `false` but it is there should someone depend on the old behaviour.

These changes were intentionally not made to the `dynamic` strategy to limit
the scope of this pull request. While I can reasonably predict what behaviour
users of the `fixed` strategy might expect, I can not say the same about the
`dynamic` strategy.

Fixes: junit-team#3026
Fixes: junit-team#2545
Fixes: junit-team#1858
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Sep 24, 2022
JUnit Jupiter (and The JUnit Platform) now support limiting the
maximum number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size` property.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum
pool size. While the number of concurrently executing tests may exceed the
configured parallelism when tests become blocked, it will not exceed the
maximum pool size.

With the following configuration:

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=2
```

This example will report between 2-5 tests running concurrently.

```java
class ExampleTest {

    private static final AtomicInteger running = new AtomicInteger();

    @beforeeach
    void increment() {
        System.out.println("Running " + running.incrementAndGet());
    }

    @AfterEach
    void decrement() {
        running.decrementAndGet();
    }

    static IntStream numbers() {
        return IntStream.range(0, 1000);
    }

    @ParameterizedTest
    @MethodSource("numbers")
    void test(int i) throws ExecutionException, InterruptedException {
        Runnable sleep = () -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        ForkJoinPool.commonPool().submit(sleep).get();
    }
}
```

By also configuring the `max-pool-size` we can ensure the concurrently
executing test does not exceed the configured 2.

```properties
junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
```

Additionally, because the `ForkJoinPool` will by default reject tasks that
would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has been
added and will default to `true`. There appears to be no reason to ever set
this `false` but it is there should someone depend on the old behaviour.

These changes were intentionally not made to the `dynamic` strategy to limit
the scope of this pull request. While I can reasonably predict what behaviour
users of the `fixed` strategy might expect, I can not say the same about the
`dynamic` strategy.

Fixes: junit-team#3026
Fixes: junit-team#2545
Fixes: junit-team#1858
mpkorstanje added a commit to mpkorstanje/junit5 that referenced this issue Oct 3, 2022
JUnit Jupiter (and The JUnit Platform) now support limiting the
maximum number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size` property.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a maximum
pool size. While the number of concurrently executing tests may exceed the
configured parallelism when tests become blocked, it will not exceed the
maximum pool size.

With the following configuration:

```properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.config.strategy=fixed
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.fixed.parallelism=2
```

This example will report between 2-5 tests running concurrently.

```java
class ExampleTest {

    private static final AtomicInteger running = new AtomicInteger();

    @beforeeach
    void increment() {
        System.out.println("Running " + running.incrementAndGet());
    }

    @AfterEach
    void decrement() {
        running.decrementAndGet();
    }

    static IntStream numbers() {
        return IntStream.range(0, 1000);
    }

    @ParameterizedTest
    @MethodSource("numbers")
    void test(int i) throws ExecutionException, InterruptedException {
        Runnable sleep = () -> {
            try {
                Thread.sleep(600);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        };
        ForkJoinPool.commonPool().submit(sleep).get();
    }
}
```

By also configuring the `max-pool-size` we can ensure the concurrently
executing test does not exceed the configured 2.

```properties
junit.jupiter.execution.parallel.config.fixed.max-pool-size=2
```

Additionally, because the `ForkJoinPool` will by default reject tasks that
would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has been
added and will default to `true`. There appears to be no reason to ever set
this `false` but it is there should someone depend on the old behaviour.

These changes were intentionally not made to the `dynamic` strategy to limit
the scope of this pull request. While I can reasonably predict what behaviour
users of the `fixed` strategy might expect, I can not say the same about the
`dynamic` strategy.

Fixes: junit-team#3026
Fixes: junit-team#2545
Fixes: junit-team#1858
@mpkorstanje
Copy link
Contributor Author

I reckon #3044 is good go.

@marcphilipp marcphilipp added this to the 5.10 M1 milestone Oct 21, 2022
marcphilipp pushed a commit that referenced this issue Jan 6, 2023
JUnit Jupiter (and The JUnit Platform) now support limiting the maximum
number of concurrently executing tests via the
`junit.jupiter.execution.parallel.config.fixed.max-pool-size`
configuration parameter.

With Java 9+ the `ForkJoinPool` used by JUnit can be configured with a
maximum pool size. While the number of concurrently executing tests may
exceed the configured parallelism when tests become blocked, it will
not exceed the maximum pool size.

Additionally, because the `ForkJoinPool` will by default reject tasks
that would exceed the maximum pool size the
`junit.jupiter.execution.parallel.config.fixed.saturate` property has
been added and will default to `true`. There appears to be no reason to
ever set this `false` but it is there should someone depend on the old
behavior.

These changes were intentionally not made to the `dynamic` strategy to
limit the scope of this pull request. While I can reasonably predict
what behavior users of the `fixed` strategy might expect, I can not say
the same about the `dynamic` strategy.

Fixes #3026.
Fixes #2545.
Fixes #1858.
@sbrannen sbrannen changed the title Support saturating the Forkjoin pool via a property Support saturating the ForkJoinPool via a property Apr 16, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment