summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Kweku Adams <kwekua@google.com> 2021-02-02 22:45:03 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2021-02-02 22:45:03 +0000
commit9d876e5dd6edcf280e9e800705c7f228f600a8ab (patch)
treec5009ee58f2202138dfa38496b12ad4a499d775e
parent898e9466ea15383ddbd19f084c56253228443fae (diff)
parent0d46c77edcfe41ad21f7e0a964806ac18b6cd003 (diff)
Merge "Fix bug and migrate test." into sc-dev
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java45
-rw-r--r--services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java295
2 files changed, 225 insertions, 115 deletions
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
index 223f3b04d4e6..6ab10518b557 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java
@@ -791,15 +791,10 @@ class JobConcurrencyManager {
mNumUnspecialized = mConfigMaxTotal;
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_TOP);
mNumUnspecialized -= mConfigNumReservedSlots.get(WORK_TYPE_BG);
- mNumUnspecialized -= mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP);
- mNumUnspecialized -= mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG);
- calculateUnspecializedRemaining();
- }
-
- private void calculateUnspecializedRemaining() {
- mNumUnspecializedRemaining = mNumUnspecialized;
+ mNumUnspecializedRemaining = mConfigMaxTotal;
for (int i = mNumRunningJobs.size() - 1; i >= 0; --i) {
- mNumUnspecializedRemaining -= mNumRunningJobs.valueAt(i);
+ mNumUnspecializedRemaining -= Math.max(mNumRunningJobs.valueAt(i),
+ mConfigNumReservedSlots.get(mNumRunningJobs.keyAt(i)));
}
}
@@ -882,24 +877,42 @@ class JobConcurrencyManager {
mNumUnspecialized = mConfigMaxTotal;
final int numTop = mNumRunningJobs.get(WORK_TYPE_TOP)
+ mNumPendingJobs.get(WORK_TYPE_TOP);
- final int resTop = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_TOP), numTop);
+ int resTop = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_TOP), numTop);
mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop);
mNumUnspecialized -= resTop;
final int numBg = mNumRunningJobs.get(WORK_TYPE_BG) + mNumPendingJobs.get(WORK_TYPE_BG);
- final int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
+ int resBg = Math.min(mConfigNumReservedSlots.get(WORK_TYPE_BG), numBg);
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg);
mNumUnspecialized -= resBg;
- calculateUnspecializedRemaining();
+
+ mNumUnspecializedRemaining = mNumUnspecialized;
+ // Account for already running jobs after we've assigned the minimum number of slots.
+ int unspecializedAssigned;
+ int extraRunning = (mNumRunningJobs.get(WORK_TYPE_TOP) - resTop);
+ if (extraRunning > 0) {
+ unspecializedAssigned = Math.max(0,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP) - resTop,
+ extraRunning));
+ resTop += unspecializedAssigned;
+ mNumUnspecializedRemaining -= extraRunning;
+ }
+ extraRunning = (mNumRunningJobs.get(WORK_TYPE_BG) - resBg);
+ if (extraRunning > 0) {
+ unspecializedAssigned = Math.max(0,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG) - resBg, extraRunning));
+ resBg += unspecializedAssigned;
+ mNumUnspecializedRemaining -= extraRunning;
+ }
// Assign remaining unspecialized based on ranking.
- int unspecializedAssigned = Math.max(0,
- Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP),
- Math.min(mNumUnspecializedRemaining, numTop - resTop)));
+ unspecializedAssigned = Math.max(0,
+ Math.min(mNumUnspecializedRemaining,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_TOP), numTop) - resTop));
mNumActuallyReservedSlots.put(WORK_TYPE_TOP, resTop + unspecializedAssigned);
mNumUnspecializedRemaining -= unspecializedAssigned;
unspecializedAssigned = Math.max(0,
- Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG),
- Math.min(mNumUnspecializedRemaining, numBg - resBg)));
+ Math.min(mNumUnspecializedRemaining,
+ Math.min(mConfigAbsoluteMaxSlots.get(WORK_TYPE_BG), numBg) - resBg));
mNumActuallyReservedSlots.put(WORK_TYPE_BG, resBg + unspecializedAssigned);
mNumUnspecializedRemaining -= unspecializedAssigned;
}
diff --git a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
index 15a9bcf59b28..62088015cbd5 100644
--- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java
@@ -21,9 +21,11 @@ import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_NONE;
import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_TOP;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
-import android.util.Log;
+import android.annotation.NonNull;
import android.util.Pair;
+import android.util.SparseIntArray;
import androidx.test.filters.MediumTest;
import androidx.test.runner.AndroidJUnit4;
@@ -58,106 +60,112 @@ public class WorkCountTrackerTest {
* Represents running and pending jobs.
*/
class Jobs {
- public int runningFg;
- public int runningBg;
- public int pendingFg;
- public int pendingBg;
+ public final SparseIntArray running = new SparseIntArray();
+ public final SparseIntArray pending = new SparseIntArray();
public void maybeEnqueueJobs(double startRatio, double fgJobRatio) {
while (mRandom.nextDouble() < startRatio) {
if (mRandom.nextDouble() < fgJobRatio) {
- pendingFg++;
+ pending.put(WORK_TYPE_TOP, pending.get(WORK_TYPE_TOP) + 1);
} else {
- pendingBg++;
+ pending.put(WORK_TYPE_BG, pending.get(WORK_TYPE_BG) + 1);
}
}
}
public void maybeFinishJobs(double stopRatio) {
- for (int i = runningBg; i > 0; i--) {
+ for (int i = running.get(WORK_TYPE_BG); i > 0; i--) {
if (mRandom.nextDouble() < stopRatio) {
- runningBg--;
+ running.put(WORK_TYPE_BG, running.get(WORK_TYPE_BG) - 1);
}
}
- for (int i = runningFg; i > 0; i--) {
+ for (int i = running.get(WORK_TYPE_TOP); i > 0; i--) {
if (mRandom.nextDouble() < stopRatio) {
- runningFg--;
+ running.put(WORK_TYPE_TOP, running.get(WORK_TYPE_TOP) - 1);
}
}
}
}
- private void startPendingJobs(Jobs jobs, int totalMax, int maxBg, int minBg) {
- mWorkCountTracker.setConfig(new JobConcurrencyManager.WorkTypeConfig("critical",
- totalMax,
- // defaultMin
- List.of(Pair.create(WORK_TYPE_TOP, totalMax - maxBg),
- Pair.create(WORK_TYPE_BG, minBg)),
- // defaultMax
- List.of(Pair.create(WORK_TYPE_BG, maxBg))));
+ private void startPendingJobs(Jobs jobs, int totalMax,
+ @NonNull List<Pair<Integer, Integer>> minLimits,
+ @NonNull List<Pair<Integer, Integer>> maxLimits) {
+ mWorkCountTracker.setConfig(new JobConcurrencyManager.WorkTypeConfig(
+ "test", totalMax, minLimits, maxLimits));
mWorkCountTracker.resetCounts();
- for (int i = 0; i < jobs.runningFg; i++) {
- mWorkCountTracker.incrementRunningJobCount(WORK_TYPE_TOP);
- }
- for (int i = 0; i < jobs.runningBg; i++) {
- mWorkCountTracker.incrementRunningJobCount(WORK_TYPE_BG);
- }
+ for (int i = 0; i < jobs.running.size(); ++i) {
+ final int workType = jobs.running.keyAt(i);
+ final int count = jobs.running.valueAt(i);
- for (int i = 0; i < jobs.pendingFg; i++) {
- mWorkCountTracker.incrementPendingJobCount(WORK_TYPE_TOP);
+ for (int c = 0; c < count; ++c) {
+ mWorkCountTracker.incrementRunningJobCount(workType);
+ }
}
- for (int i = 0; i < jobs.pendingBg; i++) {
- mWorkCountTracker.incrementPendingJobCount(WORK_TYPE_BG);
+ for (int i = 0; i < jobs.pending.size(); ++i) {
+ final int workType = jobs.pending.keyAt(i);
+ final int count = jobs.pending.valueAt(i);
+
+ for (int c = 0; c < count; ++c) {
+ mWorkCountTracker.incrementPendingJobCount(workType);
+ }
}
mWorkCountTracker.onCountDone();
- while ((jobs.pendingFg > 0
+ while ((jobs.pending.get(WORK_TYPE_TOP) > 0
&& mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE)
- || (jobs.pendingBg > 0
+ || (jobs.pending.get(WORK_TYPE_BG) > 0
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE)) {
final boolean isStartingFg = mRandom.nextBoolean();
if (isStartingFg) {
- if (jobs.pendingFg > 0
+ if (jobs.pending.get(WORK_TYPE_TOP) > 0
&& mWorkCountTracker.canJobStart(WORK_TYPE_TOP) != WORK_TYPE_NONE) {
- jobs.pendingFg--;
- jobs.runningFg++;
+ jobs.pending.put(WORK_TYPE_TOP, jobs.pending.get(WORK_TYPE_TOP) - 1);
+ jobs.running.put(WORK_TYPE_TOP, jobs.running.get(WORK_TYPE_TOP) + 1);
mWorkCountTracker.stageJob(WORK_TYPE_TOP);
mWorkCountTracker.onJobStarted(WORK_TYPE_TOP);
}
} else {
- if (jobs.pendingBg > 0
+ if (jobs.pending.get(WORK_TYPE_BG) > 0
&& mWorkCountTracker.canJobStart(WORK_TYPE_BG) != WORK_TYPE_NONE) {
- jobs.pendingBg--;
- jobs.runningBg++;
+ jobs.pending.put(WORK_TYPE_BG, jobs.pending.get(WORK_TYPE_BG) - 1);
+ jobs.running.put(WORK_TYPE_BG, jobs.running.get(WORK_TYPE_BG) + 1);
mWorkCountTracker.stageJob(WORK_TYPE_BG);
mWorkCountTracker.onJobStarted(WORK_TYPE_BG);
}
}
}
-
- Log.i(TAG, "" + mWorkCountTracker);
}
/**
* Used by the following testRandom* tests.
*/
- private void checkRandom(Jobs jobs, int numTests, int totalMax, int maxBg, int minBg,
+ private void checkRandom(Jobs jobs, int numTests, int totalMax,
+ @NonNull List<Pair<Integer, Integer>> minLimits,
+ @NonNull List<Pair<Integer, Integer>> maxLimits,
double startRatio, double fgJobRatio, double stopRatio) {
for (int i = 0; i < numTests; i++) {
-
jobs.maybeFinishJobs(stopRatio);
jobs.maybeEnqueueJobs(startRatio, fgJobRatio);
- startPendingJobs(jobs, totalMax, maxBg, minBg);
+ startPendingJobs(jobs, totalMax, minLimits, maxLimits);
- assertThat(jobs.runningFg).isAtMost(totalMax);
- assertThat(jobs.runningBg).isAtMost(totalMax);
- assertThat(jobs.runningFg + jobs.runningBg).isAtMost(totalMax);
- assertThat(jobs.runningBg).isAtMost(maxBg);
+ int totalRunning = 0;
+ for (int r = 0; r < jobs.running.size(); ++r) {
+ final int numRunning = jobs.running.valueAt(r);
+ assertWithMessage(
+ "Work type " + jobs.running.keyAt(r) + " is running too many jobs")
+ .that(numRunning).isAtMost(totalMax);
+ totalRunning += numRunning;
+ }
+ assertThat(totalRunning).isAtMost(totalMax);
+ for (Pair<Integer, Integer> maxLimit : maxLimits) {
+ assertWithMessage("Work type " + maxLimit.first + " is running too many jobs")
+ .that(jobs.running.get(maxLimit.first)).isAtMost(maxLimit.second);
+ }
}
}
@@ -170,13 +178,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final int maxBg = 4;
- final int minBg = 2;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.1;
final double fgJobRatio = 0.5;
final double startRatio = 0.1;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio , stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -185,13 +194,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 2;
- final int maxBg = 2;
- final int minBg = 0;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> minLimits = List.of();
final double stopRatio = 0.5;
final double fgJobRatio = 0.5;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -200,13 +210,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 2;
- final int maxBg = 2;
- final int minBg = 2;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.5;
final double fgJobRatio = 0.5;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -215,13 +226,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 10;
- final int maxBg = 2;
- final int minBg = 0;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
+ final List<Pair<Integer, Integer>> minLimits = List.of();
final double stopRatio = 0.5;
final double fgJobRatio = 0.5;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -230,13 +242,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final int maxBg = 4;
- final int minBg = 2;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.5;
final double fgJobRatio = 0.1;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -245,13 +258,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final int maxBg = 4;
- final int minBg = 2;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.5;
final double fgJobRatio = 0.9;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -260,13 +274,14 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final int maxBg = 4;
- final int minBg = 2;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.4;
final double fgJobRatio = 0.1;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
@Test
@@ -275,53 +290,135 @@ public class WorkCountTrackerTest {
final int numTests = 5000;
final int totalMax = 6;
- final int maxBg = 4;
- final int minBg = 2;
+ final List<Pair<Integer, Integer>> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4));
+ final List<Pair<Integer, Integer>> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2));
final double stopRatio = 0.4;
final double fgJobRatio = 0.9;
final double startRatio = 0.5;
- checkRandom(jobs, numTests, totalMax, maxBg, minBg, startRatio, fgJobRatio, stopRatio);
+ checkRandom(jobs, numTests, totalMax, minLimits, maxLimits,
+ startRatio, fgJobRatio, stopRatio);
}
/** Used by the following tests */
- private void checkSimple(int totalMax, int maxBg, int minBg,
- int runningFg, int runningBg, int pendingFg, int pendingBg,
- int resultRunningFg, int resultRunningBg, int resultPendingFg, int resultPendingBg) {
+ private void checkSimple(int totalMax,
+ @NonNull List<Pair<Integer, Integer>> minLimits,
+ @NonNull List<Pair<Integer, Integer>> maxLimits,
+ @NonNull List<Pair<Integer, Integer>> running,
+ @NonNull List<Pair<Integer, Integer>> pending,
+ @NonNull List<Pair<Integer, Integer>> resultRunning,
+ @NonNull List<Pair<Integer, Integer>> resultPending) {
final Jobs jobs = new Jobs();
- jobs.runningFg = runningFg;
- jobs.runningBg = runningBg;
- jobs.pendingFg = pendingFg;
- jobs.pendingBg = pendingBg;
-
- startPendingJobs(jobs, totalMax, maxBg, minBg);
+ for (Pair<Integer, Integer> run : running) {
+ jobs.running.put(run.first, run.second);
+ }
+ for (Pair<Integer, Integer> pend : pending) {
+ jobs.pending.put(pend.first, pend.second);
+ }
-// fail(mWorkerCountTracker.toString());
- assertThat(jobs.runningFg).isEqualTo(resultRunningFg);
- assertThat(jobs.runningBg).isEqualTo(resultRunningBg);
+ startPendingJobs(jobs, totalMax, minLimits, maxLimits);
- assertThat(jobs.pendingFg).isEqualTo(resultPendingFg);
- assertThat(jobs.pendingBg).isEqualTo(resultPendingBg);
+ for (Pair<Integer, Integer> run : resultRunning) {
+ assertWithMessage("Incorrect running result for work type " + run.first)
+ .that(jobs.running.get(run.first)).isEqualTo(run.second);
+ }
+ for (Pair<Integer, Integer> pend : resultPending) {
+ assertWithMessage("Incorrect pending result for work type " + pend.first)
+ .that(jobs.pending.get(pend.first)).isEqualTo(pend.second);
+ }
}
-
@Test
public void testBasic() {
- // Args are:
- // First 3: Total-max, bg-max, bg-min.
- // Next 2: Running FG / BG
- // Next 2: Pending FG / BG
- // Next 4: Result running FG / BG, pending FG/BG.
- checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 1, 0, /*res run/pen=*/ 1, 0, 0, 0);
-
- checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 0, /*res run/pen=*/ 6, 0, 4, 0);
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* run */ List.of(),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 1)),
+ /* resPen */ List.of());
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* run */ List.of(),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 4)));
// When there are BG jobs pending, 2 (min-BG) jobs should run.
- checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 1, /*res run/pen=*/ 5, 1, 5, 0);
- checkSimple(6, 4, 2, /*run=*/ 0, 0, /*pen=*/ 10, 3, /*res run/pen=*/ 4, 2, 6, 1);
-
- checkSimple(8, 6, 2, /*run=*/ 0, 0, /*pen=*/ 0, 49, /*res run/pen=*/ 0, 6, 0, 43);
-
- checkSimple(6, 4, 2, /*run=*/ 6, 0, /*pen=*/ 10, 3, /*res run/pen=*/ 6, 0, 10, 3);
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* run */ List.of(),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 5)));
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* run */ List.of(),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 2)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 1)));
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* run */ List.of(),
+ /* pen */ List.of(Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_BG, 43)));
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_BG, 47)));
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 6)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 1)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 48)));
+
+ checkSimple(8,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 2)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 49)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 8), Pair.create(WORK_TYPE_BG, 49)));
+
+ checkSimple(6,
+ /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)),
+ /* run */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
+
+ // This could happen if we lower the effective config due to higher memory pressure after
+ // we've already started running jobs. We shouldn't stop already running jobs, but also
+ // shouldn't start new ones.
+ checkSimple(5,
+ /* min */ List.of(),
+ /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)),
+ /* run */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)),
+ /* resRun */ List.of(Pair.create(WORK_TYPE_BG, 6)),
+ /* resPen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3)));
}
}