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 b806ef88f2d7a..e0e0b4bd62e2f 100644 --- a/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java +++ b/apex/jobscheduler/service/java/com/android/server/job/JobConcurrencyManager.java @@ -17,6 +17,7 @@ package com.android.server.job; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static android.util.DataUnit.GIGABYTES; import static com.android.server.job.JobSchedulerService.RESTRICTED_INDEX; import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock; @@ -58,6 +59,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IBatteryStats; import com.android.internal.app.procstats.ProcessStats; +import com.android.internal.util.MemInfoReader; import com.android.internal.util.StatLogger; import com.android.server.JobSchedulerBackgroundThread; import com.android.server.LocalServices; @@ -85,11 +87,33 @@ class JobConcurrencyManager { private static final boolean DEBUG = JobSchedulerService.DEBUG; /** The maximum number of concurrent jobs we'll aim to run at one time. */ - public static final int STANDARD_CONCURRENCY_LIMIT = 16; + @VisibleForTesting + static final int MAX_CONCURRENCY_LIMIT = 64; /** The maximum number of objects we should retain in memory when not in use. */ - private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * STANDARD_CONCURRENCY_LIMIT); + private static final int MAX_RETAINED_OBJECTS = (int) (1.5 * MAX_CONCURRENCY_LIMIT); static final String CONFIG_KEY_PREFIX_CONCURRENCY = "concurrency_"; + private static final String KEY_CONCURRENCY_LIMIT = CONFIG_KEY_PREFIX_CONCURRENCY + "limit"; + @VisibleForTesting + static final int DEFAULT_CONCURRENCY_LIMIT; + + static { + if (ActivityManager.isLowRamDeviceStatic()) { + DEFAULT_CONCURRENCY_LIMIT = 8; + } else { + final long ramBytes = new MemInfoReader().getTotalSize(); + if (ramBytes <= GIGABYTES.toBytes(6)) { + DEFAULT_CONCURRENCY_LIMIT = 16; + } else if (ramBytes <= GIGABYTES.toBytes(8)) { + DEFAULT_CONCURRENCY_LIMIT = 20; + } else if (ramBytes <= GIGABYTES.toBytes(12)) { + DEFAULT_CONCURRENCY_LIMIT = 32; + } else { + DEFAULT_CONCURRENCY_LIMIT = 40; + } + } + } + private static final String KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS = CONFIG_KEY_PREFIX_CONCURRENCY + "screen_off_adjustment_delay_ms"; private static final long DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS = 30_000; @@ -100,7 +124,7 @@ class JobConcurrencyManager { @VisibleForTesting static final String KEY_PKG_CONCURRENCY_LIMIT_REGULAR = CONFIG_KEY_PREFIX_CONCURRENCY + "pkg_concurrency_limit_regular"; - private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = STANDARD_CONCURRENCY_LIMIT / 2; + private static final int DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR = DEFAULT_CONCURRENCY_LIMIT / 2; @VisibleForTesting static final String KEY_ENABLE_MAX_WAIT_TIME_BYPASS = CONFIG_KEY_PREFIX_CONCURRENCY + "enable_max_wait_time_bypass"; @@ -209,84 +233,100 @@ class JobConcurrencyManager { private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_ON = new WorkConfigLimitsPerMemoryTrimLevel( - new WorkTypeConfig("screen_on_normal", 11, + new WorkTypeConfig("screen_on_normal", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 3 / 4, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), + List.of(Pair.create(WORK_TYPE_TOP, .4f), + Pair.create(WORK_TYPE_FGS, .2f), + Pair.create(WORK_TYPE_EJ, .2f), Pair.create(WORK_TYPE_BG, .1f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 6), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2), - Pair.create(WORK_TYPE_BGUSER, 3)) + List.of(Pair.create(WORK_TYPE_BG, .5f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .25f), + Pair.create(WORK_TYPE_BGUSER, .2f)) ), - new WorkTypeConfig("screen_on_moderate", 9, + new WorkTypeConfig("screen_on_moderate", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT / 2, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), + List.of(Pair.create(WORK_TYPE_TOP, .4f), + Pair.create(WORK_TYPE_FGS, .1f), + Pair.create(WORK_TYPE_EJ, .1f), Pair.create(WORK_TYPE_BG, .1f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 4), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, .4f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f), + Pair.create(WORK_TYPE_BGUSER, .1f)) ), - new WorkTypeConfig("screen_on_low", 6, + new WorkTypeConfig("screen_on_low", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 4 / 10, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 1)), + List.of(Pair.create(WORK_TYPE_TOP, 2.0f / 3), + Pair.create(WORK_TYPE_FGS, .1f), + Pair.create(WORK_TYPE_EJ, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 2), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1.0f / 6), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)) ), - new WorkTypeConfig("screen_on_critical", 6, + new WorkTypeConfig("screen_on_critical", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 4 / 10, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 1)), + List.of(Pair.create(WORK_TYPE_TOP, 2.0f / 3), + Pair.create(WORK_TYPE_FGS, .1f), + Pair.create(WORK_TYPE_EJ, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 1), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 6), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1.0f / 6), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)) ) ); private static final WorkConfigLimitsPerMemoryTrimLevel CONFIG_LIMITS_SCREEN_OFF = new WorkConfigLimitsPerMemoryTrimLevel( - new WorkTypeConfig("screen_off_normal", 16, + new WorkTypeConfig("screen_off_normal", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), + List.of(Pair.create(WORK_TYPE_TOP, .3f), + Pair.create(WORK_TYPE_FGS, .2f), + Pair.create(WORK_TYPE_EJ, .3f), Pair.create(WORK_TYPE_BG, .2f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 10), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2), - Pair.create(WORK_TYPE_BGUSER, 3)) + List.of(Pair.create(WORK_TYPE_BG, .6f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .2f), + Pair.create(WORK_TYPE_BGUSER, .2f)) ), - new WorkTypeConfig("screen_off_moderate", 14, + new WorkTypeConfig("screen_off_moderate", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 9 / 10, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1)), + List.of(Pair.create(WORK_TYPE_TOP, .3f), + Pair.create(WORK_TYPE_FGS, .2f), + Pair.create(WORK_TYPE_EJ, .3f), Pair.create(WORK_TYPE_BG, .2f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 7), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, .5f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f), + Pair.create(WORK_TYPE_BGUSER, .1f)) ), - new WorkTypeConfig("screen_off_low", 9, + new WorkTypeConfig("screen_off_low", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 6 / 10, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)), + List.of(Pair.create(WORK_TYPE_TOP, .4f), + Pair.create(WORK_TYPE_FGS, .1f), + Pair.create(WORK_TYPE_EJ, .2f), Pair.create(WORK_TYPE_BG, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 3), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, .25f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f), + Pair.create(WORK_TYPE_BGUSER, .1f)) ), - new WorkTypeConfig("screen_off_critical", 6, + new WorkTypeConfig("screen_off_critical", DEFAULT_CONCURRENCY_LIMIT, + /* defaultMaxTotal */ DEFAULT_CONCURRENCY_LIMIT * 4 / 10, // defaultMin - List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_FGS, 1), - Pair.create(WORK_TYPE_EJ, 1)), + List.of(Pair.create(WORK_TYPE_TOP, .5f), + Pair.create(WORK_TYPE_FGS, .1f), + Pair.create(WORK_TYPE_EJ, .1f)), // defaultMax - List.of(Pair.create(WORK_TYPE_BG, 1), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)) + List.of(Pair.create(WORK_TYPE_BG, .1f), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, .1f), + Pair.create(WORK_TYPE_BGUSER, .1f)) ) ); @@ -357,6 +397,12 @@ class JobConcurrencyManager { /** Wait for this long after screen off before adjusting the job concurrency. */ private long mScreenOffAdjustmentDelayMs = DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS; + /** + * The maximum number of jobs we'll attempt to have running at one time. This may occasionally + * be exceeded based on other factors. + */ + private int mSteadyStateConcurrencyLimit = DEFAULT_CONCURRENCY_LIMIT; + /** * The maximum number of expedited jobs a single userId-package can have running simultaneously. * TOP apps are not limited. @@ -451,7 +497,7 @@ class JobConcurrencyManager { void onThirdPartyAppsCanStart() { final IBatteryStats batteryStats = IBatteryStats.Stub.asInterface( ServiceManager.getService(BatteryStats.SERVICE_NAME)); - for (int i = 0; i < STANDARD_CONCURRENCY_LIMIT; i++) { + for (int i = 0; i < mSteadyStateConcurrencyLimit; ++i) { mIdleContexts.add( mInjector.createJobServiceContext(mService, this, mNotificationCoordinator, batteryStats, @@ -778,13 +824,14 @@ class JobConcurrencyManager { } preferredUidOnly.sort(sDeterminationComparator); stoppable.sort(sDeterminationComparator); - for (int i = numRunningJobs; i < STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = numRunningJobs; i < mSteadyStateConcurrencyLimit; ++i) { final JobServiceContext jsc; final int numIdleContexts = mIdleContexts.size(); if (numIdleContexts > 0) { jsc = mIdleContexts.removeAt(numIdleContexts - 1); } else { - Slog.wtf(TAG, "Had fewer than " + STANDARD_CONCURRENCY_LIMIT + " in existence"); + // This could happen if the config is changed at runtime. + Slog.w(TAG, "Had fewer than " + mSteadyStateConcurrencyLimit + " in existence"); jsc = createNewJobServiceContext(); } @@ -850,7 +897,7 @@ class JobConcurrencyManager { ContextAssignment selectedContext = null; final int allWorkTypes = getJobWorkTypes(nextPending); final boolean pkgConcurrencyOkay = !isPkgConcurrencyLimitedLocked(nextPending); - final boolean isInOverage = projectedRunningCount > STANDARD_CONCURRENCY_LIMIT; + final boolean isInOverage = projectedRunningCount > mSteadyStateConcurrencyLimit; boolean startingJob = false; if (idle.size() > 0) { final int idx = idle.size() - 1; @@ -1398,7 +1445,7 @@ class JobConcurrencyManager { noteConcurrency(); return; } - if (mActiveServices.size() >= STANDARD_CONCURRENCY_LIMIT) { + if (mActiveServices.size() >= mSteadyStateConcurrencyLimit) { final boolean respectConcurrencyLimit; if (!mMaxWaitTimeBypassEnabled) { respectConcurrencyLimit = true; @@ -1801,23 +1848,27 @@ class JobConcurrencyManager { DeviceConfig.Properties properties = DeviceConfig.getProperties(DeviceConfig.NAMESPACE_JOB_SCHEDULER); + // Concurrency limit should be in the range [8, MAX_CONCURRENCY_LIMIT]. + mSteadyStateConcurrencyLimit = Math.max(8, Math.min(MAX_CONCURRENCY_LIMIT, + properties.getInt(KEY_CONCURRENCY_LIMIT, DEFAULT_CONCURRENCY_LIMIT))); + mScreenOffAdjustmentDelayMs = properties.getLong( KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, DEFAULT_SCREEN_OFF_ADJUSTMENT_DELAY_MS); - CONFIG_LIMITS_SCREEN_ON.normal.update(properties); - CONFIG_LIMITS_SCREEN_ON.moderate.update(properties); - CONFIG_LIMITS_SCREEN_ON.low.update(properties); - CONFIG_LIMITS_SCREEN_ON.critical.update(properties); + CONFIG_LIMITS_SCREEN_ON.normal.update(properties, mSteadyStateConcurrencyLimit); + CONFIG_LIMITS_SCREEN_ON.moderate.update(properties, mSteadyStateConcurrencyLimit); + CONFIG_LIMITS_SCREEN_ON.low.update(properties, mSteadyStateConcurrencyLimit); + CONFIG_LIMITS_SCREEN_ON.critical.update(properties, mSteadyStateConcurrencyLimit); - CONFIG_LIMITS_SCREEN_OFF.normal.update(properties); - CONFIG_LIMITS_SCREEN_OFF.moderate.update(properties); - CONFIG_LIMITS_SCREEN_OFF.low.update(properties); - CONFIG_LIMITS_SCREEN_OFF.critical.update(properties); + CONFIG_LIMITS_SCREEN_OFF.normal.update(properties, mSteadyStateConcurrencyLimit); + CONFIG_LIMITS_SCREEN_OFF.moderate.update(properties, mSteadyStateConcurrencyLimit); + CONFIG_LIMITS_SCREEN_OFF.low.update(properties, mSteadyStateConcurrencyLimit); + CONFIG_LIMITS_SCREEN_OFF.critical.update(properties, mSteadyStateConcurrencyLimit); - // Package concurrency limits must in the range [1, STANDARD_CONCURRENCY_LIMIT]. - mPkgConcurrencyLimitEj = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT, + // Package concurrency limits must in the range [1, mSteadyStateConcurrencyLimit]. + mPkgConcurrencyLimitEj = Math.max(1, Math.min(mSteadyStateConcurrencyLimit, properties.getInt(KEY_PKG_CONCURRENCY_LIMIT_EJ, DEFAULT_PKG_CONCURRENCY_LIMIT_EJ))); - mPkgConcurrencyLimitRegular = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT, + mPkgConcurrencyLimitRegular = Math.max(1, Math.min(mSteadyStateConcurrencyLimit, properties.getInt( KEY_PKG_CONCURRENCY_LIMIT_REGULAR, DEFAULT_PKG_CONCURRENCY_LIMIT_REGULAR))); @@ -1838,6 +1889,7 @@ class JobConcurrencyManager { try { pw.println("Configuration:"); pw.increaseIndent(); + pw.print(KEY_CONCURRENCY_LIMIT, mSteadyStateConcurrencyLimit).println(); pw.print(KEY_SCREEN_OFF_ADJUSTMENT_DELAY_MS, mScreenOffAdjustmentDelayMs).println(); pw.print(KEY_PKG_CONCURRENCY_LIMIT_EJ, mPkgConcurrencyLimitEj).println(); pw.print(KEY_PKG_CONCURRENCY_LIMIT_REGULAR, mPkgConcurrencyLimitRegular).println(); @@ -2041,130 +2093,181 @@ class JobConcurrencyManager { @VisibleForTesting static class WorkTypeConfig { - @VisibleForTesting - static final String KEY_PREFIX_MAX = CONFIG_KEY_PREFIX_CONCURRENCY + "max_"; - @VisibleForTesting - static final String KEY_PREFIX_MIN = CONFIG_KEY_PREFIX_CONCURRENCY + "min_"; + private static final String KEY_PREFIX_MAX = CONFIG_KEY_PREFIX_CONCURRENCY + "max_"; + private static final String KEY_PREFIX_MIN = CONFIG_KEY_PREFIX_CONCURRENCY + "min_"; @VisibleForTesting static final String KEY_PREFIX_MAX_TOTAL = CONFIG_KEY_PREFIX_CONCURRENCY + "max_total_"; - private static final String KEY_PREFIX_MAX_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "max_top_"; - private static final String KEY_PREFIX_MAX_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "max_fgs_"; - private static final String KEY_PREFIX_MAX_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "max_ej_"; - private static final String KEY_PREFIX_MAX_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "max_bg_"; - private static final String KEY_PREFIX_MAX_BGUSER = - CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_"; - private static final String KEY_PREFIX_MAX_BGUSER_IMPORTANT = - CONFIG_KEY_PREFIX_CONCURRENCY + "max_bguser_important_"; - private static final String KEY_PREFIX_MIN_TOP = CONFIG_KEY_PREFIX_CONCURRENCY + "min_top_"; - private static final String KEY_PREFIX_MIN_FGS = CONFIG_KEY_PREFIX_CONCURRENCY + "min_fgs_"; - private static final String KEY_PREFIX_MIN_EJ = CONFIG_KEY_PREFIX_CONCURRENCY + "min_ej_"; - private static final String KEY_PREFIX_MIN_BG = CONFIG_KEY_PREFIX_CONCURRENCY + "min_bg_"; - private static final String KEY_PREFIX_MIN_BGUSER = - CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_"; - private static final String KEY_PREFIX_MIN_BGUSER_IMPORTANT = - CONFIG_KEY_PREFIX_CONCURRENCY + "min_bguser_important_"; + @VisibleForTesting + static final String KEY_PREFIX_MAX_RATIO = KEY_PREFIX_MAX + "ratio_"; + private static final String KEY_PREFIX_MAX_RATIO_TOP = KEY_PREFIX_MAX_RATIO + "top_"; + private static final String KEY_PREFIX_MAX_RATIO_FGS = KEY_PREFIX_MAX_RATIO + "fgs_"; + private static final String KEY_PREFIX_MAX_RATIO_EJ = KEY_PREFIX_MAX_RATIO + "ej_"; + private static final String KEY_PREFIX_MAX_RATIO_BG = KEY_PREFIX_MAX_RATIO + "bg_"; + private static final String KEY_PREFIX_MAX_RATIO_BGUSER = KEY_PREFIX_MAX_RATIO + "bguser_"; + private static final String KEY_PREFIX_MAX_RATIO_BGUSER_IMPORTANT = + KEY_PREFIX_MAX_RATIO + "bguser_important_"; + @VisibleForTesting + static final String KEY_PREFIX_MIN_RATIO = KEY_PREFIX_MIN + "ratio_"; + private static final String KEY_PREFIX_MIN_RATIO_TOP = KEY_PREFIX_MIN_RATIO + "top_"; + private static final String KEY_PREFIX_MIN_RATIO_FGS = KEY_PREFIX_MIN_RATIO + "fgs_"; + private static final String KEY_PREFIX_MIN_RATIO_EJ = KEY_PREFIX_MIN_RATIO + "ej_"; + private static final String KEY_PREFIX_MIN_RATIO_BG = KEY_PREFIX_MIN_RATIO + "bg_"; + private static final String KEY_PREFIX_MIN_RATIO_BGUSER = KEY_PREFIX_MIN_RATIO + "bguser_"; + private static final String KEY_PREFIX_MIN_RATIO_BGUSER_IMPORTANT = + KEY_PREFIX_MIN_RATIO + "bguser_important_"; private final String mConfigIdentifier; private int mMaxTotal; private final SparseIntArray mMinReservedSlots = new SparseIntArray(NUM_WORK_TYPES); private final SparseIntArray mMaxAllowedSlots = new SparseIntArray(NUM_WORK_TYPES); private final int mDefaultMaxTotal; - private final SparseIntArray mDefaultMinReservedSlots = new SparseIntArray(NUM_WORK_TYPES); - private final SparseIntArray mDefaultMaxAllowedSlots = new SparseIntArray(NUM_WORK_TYPES); + // We use SparseIntArrays to store floats because there is currently no SparseFloatArray + // available, and it doesn't seem worth it to add such a data structure just for this + // use case. We don't use SparseDoubleArrays because DeviceConfig only supports floats and + // converting between floats and ints is more straightforward than floats and doubles. + private final SparseIntArray mDefaultMinReservedSlotsRatio = + new SparseIntArray(NUM_WORK_TYPES); + private final SparseIntArray mDefaultMaxAllowedSlotsRatio = + new SparseIntArray(NUM_WORK_TYPES); - WorkTypeConfig(@NonNull String configIdentifier, int defaultMaxTotal, - List> defaultMin, List> defaultMax) { + WorkTypeConfig(@NonNull String configIdentifier, + int steadyStateConcurrencyLimit, int defaultMaxTotal, + List> defaultMinRatio, + List> defaultMaxRatio) { mConfigIdentifier = configIdentifier; - mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, STANDARD_CONCURRENCY_LIMIT); + mDefaultMaxTotal = mMaxTotal = Math.min(defaultMaxTotal, steadyStateConcurrencyLimit); int numReserved = 0; - for (int i = defaultMin.size() - 1; i >= 0; --i) { - mDefaultMinReservedSlots.put(defaultMin.get(i).first, defaultMin.get(i).second); - numReserved += defaultMin.get(i).second; + for (int i = defaultMinRatio.size() - 1; i >= 0; --i) { + final float ratio = defaultMinRatio.get(i).second; + final int wt = defaultMinRatio.get(i).first; + if (ratio < 0 || 1 <= ratio) { + // 1 means to reserve everything. This shouldn't be allowed. + // We only create new configs on boot, so this should trigger during development + // (before the code gets checked in), so this makes sure the hard-coded defaults + // make sense. DeviceConfig values will be handled gracefully in update(). + throw new IllegalArgumentException("Invalid default min ratio: wt=" + wt + + " minRatio=" + ratio); + } + mDefaultMinReservedSlotsRatio.put(wt, Float.floatToRawIntBits(ratio)); + numReserved += mMaxTotal * ratio; } if (mDefaultMaxTotal < 0 || numReserved > mDefaultMaxTotal) { // We only create new configs on boot, so this should trigger during development // (before the code gets checked in), so this makes sure the hard-coded defaults // make sense. DeviceConfig values will be handled gracefully in update(). throw new IllegalArgumentException("Invalid default config: t=" + defaultMaxTotal - + " min=" + defaultMin + " max=" + defaultMax); + + " min=" + defaultMinRatio + " max=" + defaultMaxRatio); } - for (int i = defaultMax.size() - 1; i >= 0; --i) { - mDefaultMaxAllowedSlots.put(defaultMax.get(i).first, defaultMax.get(i).second); + for (int i = defaultMaxRatio.size() - 1; i >= 0; --i) { + final float ratio = defaultMaxRatio.get(i).second; + final int wt = defaultMaxRatio.get(i).first; + final float minRatio = + Float.intBitsToFloat(mDefaultMinReservedSlotsRatio.get(wt, 0)); + if (ratio < minRatio || ratio <= 0) { + // Max ratio shouldn't be <= 0 or less than minRatio. + throw new IllegalArgumentException("Invalid default config:" + + " t=" + defaultMaxTotal + + " min=" + defaultMinRatio + " max=" + defaultMaxRatio); + } + mDefaultMaxAllowedSlotsRatio.put(wt, Float.floatToRawIntBits(ratio)); } update(new DeviceConfig.Properties.Builder( - DeviceConfig.NAMESPACE_JOB_SCHEDULER).build()); + DeviceConfig.NAMESPACE_JOB_SCHEDULER).build(), steadyStateConcurrencyLimit); } - void update(@NonNull DeviceConfig.Properties properties) { - // Ensure total in the range [1, STANDARD_CONCURRENCY_LIMIT]. - mMaxTotal = Math.max(1, Math.min(STANDARD_CONCURRENCY_LIMIT, + void update(@NonNull DeviceConfig.Properties properties, int steadyStateConcurrencyLimit) { + // Ensure total in the range [1, mSteadyStateConcurrencyLimit]. + mMaxTotal = Math.max(1, Math.min(steadyStateConcurrencyLimit, properties.getInt(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mDefaultMaxTotal))); + final int oneIntBits = Float.floatToIntBits(1); + mMaxAllowedSlots.clear(); // Ensure they're in the range [1, total]. - final int maxTop = Math.max(1, Math.min(mMaxTotal, - properties.getInt(KEY_PREFIX_MAX_TOP + mConfigIdentifier, - mDefaultMaxAllowedSlots.get(WORK_TYPE_TOP, mMaxTotal)))); + final int maxTop = getMaxValue(properties, + KEY_PREFIX_MAX_RATIO_TOP + mConfigIdentifier, WORK_TYPE_TOP, oneIntBits); mMaxAllowedSlots.put(WORK_TYPE_TOP, maxTop); - final int maxFgs = Math.max(1, Math.min(mMaxTotal, - properties.getInt(KEY_PREFIX_MAX_FGS + mConfigIdentifier, - mDefaultMaxAllowedSlots.get(WORK_TYPE_FGS, mMaxTotal)))); + final int maxFgs = getMaxValue(properties, + KEY_PREFIX_MAX_RATIO_FGS + mConfigIdentifier, WORK_TYPE_FGS, oneIntBits); mMaxAllowedSlots.put(WORK_TYPE_FGS, maxFgs); - final int maxEj = Math.max(1, Math.min(mMaxTotal, - properties.getInt(KEY_PREFIX_MAX_EJ + mConfigIdentifier, - mDefaultMaxAllowedSlots.get(WORK_TYPE_EJ, mMaxTotal)))); + final int maxEj = getMaxValue(properties, + KEY_PREFIX_MAX_RATIO_EJ + mConfigIdentifier, WORK_TYPE_EJ, oneIntBits); mMaxAllowedSlots.put(WORK_TYPE_EJ, maxEj); - final int maxBg = Math.max(1, Math.min(mMaxTotal, - properties.getInt(KEY_PREFIX_MAX_BG + mConfigIdentifier, - mDefaultMaxAllowedSlots.get(WORK_TYPE_BG, mMaxTotal)))); + final int maxBg = getMaxValue(properties, + KEY_PREFIX_MAX_RATIO_BG + mConfigIdentifier, WORK_TYPE_BG, oneIntBits); mMaxAllowedSlots.put(WORK_TYPE_BG, maxBg); - final int maxBgUserImp = Math.max(1, Math.min(mMaxTotal, - properties.getInt(KEY_PREFIX_MAX_BGUSER_IMPORTANT + mConfigIdentifier, - mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, mMaxTotal)))); + final int maxBgUserImp = getMaxValue(properties, + KEY_PREFIX_MAX_RATIO_BGUSER_IMPORTANT + mConfigIdentifier, + WORK_TYPE_BGUSER_IMPORTANT, oneIntBits); mMaxAllowedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, maxBgUserImp); - final int maxBgUser = Math.max(1, Math.min(mMaxTotal, - properties.getInt(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier, - mDefaultMaxAllowedSlots.get(WORK_TYPE_BGUSER, mMaxTotal)))); + final int maxBgUser = getMaxValue(properties, + KEY_PREFIX_MAX_RATIO_BGUSER + mConfigIdentifier, WORK_TYPE_BGUSER, oneIntBits); mMaxAllowedSlots.put(WORK_TYPE_BGUSER, maxBgUser); int remaining = mMaxTotal; mMinReservedSlots.clear(); // Ensure top is in the range [1, min(maxTop, total)] - final int minTop = Math.max(1, Math.min(Math.min(maxTop, mMaxTotal), - properties.getInt(KEY_PREFIX_MIN_TOP + mConfigIdentifier, - mDefaultMinReservedSlots.get(WORK_TYPE_TOP)))); + final int minTop = getMinValue(properties, + KEY_PREFIX_MIN_RATIO_TOP + mConfigIdentifier, WORK_TYPE_TOP, + 1, Math.min(maxTop, mMaxTotal)); mMinReservedSlots.put(WORK_TYPE_TOP, minTop); remaining -= minTop; // Ensure fgs is in the range [0, min(maxFgs, remaining)] - final int minFgs = Math.max(0, Math.min(Math.min(maxFgs, remaining), - properties.getInt(KEY_PREFIX_MIN_FGS + mConfigIdentifier, - mDefaultMinReservedSlots.get(WORK_TYPE_FGS)))); + final int minFgs = getMinValue(properties, + KEY_PREFIX_MIN_RATIO_FGS + mConfigIdentifier, WORK_TYPE_FGS, + 0, Math.min(maxFgs, remaining)); mMinReservedSlots.put(WORK_TYPE_FGS, minFgs); remaining -= minFgs; // Ensure ej is in the range [0, min(maxEj, remaining)] - final int minEj = Math.max(0, Math.min(Math.min(maxEj, remaining), - properties.getInt(KEY_PREFIX_MIN_EJ + mConfigIdentifier, - mDefaultMinReservedSlots.get(WORK_TYPE_EJ)))); + final int minEj = getMinValue(properties, + KEY_PREFIX_MIN_RATIO_EJ + mConfigIdentifier, WORK_TYPE_EJ, + 0, Math.min(maxEj, remaining)); mMinReservedSlots.put(WORK_TYPE_EJ, minEj); remaining -= minEj; // Ensure bg is in the range [0, min(maxBg, remaining)] - final int minBg = Math.max(0, Math.min(Math.min(maxBg, remaining), - properties.getInt(KEY_PREFIX_MIN_BG + mConfigIdentifier, - mDefaultMinReservedSlots.get(WORK_TYPE_BG)))); + final int minBg = getMinValue(properties, + KEY_PREFIX_MIN_RATIO_BG + mConfigIdentifier, WORK_TYPE_BG, + 0, Math.min(maxBg, remaining)); mMinReservedSlots.put(WORK_TYPE_BG, minBg); remaining -= minBg; // Ensure bg user imp is in the range [0, min(maxBgUserImp, remaining)] - final int minBgUserImp = Math.max(0, Math.min(Math.min(maxBgUserImp, remaining), - properties.getInt(KEY_PREFIX_MIN_BGUSER_IMPORTANT + mConfigIdentifier, - mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT, 0)))); + final int minBgUserImp = getMinValue(properties, + KEY_PREFIX_MIN_RATIO_BGUSER_IMPORTANT + mConfigIdentifier, + WORK_TYPE_BGUSER_IMPORTANT, 0, Math.min(maxBgUserImp, remaining)); mMinReservedSlots.put(WORK_TYPE_BGUSER_IMPORTANT, minBgUserImp); + remaining -= minBgUserImp; // Ensure bg user is in the range [0, min(maxBgUser, remaining)] - final int minBgUser = Math.max(0, Math.min(Math.min(maxBgUser, remaining), - properties.getInt(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier, - mDefaultMinReservedSlots.get(WORK_TYPE_BGUSER, 0)))); + final int minBgUser = getMinValue(properties, + KEY_PREFIX_MIN_RATIO_BGUSER + mConfigIdentifier, WORK_TYPE_BGUSER, + 0, Math.min(maxBgUser, remaining)); mMinReservedSlots.put(WORK_TYPE_BGUSER, minBgUser); } + /** + * Return the calculated max value for the work type. + * @param defaultFloatInIntBits A {@code float} value in int bits representation (using + * {@link Float#floatToIntBits(float)}. + */ + private int getMaxValue(@NonNull DeviceConfig.Properties properties, @NonNull String key, + int workType, int defaultFloatInIntBits) { + final float maxRatio = Math.min(1, properties.getFloat(key, + Float.intBitsToFloat( + mDefaultMaxAllowedSlotsRatio.get(workType, defaultFloatInIntBits)))); + // Max values should be in the range [1, total]. + return Math.max(1, (int) (mMaxTotal * maxRatio)); + } + + /** + * Return the calculated min value for the work type. + */ + private int getMinValue(@NonNull DeviceConfig.Properties properties, @NonNull String key, + int workType, int lowerLimit, int upperLimit) { + final float minRatio = Math.min(1, + properties.getFloat(key, + Float.intBitsToFloat(mDefaultMinReservedSlotsRatio.get(workType)))); + return Math.max(lowerLimit, Math.min(upperLimit, (int) (mMaxTotal * minRatio))); + } + int getMaxTotal() { return mMaxTotal; } @@ -2179,29 +2282,37 @@ class JobConcurrencyManager { void dump(IndentingPrintWriter pw) { pw.print(KEY_PREFIX_MAX_TOTAL + mConfigIdentifier, mMaxTotal).println(); - pw.print(KEY_PREFIX_MIN_TOP + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_TOP)) + pw.print(KEY_PREFIX_MIN_RATIO_TOP + mConfigIdentifier, + mMinReservedSlots.get(WORK_TYPE_TOP)) .println(); - pw.print(KEY_PREFIX_MAX_TOP + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_TOP)) + pw.print(KEY_PREFIX_MAX_RATIO_TOP + mConfigIdentifier, + mMaxAllowedSlots.get(WORK_TYPE_TOP)) .println(); - pw.print(KEY_PREFIX_MIN_FGS + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_FGS)) + pw.print(KEY_PREFIX_MIN_RATIO_FGS + mConfigIdentifier, + mMinReservedSlots.get(WORK_TYPE_FGS)) .println(); - pw.print(KEY_PREFIX_MAX_FGS + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_FGS)) + pw.print(KEY_PREFIX_MAX_RATIO_FGS + mConfigIdentifier, + mMaxAllowedSlots.get(WORK_TYPE_FGS)) .println(); - pw.print(KEY_PREFIX_MIN_EJ + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_EJ)) + pw.print(KEY_PREFIX_MIN_RATIO_EJ + mConfigIdentifier, + mMinReservedSlots.get(WORK_TYPE_EJ)) .println(); - pw.print(KEY_PREFIX_MAX_EJ + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_EJ)) + pw.print(KEY_PREFIX_MAX_RATIO_EJ + mConfigIdentifier, + mMaxAllowedSlots.get(WORK_TYPE_EJ)) .println(); - pw.print(KEY_PREFIX_MIN_BG + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BG)) + pw.print(KEY_PREFIX_MIN_RATIO_BG + mConfigIdentifier, + mMinReservedSlots.get(WORK_TYPE_BG)) .println(); - pw.print(KEY_PREFIX_MAX_BG + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BG)) + pw.print(KEY_PREFIX_MAX_RATIO_BG + mConfigIdentifier, + mMaxAllowedSlots.get(WORK_TYPE_BG)) .println(); - pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier, + pw.print(KEY_PREFIX_MIN_RATIO_BGUSER + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println(); - pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier, + pw.print(KEY_PREFIX_MAX_RATIO_BGUSER + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BGUSER_IMPORTANT)).println(); - pw.print(KEY_PREFIX_MIN_BGUSER + mConfigIdentifier, + pw.print(KEY_PREFIX_MIN_RATIO_BGUSER + mConfigIdentifier, mMinReservedSlots.get(WORK_TYPE_BGUSER)).println(); - pw.print(KEY_PREFIX_MAX_BGUSER + mConfigIdentifier, + pw.print(KEY_PREFIX_MAX_RATIO_BGUSER + mConfigIdentifier, mMaxAllowedSlots.get(WORK_TYPE_BGUSER)).println(); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java index 79fbc877835c6..7e1a42b679223 100644 --- a/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/job/JobConcurrencyManagerTest.java @@ -213,7 +213,7 @@ public final class JobConcurrencyManagerTest { mJobConcurrencyManager.prepareForAssignmentDeterminationLocked( idle, preferredUidOnly, stoppable, assignmentInfo); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, idle.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, idle.size()); assertEquals(0, preferredUidOnly.size()); assertEquals(0, stoppable.size()); assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); @@ -222,7 +222,7 @@ public final class JobConcurrencyManagerTest { @Test public void testPrepareForAssignmentDetermination_onlyPendingJobs() { - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i); mPendingJobQueue.add(job); } @@ -235,7 +235,7 @@ public final class JobConcurrencyManagerTest { mJobConcurrencyManager.prepareForAssignmentDeterminationLocked( idle, preferredUidOnly, stoppable, assignmentInfo); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, idle.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, idle.size()); assertEquals(0, preferredUidOnly.size()); assertEquals(0, stoppable.size()); assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); @@ -244,7 +244,7 @@ public final class JobConcurrencyManagerTest { @Test public void testPrepareForAssignmentDetermination_onlyPreferredUidOnly() { - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i); mJobConcurrencyManager.addRunningJobForTesting(job); } @@ -262,7 +262,7 @@ public final class JobConcurrencyManagerTest { idle, preferredUidOnly, stoppable, assignmentInfo); assertEquals(0, idle.size()); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); assertEquals(0, stoppable.size()); assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); assertEquals(0, assignmentInfo.numRunningImmediacyPrivileged); @@ -270,7 +270,7 @@ public final class JobConcurrencyManagerTest { @Test public void testPrepareForAssignmentDetermination_onlyStartedWithImmediacyPrivilege() { - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i); job.startedWithImmediacyPrivilege = true; mJobConcurrencyManager.addRunningJobForTesting(job); @@ -289,19 +289,19 @@ public final class JobConcurrencyManagerTest { idle, preferredUidOnly, stoppable, assignmentInfo); assertEquals(0, idle.size()); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT / 2, preferredUidOnly.size()); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT / 2, stoppable.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT / 2, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT / 2, stoppable.size()); assertEquals(0, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, assignmentInfo.numRunningImmediacyPrivileged); } @Test public void testDetermineAssignments_allRegular() throws Exception { - setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, - new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT)); + setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, + new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT)); final ArraySet jobs = new ArraySet<>(); - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i; final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid); setPackageUid(sourcePkgName, uid); @@ -322,7 +322,7 @@ public final class JobConcurrencyManagerTest { .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable, assignmentInfo); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, changed.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, changed.size()); for (int i = changed.size() - 1; i >= 0; --i) { jobs.remove(changed.valueAt(i).newJob); } @@ -332,16 +332,16 @@ public final class JobConcurrencyManagerTest { @Test public void testDetermineAssignments_allPreferredUidOnly_shortTimeLeft() throws Exception { mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true); - setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, - new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT)); - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) { + setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, + new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT)); + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) { final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i; final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid); setPackageUid(sourcePkgName, uid); final JobStatus job = createJob(uid, sourcePkgName); spyOn(job); doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob(); - if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) { + if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) { mJobConcurrencyManager.addRunningJobForTesting(job); } else { mPendingJobQueue.add(job); @@ -366,30 +366,30 @@ public final class JobConcurrencyManagerTest { mJobConcurrencyManager.prepareForAssignmentDeterminationLocked( idle, preferredUidOnly, stoppable, assignmentInfo); assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); mJobConcurrencyManager .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable, assignmentInfo); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); assertEquals(0, changed.size()); } @Test public void testDetermineAssignments_allPreferredUidOnly_mediumTimeLeft() throws Exception { mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true); - setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, - new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT)); + setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, + new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT)); final ArraySet jobs = new ArraySet<>(); - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) { final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i; final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid); setPackageUid(sourcePkgName, uid); final JobStatus job = createJob(uid, sourcePkgName); spyOn(job); doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob(); - if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) { + if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) { mJobConcurrencyManager.addRunningJobForTesting(job); } else { mPendingJobQueue.add(job); @@ -417,17 +417,17 @@ public final class JobConcurrencyManagerTest { mJobConcurrencyManager.prepareForAssignmentDeterminationLocked( idle, preferredUidOnly, stoppable, assignmentInfo); assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); mJobConcurrencyManager .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable, assignmentInfo); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); for (int i = changed.size() - 1; i >= 0; --i) { jobs.remove(changed.valueAt(i).newJob); } - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT - 1, jobs.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT - 1, jobs.size()); assertEquals(1, changed.size()); JobStatus assignedJob = changed.valueAt(0).newJob; assertTrue(assignedJob.shouldTreatAsExpeditedJob()); @@ -436,17 +436,17 @@ public final class JobConcurrencyManagerTest { @Test public void testDetermineAssignments_allPreferredUidOnly_longTimeLeft() throws Exception { mConfigBuilder.setBoolean(JobConcurrencyManager.KEY_ENABLE_MAX_WAIT_TIME_BYPASS, true); - setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, - new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT)); + setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, + new TypeConfig(WORK_TYPE_BG, 0, JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT)); final ArraySet jobs = new ArraySet<>(); - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT * 2; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT * 2; ++i) { final int uid = mDefaultUserId * UserHandle.PER_USER_RANGE + i; final String sourcePkgName = "com.source.package." + UserHandle.getAppId(uid); setPackageUid(sourcePkgName, uid); final JobStatus job = createJob(uid, sourcePkgName); spyOn(job); doReturn(i % 2 == 0).when(job).shouldTreatAsExpeditedJob(); - if (i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT) { + if (i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT) { mJobConcurrencyManager.addRunningJobForTesting(job); } else { mPendingJobQueue.add(job); @@ -473,13 +473,13 @@ public final class JobConcurrencyManagerTest { mJobConcurrencyManager.prepareForAssignmentDeterminationLocked( idle, preferredUidOnly, stoppable, assignmentInfo); assertEquals(remainingTimeMs, assignmentInfo.minPreferredUidOnlyWaitingTimeMs); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); mJobConcurrencyManager .determineAssignmentsLocked(changed, idle, preferredUidOnly, stoppable, assignmentInfo); - assertEquals(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT, preferredUidOnly.size()); + assertEquals(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT, preferredUidOnly.size()); // Depending on iteration order, we may create 1 or 2 contexts. final long numAssignedJobs = changed.size(); assertTrue(numAssignedJobs > 0); @@ -488,7 +488,7 @@ public final class JobConcurrencyManagerTest { jobs.remove(changed.valueAt(i).newJob); } assertEquals(numAssignedJobs, - JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT - jobs.size()); + JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT - jobs.size()); JobStatus firstAssignedJob = changed.valueAt(0).newJob; if (!firstAssignedJob.shouldTreatAsExpeditedJob()) { assertEquals(2, numAssignedJobs); @@ -538,14 +538,14 @@ public final class JobConcurrencyManagerTest { assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob)); // Pending jobs shouldn't affect TOP job's status. - for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 1; i <= JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i); mPendingJobQueue.add(job); } assertFalse(mJobConcurrencyManager.isPkgConcurrencyLimitedLocked(topJob)); // Already running jobs shouldn't affect TOP job's status. - for (int i = 1; i <= JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 1; i <= JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE, i); mJobConcurrencyManager.addRunningJobForTesting(job); } @@ -605,9 +605,9 @@ public final class JobConcurrencyManagerTest { spyOn(testEj); doReturn(true).when(testEj).shouldTreatAsExpeditedJob(); - setConcurrencyConfig(JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT); + setConcurrencyConfig(JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT); - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { final JobStatus job = createJob(mDefaultUserId * UserHandle.PER_USER_RANGE + i, i + 1); mPendingJobQueue.add(job); } @@ -887,12 +887,14 @@ public final class JobConcurrencyManagerTest { mConfigBuilder .setInt(WorkTypeConfig.KEY_PREFIX_MAX_TOTAL + identifier, total); for (TypeConfig config : typeConfigs) { - mConfigBuilder.setInt( - WorkTypeConfig.KEY_PREFIX_MAX + config.workTypeString + "_" + identifier, - config.max); - mConfigBuilder.setInt( - WorkTypeConfig.KEY_PREFIX_MIN + config.workTypeString + "_" + identifier, - config.min); + mConfigBuilder.setFloat( + WorkTypeConfig.KEY_PREFIX_MAX_RATIO + config.workTypeString + "_" + + identifier, + (float) config.max / total); + mConfigBuilder.setFloat( + WorkTypeConfig.KEY_PREFIX_MIN_RATIO + config.workTypeString + "_" + + identifier, + (float) config.min / total); } } updateDeviceConfig(); diff --git a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java index e886e7dc1d60e..56d01b0e3a2ab 100644 --- a/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java +++ b/services/tests/servicestests/src/com/android/server/job/BiasSchedulingTest.java @@ -57,14 +57,14 @@ public class BiasSchedulingTest extends AndroidTestCase { } public void testLowerBiasJobPreempted() throws Exception { - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.MAX_CONCURRENCY_LIMIT; ++i) { JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent) .setBias(LOW_BIAS) .setOverrideDeadline(0) .build(); mJobScheduler.schedule(job); } - final int higherBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; + final int higherBiasJobId = 100 + JobConcurrencyManager.MAX_CONCURRENCY_LIMIT; JobInfo jobHigher = new JobInfo.Builder(higherBiasJobId, sJobServiceComponent) .setBias(HIGH_BIAS) .setMinimumLatency(2000) @@ -88,14 +88,14 @@ public class BiasSchedulingTest extends AndroidTestCase { } public void testHigherBiasJobNotPreempted() throws Exception { - for (int i = 0; i < JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; ++i) { + for (int i = 0; i < JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; ++i) { JobInfo job = new JobInfo.Builder(100 + i, sJobServiceComponent) .setBias(HIGH_BIAS) .setOverrideDeadline(0) .build(); mJobScheduler.schedule(job); } - final int lowerBiasJobId = 100 + JobConcurrencyManager.STANDARD_CONCURRENCY_LIMIT; + final int lowerBiasJobId = 100 + JobConcurrencyManager.DEFAULT_CONCURRENCY_LIMIT; JobInfo jobLower = new JobInfo.Builder(lowerBiasJobId, sJobServiceComponent) .setBias(LOW_BIAS) .setMinimumLatency(2000) 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 dd9ae6592f5cb..0fd6a9e9248a5 100644 --- a/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/job/WorkCountTrackerTest.java @@ -16,6 +16,7 @@ package com.android.server.job; +import static com.android.server.job.JobConcurrencyManager.MAX_CONCURRENCY_LIMIT; import static com.android.server.job.JobConcurrencyManager.NUM_WORK_TYPES; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BG; import static com.android.server.job.JobConcurrencyManager.WORK_TYPE_BGUSER; @@ -191,10 +192,10 @@ public class WorkCountTrackerTest { } private void recount(Jobs jobs, int totalMax, - @NonNull List> minLimits, - @NonNull List> maxLimits) { + @NonNull List> minLimitRatios, + @NonNull List> maxLimitRatios) { mWorkCountTracker.setConfig(new JobConcurrencyManager.WorkTypeConfig( - "test", totalMax, minLimits, maxLimits)); + "test", MAX_CONCURRENCY_LIMIT, totalMax, minLimitRatios, maxLimitRatios)); mWorkCountTracker.resetCounts(); for (int i = 0; i < jobs.running.size(); ++i) { @@ -259,18 +260,18 @@ public class WorkCountTrackerTest { * Used by the following testRandom* tests. */ private void checkRandom(Jobs jobs, int numTests, int totalMax, - @NonNull List> minLimits, - @NonNull List> maxLimits, + @NonNull List> minLimitRatios, + @NonNull List> maxLimitRatios, double probStart, double[] typeCdf, double[] numTypesCdf, double probStop) { int minExpected = 0; - for (Pair minLimit : minLimits) { - minExpected = Math.min(minLimit.second, minExpected); + for (Pair minLimit : minLimitRatios) { + minExpected = Math.min((int) (minLimit.second * MAX_CONCURRENCY_LIMIT), minExpected); } for (int i = 0; i < numTests; i++) { jobs.maybeFinishJobs(probStop); jobs.maybeEnqueueJobs(probStart, typeCdf, numTypesCdf); - recount(jobs, totalMax, minLimits, maxLimits); + recount(jobs, totalMax, minLimitRatios, maxLimitRatios); final int numPending = jobs.pendingMultiTypes.size(); startPendingJobs(jobs); @@ -284,9 +285,11 @@ public class WorkCountTrackerTest { } assertThat(totalRunning).isAtMost(totalMax); assertThat(totalRunning).isAtLeast(Math.min(minExpected, numPending)); - for (Pair maxLimit : maxLimits) { - assertWithMessage("Work type " + maxLimit.first + " is running too many jobs") - .that(jobs.running.get(maxLimit.first)).isAtMost(maxLimit.second); + for (Pair maxLimitRatio : maxLimitRatios) { + final int workType = maxLimitRatio.first; + final int maxLimit = (int) (maxLimitRatio.second * MAX_CONCURRENCY_LIMIT); + assertWithMessage("Work type " + workType + " is running too many jobs") + .that(jobs.running.get(workType)).isAtMost(maxLimit); } } } @@ -302,12 +305,14 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4)); - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3)); final double probStop = 0.1; final double probStart = 0.1; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, EQUAL_PROBABILITY_CDF, EQUAL_PROBABILITY_CDF, probStop); } @@ -317,15 +322,15 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 2; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); - final List> minLimits = List.of(); + final List> minLimitRatios = List.of(); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, .5f)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(0.5, 0, 0, 0.5, 0, 0); final double[] numTypesCdf = buildCdf(.5, .3, .15, .05); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -335,15 +340,15 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 2; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = List.of(Pair.create(WORK_TYPE_BG, .99f)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, .5f)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3); final double[] numTypesCdf = buildCdf(.75, .2, .05); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -353,15 +358,15 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 10; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); - final List> minLimits = List.of(); + final List> minLimitRatios = List.of(); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, .2f), Pair.create(WORK_TYPE_BGUSER, .1f)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(1.0 / 3, 0, 0, 1.0 / 3, 0, 1.0 / 3); final double[] numTypesCdf = buildCdf(.05, .95); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -371,15 +376,17 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 2.0f / 3)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.8, 0.02, .08); final double[] numTypesCdf = buildCdf(.5, .3, .15, .05); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -389,15 +396,17 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(0.85, 0.05, 0, 0.1, 0, 0); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -407,15 +416,17 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)); final double probStop = 0.4; final double[] cdf = buildWorkTypeCdf(0.1, 0, 0, 0.1, 0.05, .75); final double[] numTypesCdf = buildCdf(0.5, 0.5); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -425,16 +436,18 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)); final double probStop = 0.4; final double[] cdf = buildWorkTypeCdf(0.8, 0.1, 0, 0.05, 0, 0.05); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -444,16 +457,18 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.5, 0, 0.5); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -463,16 +478,18 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.1, 0, 0.9); final double[] numTypesCdf = buildCdf(0.9, 0.1); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -482,16 +499,18 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_BG, 2), Pair.create(WORK_TYPE_BGUSER, 1)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)); final double probStop = 0.5; final double[] cdf = buildWorkTypeCdf(0, 0, 0, 0.9, 0, 0.1); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -501,15 +520,16 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 4)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 3), Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3)); final double probStop = 0.4; final double[] cdf = buildWorkTypeCdf(0.5, 0, 0.5, 0, 0, 0); final double[] numTypesCdf = buildCdf(0.1, 0.7, 0.2); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -522,16 +542,16 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 13; - final List> maxLimits = List.of( - Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4), - Pair.create(WORK_TYPE_BGUSER, 3)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 1)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 2.0f / 13), Pair.create(WORK_TYPE_BG, 1.0f / 13)); + final List> maxLimitRatios = List.of( + Pair.create(WORK_TYPE_EJ, 5.0f / 13), Pair.create(WORK_TYPE_BG, 4.0f / 13), + Pair.create(WORK_TYPE_BGUSER, 3.0f / 13)); final double probStop = 0.13; final double[] numTypesCdf = buildCdf(0, 0.05, 0.1, 0.7, 0.1, 0.05); final double probStart = 0.87; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, EQUAL_PROBABILITY_CDF, numTypesCdf, probStop); } @@ -541,15 +561,16 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4)); - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 5.0f / 6), Pair.create(WORK_TYPE_BG, 2.0f / 3)); final double probStop = 0.4; final double[] cdf = buildWorkTypeCdf(.1, 0, 0.5, 0.35, 0, 0.05); final double[] numTypesCdf = buildCdf(1); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -559,17 +580,17 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 6; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4), - Pair.create(WORK_TYPE_BGUSER, 1)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, .5f), Pair.create(WORK_TYPE_BG, 1.0f / 3)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 5.0f / 6), Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)); final double probStop = 0.4; final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.4, 0.1, 0, 0.4); final double[] numTypesCdf = buildCdf(0.7, 0.3); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } @@ -579,25 +600,25 @@ public class WorkCountTrackerTest { final int numTests = 5000; final int totalMax = 7; - final List> maxLimits = - List.of(Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 4), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1), - Pair.create(WORK_TYPE_BGUSER, 1)); - final List> minLimits = - List.of(Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 2)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 3.0f / 7), Pair.create(WORK_TYPE_BG, 2.0f / 7)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 5.0f / 7), Pair.create(WORK_TYPE_BG, 4.0f / 7), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 1.0f / 7), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 7)); final double probStop = 0.4; final double[] cdf = buildWorkTypeCdf(0.01, 0.09, 0.25, 0.05, 0.3, 0.3); final double[] numTypesCdf = buildCdf(0.7, 0.3); final double probStart = 0.5; - checkRandom(jobs, numTests, totalMax, minLimits, maxLimits, probStart, + checkRandom(jobs, numTests, totalMax, minLimitRatios, maxLimitRatios, probStart, cdf, numTypesCdf, probStop); } /** Used by the following tests */ private void checkSimple(int totalMax, - @NonNull List> minLimits, - @NonNull List> maxLimits, + @NonNull List> minLimitRatios, + @NonNull List> maxLimitRatios, @NonNull List> running, @NonNull List> pending, @NonNull List> resultRunning, @@ -610,17 +631,19 @@ public class WorkCountTrackerTest { jobs.addPending(pend.first, pend.second); } - recount(jobs, totalMax, minLimits, maxLimits); + recount(jobs, totalMax, minLimitRatios, maxLimitRatios); startPendingJobs(jobs); for (Pair run : resultRunning) { assertWithMessage( - "Incorrect running result for work type " + workTypeToString(run.first)) + "Incorrect running result for work type " + workTypeToString(run.first) + + " wanted " + run.second + ", got " + jobs.running.get(run.first)) .that(jobs.running.get(run.first)).isEqualTo(run.second); } for (Pair pend : resultPending) { assertWithMessage( - "Incorrect pending result for work type " + workTypeToString(pend.first)) + "Incorrect pending result for work type " + workTypeToString(pend.first) + + " wanted " + pend.second + ", got " + jobs.pending.get(pend.first)) .that(jobs.pending.get(pend.first)).isEqualTo(pend.second); } } @@ -628,16 +651,18 @@ public class WorkCountTrackerTest { @Test public void testBasic() { checkSimple(6, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)), /* 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), Pair.create(WORK_TYPE_BGUSER, 2)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)), /* run */ List.of(), /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10)), /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 6)), @@ -645,39 +670,40 @@ public class WorkCountTrackerTest { // When there are BG jobs pending, 2 (min-BG) jobs should run. checkSimple(6, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)), /* 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3)), /* 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)), /* 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)), /* 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_BG, 6)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)), /* run */ List.of(Pair.create(WORK_TYPE_TOP, 2), Pair.create(WORK_TYPE_BG, 4)), /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 49), Pair.create(WORK_TYPE_BG, 49)), /* resRun */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4)), @@ -686,48 +712,52 @@ public class WorkCountTrackerTest { 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)), + /* max */ + List.of(Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .75f)), /* 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .25f)), + /* max */ List.of( + Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .75f)), /* 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 8)), + /* max */ List.of( + Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .25f)), /* 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(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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 8)), + /* max */ + List.of(Pair.create(WORK_TYPE_TOP, .75f), Pair.create(WORK_TYPE_BG, .25f)), /* 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)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3)), /* 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))); checkSimple(8, - /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 4)), + /* min */ List.of(Pair.create(WORK_TYPE_EJ, .25f), Pair.create(WORK_TYPE_BG, .25f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .75f)), /* run */ List.of(Pair.create(WORK_TYPE_TOP, 6)), /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_EJ, 5), Pair.create(WORK_TYPE_BG, 3)), @@ -740,15 +770,16 @@ public class WorkCountTrackerTest { // shouldn't start new ones. checkSimple(5, /* min */ List.of(), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .2f)), /* 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))); checkSimple(6, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)), /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)), /* pen */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 3), @@ -759,8 +790,9 @@ public class WorkCountTrackerTest { Pair.create(WORK_TYPE_BGUSER, 3))); checkSimple(6, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 3)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of( + Pair.create(WORK_TYPE_BG, 2.0f / 3), Pair.create(WORK_TYPE_BGUSER, .5f)), /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)), /* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)), /* resRun */ List.of( @@ -769,8 +801,9 @@ public class WorkCountTrackerTest { Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))); checkSimple(6, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 2)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, 1.0f / 3)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)), /* run */ List.of(Pair.create(WORK_TYPE_BG, 2)), /* pen */ List.of(Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 3)), /* resRun */ List.of( @@ -778,12 +811,13 @@ public class WorkCountTrackerTest { /* resPen */ List.of( Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 2))); - Log.d(TAG, "START***#*#*#*#*#*#**#*"); // Test multi-types checkSimple(6, - /* min */ List.of(Pair.create(WORK_TYPE_EJ, 2), Pair.create(WORK_TYPE_BG, 2)), + /* min */ + List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 3), Pair.create(WORK_TYPE_BG, 1.0f / 3)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 1)), + Pair.create(WORK_TYPE_BG, 2.0f / 3), + Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)), /* run */ List.of(), /* pen */ List.of( // 2 of these as TOP, 1 as EJ @@ -809,10 +843,12 @@ public class WorkCountTrackerTest { jobs.addPending(WORK_TYPE_BG, 10); final int totalMax = 6; - final List> minLimits = List.of(Pair.create(WORK_TYPE_BG, 1)); - final List> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 1.0f / totalMax)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 5.0f / totalMax)); - recount(jobs, totalMax, minLimits, maxLimits); + recount(jobs, totalMax, minLimitRatios, maxLimitRatios); startPendingJobs(jobs); @@ -887,11 +923,12 @@ public class WorkCountTrackerTest { jobs.addPending(WORK_TYPE_BG, 10); // c final int totalMax = 8; - final List> minLimits = - List.of(Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)); - final List> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 8), Pair.create(WORK_TYPE_BG, 1.0f / 8)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 5.0f / 8)); - recount(jobs, totalMax, minLimits, maxLimits); + recount(jobs, totalMax, minLimitRatios, maxLimitRatios); assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(11); assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(5); @@ -966,11 +1003,12 @@ public class WorkCountTrackerTest { } final int totalMax = 8; - final List> minLimits = - List.of(Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)); - final List> maxLimits = List.of(Pair.create(WORK_TYPE_BG, 5)); + final List> minLimitRatios = + List.of(Pair.create(WORK_TYPE_EJ, 1.0f / 8), Pair.create(WORK_TYPE_BG, 1.0f / 8)); + final List> maxLimitRatios = + List.of(Pair.create(WORK_TYPE_BG, 5.0f / 8)); - recount(jobs, totalMax, minLimits, maxLimits); + recount(jobs, totalMax, minLimitRatios, maxLimitRatios); assertThat(jobs.pending.get(WORK_TYPE_TOP)).isEqualTo(11); assertThat(jobs.pending.get(WORK_TYPE_EJ)).isEqualTo(10); diff --git a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java index 21d27848bc577..bd5a063b1484c 100644 --- a/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java +++ b/services/tests/servicestests/src/com/android/server/job/WorkTypeConfigTest.java @@ -45,23 +45,26 @@ import java.util.List; @SmallTest public class WorkTypeConfigTest { private static final String KEY_MAX_TOTAL = "concurrency_max_total_test"; - private static final String KEY_MAX_TOP = "concurrency_max_top_test"; - private static final String KEY_MAX_FGS = "concurrency_max_fgs_test"; - private static final String KEY_MAX_EJ = "concurrency_max_ej_test"; - private static final String KEY_MAX_BG = "concurrency_max_bg_test"; - private static final String KEY_MAX_BGUSER_IMPORTANT = "concurrency_max_bguser_important_test"; - private static final String KEY_MAX_BGUSER = "concurrency_max_bguser_test"; - private static final String KEY_MIN_TOP = "concurrency_min_top_test"; - private static final String KEY_MIN_FGS = "concurrency_min_fgs_test"; - private static final String KEY_MIN_EJ = "concurrency_min_ej_test"; - private static final String KEY_MIN_BG = "concurrency_min_bg_test"; - private static final String KEY_MIN_BGUSER_IMPORTANT = "concurrency_min_bguser_important_test"; - private static final String KEY_MIN_BGUSER = "concurrency_min_bguser_test"; + private static final String KEY_MAX_RATIO_TOP = "concurrency_max_ratio_top_test"; + private static final String KEY_MAX_RATIO_FGS = "concurrency_max_ratio_fgs_test"; + private static final String KEY_MAX_RATIO_EJ = "concurrency_max_ratio_ej_test"; + private static final String KEY_MAX_RATIO_BG = "concurrency_max_ratio_bg_test"; + private static final String KEY_MAX_RATIO_BGUSER_IMPORTANT = + "concurrency_max_ratio_bguser_important_test"; + private static final String KEY_MAX_RATIO_BGUSER = "concurrency_max_ratio_bguser_test"; + private static final String KEY_MIN_RATIO_TOP = "concurrency_min_ratio_top_test"; + private static final String KEY_MIN_RATIO_FGS = "concurrency_min_ratio_fgs_test"; + private static final String KEY_MIN_RATIO_EJ = "concurrency_min_ratio_ej_test"; + private static final String KEY_MIN_RATIO_BG = "concurrency_min_ratio_bg_test"; + private static final String KEY_MIN_RATIO_BGUSER_IMPORTANT = + "concurrency_min_ratio_bguser_important_test"; + private static final String KEY_MIN_RATIO_BGUSER = "concurrency_min_ratio_bguser_test"; private void check(@Nullable DeviceConfig.Properties config, + int defaultLimit, int defaultTotal, - @NonNull List> defaultMin, - @NonNull List> defaultMax, + @NonNull List> defaultMinRatios, + @NonNull List> defaultMaxRatios, boolean expectedValid, int expectedTotal, @NonNull List> expectedMinLimits, @NonNull List> expectedMaxLimits) throws Exception { @@ -69,7 +72,7 @@ public class WorkTypeConfigTest { final WorkTypeConfig counts; try { counts = new WorkTypeConfig("test", - defaultTotal, defaultMin, defaultMax); + defaultLimit, defaultTotal, defaultMinRatios, defaultMaxRatios); if (!expectedValid) { fail("Invalid config successfully created"); return; @@ -84,7 +87,7 @@ public class WorkTypeConfigTest { } if (config != null) { - counts.update(config); + counts.update(config, defaultLimit); } assertEquals(expectedTotal, counts.getMaxTotal()); @@ -101,7 +104,7 @@ public class WorkTypeConfigTest { @Test public void test() throws Exception { // Tests with various combinations. - check(null, /*default*/ 13, + check(null, /* limit */ 16, /*default*/ 13, /* min */ List.of(), /* max */ List.of(), /*expected*/ true, 13, @@ -109,111 +112,141 @@ public class WorkTypeConfigTest { Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 13), Pair.create(WORK_TYPE_EJ, 13), Pair.create(WORK_TYPE_BG, 13), Pair.create(WORK_TYPE_BGUSER, 13))); - check(null, /*default*/ 5, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 0)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)), + check(null, /* limit */ 16, /*default*/ 5, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, .8f), Pair.create(WORK_TYPE_BG, 0f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .2f)), /*expected*/ true, 5, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1))); - check(null, /*default*/ 5, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5), - Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)), + check(null, /* limit */ 16, /*default*/ 5, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1f), + Pair.create(WORK_TYPE_BG, 0f), Pair.create(WORK_TYPE_BGUSER, 0f)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 1)), - /*expected*/ true, 5, + Pair.create(WORK_TYPE_BG, 0f), Pair.create(WORK_TYPE_BGUSER, .2f)), + /*expected*/ false, 5, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))); - check(null, /*default*/ 0, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 0)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 0)), - /*expected*/ false, 1, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)), - /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1))); - check(null, /*default*/ -1, - /* min */ List.of(Pair.create(WORK_TYPE_BG, -1)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, -1)), - /*expected*/ false, 1, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)), - /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1))); - check(null, /*default*/ 5, - /* min */ List.of( - Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 0)), + check(null, /* limit */ 16, /*default*/ 5, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, .99f), + Pair.create(WORK_TYPE_BG, 0f), Pair.create(WORK_TYPE_BGUSER, 0f)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)), + Pair.create(WORK_TYPE_BG, .01f), Pair.create(WORK_TYPE_BGUSER, .2f)), + /*expected*/ true, 5, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), + Pair.create(WORK_TYPE_BG, 0), Pair.create(WORK_TYPE_BGUSER, 0)), + /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), + Pair.create(WORK_TYPE_BG, 1), Pair.create(WORK_TYPE_BGUSER, 1))); + check(null, /* limit */ 16, /*default*/ 0, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1f), Pair.create(WORK_TYPE_BG, 0f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 0f)), + /*expected*/ false, 1, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)), + /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1))); + check(null, /* limit */ 16, /*default*/ -1, + /* min */ List.of(Pair.create(WORK_TYPE_BG, -1f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, -1f)), + /*expected*/ false, 1, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 0)), + /* max */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 1))); + check(null, /* limit */ 16, /*default*/ 5, + /* min */ List.of( + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 0f)), + /* max */ List.of( + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)), + /*expected*/ false, 5, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), + Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 0)), + /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), + Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5))); + check(null, /* limit */ 16, /*default*/ 5, + /* min */ List.of( + Pair.create(WORK_TYPE_BG, .99f), Pair.create(WORK_TYPE_BGUSER, 0f)), + /* max */ List.of( + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)), /*expected*/ true, 5, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5))); - check(null, /*default*/ 6, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), - Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 2)), + check(null, /* limit */ 16, /*default*/ 6, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1.0f / 6), + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1.0f / 3)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 1)), + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1.0f / 6)), /*expected*/ false, 6, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 6), Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 1))); - check(null, /*default*/ 4, + check(null, /* limit */ 16, /*default*/ 4, /* min */ List.of( - Pair.create(WORK_TYPE_BG, 6), Pair.create(WORK_TYPE_BGUSER, 6)), + Pair.create(WORK_TYPE_BG, 1.5f), Pair.create(WORK_TYPE_BGUSER, 1.5f)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 5), Pair.create(WORK_TYPE_BGUSER, 5)), + Pair.create(WORK_TYPE_BG, 1.25f), Pair.create(WORK_TYPE_BGUSER, 1.25f)), /*expected*/ false, 4, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3), Pair.create(WORK_TYPE_BGUSER, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 4))); - check(null, /*default*/ 5, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)), + check(null, /* limit */ 16, /*default*/ 5, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, .8f), Pair.create(WORK_TYPE_BG, .2f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .2f)), /*expected*/ true, 5, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_BG, 1)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 1))); - check(null, /*default*/ 10, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3), - Pair.create(WORK_TYPE_BG, 1)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 1)), + check(null, /* limit */ 16, /*default*/ 10, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, .4f), Pair.create(WORK_TYPE_EJ, .3f), + Pair.create(WORK_TYPE_BG, .1f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, .1f)), /*expected*/ true, 10, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 4), Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 1)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 10), Pair.create(WORK_TYPE_BG, 1))); - check(null, /*default*/ 10, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)), - /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3)), + check(null, /* limit */ 16, /*default*/ 10, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, .3f), Pair.create(WORK_TYPE_FGS, .2f), + Pair.create(WORK_TYPE_EJ, .1f), Pair.create(WORK_TYPE_BG, .1f)), + /* max */ List.of(Pair.create(WORK_TYPE_FGS, .3f)), /*expected*/ true, 10, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 3), Pair.create(WORK_TYPE_FGS, 2), Pair.create(WORK_TYPE_EJ, 1), Pair.create(WORK_TYPE_BG, 1)), /* max */ List.of(Pair.create(WORK_TYPE_FGS, 3))); - check(null, /*default*/ 15, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 15)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 15)), + check(null, /* limit */ 16, /*default*/ 15, + /* min */ List.of(Pair.create(WORK_TYPE_BG, .95f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 15, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 14)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 15), Pair.create(WORK_TYPE_BG, 15))); - check(null, /*default*/ 16, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 16)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 16)), + check(null, /* limit */ 16, /*default*/ 16, + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 16, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16))); - check(null, /*default*/ 20, + check(null, /* limit */ 16, /*default*/ 20, /* min */ List.of( - Pair.create(WORK_TYPE_BG, 20), Pair.create(WORK_TYPE_BGUSER, 10)), + Pair.create(WORK_TYPE_BG, .99f), Pair.create(WORK_TYPE_BGUSER, .5f)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 20), Pair.create(WORK_TYPE_BGUSER, 20)), + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)), /*expected*/ false, 16, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15), Pair.create(WORK_TYPE_BGUSER, 0)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16), Pair.create(WORK_TYPE_BGUSER, 16))); - check(null, /*default*/ 20, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 16)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 16)), + check(null, /* limit */ 76, /*default*/ 80, + /* min */ List.of( + Pair.create(WORK_TYPE_BG, .98f), Pair.create(WORK_TYPE_BGUSER, .9f)), + /* max */ List.of( + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, 1f)), + /*expected*/ false, 64, + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), + Pair.create(WORK_TYPE_BG, 63), Pair.create(WORK_TYPE_BGUSER, 0)), + /* max */ List.of(Pair.create(WORK_TYPE_TOP, 64), + Pair.create(WORK_TYPE_BG, 64), Pair.create(WORK_TYPE_BGUSER, 64))); + check(null, /* limit */ 16, /*default*/ 20, + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 16, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 15)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16))); @@ -221,94 +254,101 @@ public class WorkTypeConfigTest { // Test for overriding with a setting string. check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) .setInt(KEY_MAX_TOTAL, 5) - .setInt(KEY_MAX_BG, 4) - .setInt(KEY_MIN_BG, 3) + .setFloat(KEY_MAX_RATIO_BG, .8f) + .setFloat(KEY_MIN_RATIO_BG, .6f) .build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), /* max */ List.of( - Pair.create(WORK_TYPE_BG, 9), Pair.create(WORK_TYPE_BGUSER, 2)), + Pair.create(WORK_TYPE_BG, 1f), Pair.create(WORK_TYPE_BGUSER, .4f)), /*expected*/ true, 5, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 4), Pair.create(WORK_TYPE_BGUSER, 2))); check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) .setInt(KEY_MAX_TOTAL, 5).build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 5, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 5), Pair.create(WORK_TYPE_BG, 5))); check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) - .setInt(KEY_MAX_BG, 4).build(), + .setFloat(KEY_MAX_RATIO_BG, 4.0f / 9).build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 9, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 4)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 9), Pair.create(WORK_TYPE_BG, 4))); check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) - .setInt(KEY_MIN_BG, 3).build(), + .setFloat(KEY_MIN_RATIO_BG, 1.0f / 3).build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 9, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 3)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 9), Pair.create(WORK_TYPE_BG, 9))); check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) .setInt(KEY_MAX_TOTAL, 20) - .setInt(KEY_MAX_EJ, 5) - .setInt(KEY_MIN_EJ, 2) - .setInt(KEY_MAX_BG, 16) - .setInt(KEY_MIN_BG, 8) + .setFloat(KEY_MAX_RATIO_EJ, .25f) + .setFloat(KEY_MIN_RATIO_EJ, .1f) + .setFloat(KEY_MAX_RATIO_BG, .8f) + .setFloat(KEY_MIN_RATIO_BG, .4f) .build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 16, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_EJ, 2), - Pair.create(WORK_TYPE_BG, 8)), + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_EJ, 1), + Pair.create(WORK_TYPE_BG, 6)), /* max */ - List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_EJ, 5), - Pair.create(WORK_TYPE_BG, 16))); + List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_EJ, 4), + Pair.create(WORK_TYPE_BG, 12))); check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) .setInt(KEY_MAX_TOTAL, 20) - .setInt(KEY_MAX_BG, 20) - .setInt(KEY_MIN_BG, 8) + .setFloat(KEY_MAX_RATIO_BG, 1f) + .setFloat(KEY_MIN_RATIO_BG, .4f) .build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 16, - /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 8)), + /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_BG, 6)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_BG, 16))); check(new DeviceConfig.Properties.Builder(DeviceConfig.NAMESPACE_JOB_SCHEDULER) .setInt(KEY_MAX_TOTAL, 16) - .setInt(KEY_MAX_TOP, 16) - .setInt(KEY_MIN_TOP, 1) - .setInt(KEY_MAX_FGS, 15) - .setInt(KEY_MIN_FGS, 2) - .setInt(KEY_MAX_EJ, 14) - .setInt(KEY_MIN_EJ, 3) - .setInt(KEY_MAX_BG, 13) - .setInt(KEY_MIN_BG, 4) - .setInt(KEY_MAX_BGUSER_IMPORTANT, 12) - .setInt(KEY_MIN_BGUSER_IMPORTANT, 5) - .setInt(KEY_MAX_BGUSER, 11) - .setInt(KEY_MIN_BGUSER, 6) + .setFloat(KEY_MAX_RATIO_TOP, 1f) + .setFloat(KEY_MIN_RATIO_TOP, 1.0f / 16) + .setFloat(KEY_MAX_RATIO_FGS, 15.0f / 16) + .setFloat(KEY_MIN_RATIO_FGS, 2.0f / 16) + .setFloat(KEY_MAX_RATIO_EJ, 14.0f / 16) + .setFloat(KEY_MIN_RATIO_EJ, 3.0f / 16) + .setFloat(KEY_MAX_RATIO_BG, 13.0f / 16) + .setFloat(KEY_MIN_RATIO_BG, 3.0f / 16) + .setFloat(KEY_MAX_RATIO_BGUSER_IMPORTANT, 12.0f / 16) + .setFloat(KEY_MIN_RATIO_BGUSER_IMPORTANT, 2.0f / 16) + .setFloat(KEY_MAX_RATIO_BGUSER, 11.0f / 16) + .setFloat(KEY_MIN_RATIO_BGUSER, 2.0f / 16) .build(), + /* limit */ 16, /*default*/ 9, - /* min */ List.of(Pair.create(WORK_TYPE_BG, 9)), - /* max */ List.of(Pair.create(WORK_TYPE_BG, 9)), + /* min */ List.of(Pair.create(WORK_TYPE_BG, .99f)), + /* max */ List.of(Pair.create(WORK_TYPE_BG, 1f)), /*expected*/ true, 16, /* min */ List.of(Pair.create(WORK_TYPE_TOP, 1), Pair.create(WORK_TYPE_FGS, 2), - Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 4), - Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 5), - Pair.create(WORK_TYPE_BGUSER, 6)), + Pair.create(WORK_TYPE_EJ, 3), Pair.create(WORK_TYPE_BG, 3), + Pair.create(WORK_TYPE_BGUSER_IMPORTANT, 2), + Pair.create(WORK_TYPE_BGUSER, 2)), /* max */ List.of(Pair.create(WORK_TYPE_TOP, 16), Pair.create(WORK_TYPE_FGS, 15), Pair.create(WORK_TYPE_EJ, 14), Pair.create(WORK_TYPE_BG, 13),