-
Notifications
You must be signed in to change notification settings - Fork 15
Improve performance for Probabilistic priority queueing #344
Changes from all commits
d8f6f1f
c4e650b
d3d77a2
42bf2f7
2a35900
1196da5
81b887c
6d836ea
113a0bc
dc594d5
9d6a7f6
7bd29c3
bd36a72
ff11201
e600867
c4a6fc3
48e75b3
22bc79e
6aff891
daffeee
9f94253
b9c9ce6
259eb54
cc35f9a
e544e86
b5f5bb8
9ff939c
4f6c2a6
3ec721a
5ba02dc
c7ad72a
0ff2ad8
9308725
d6c8fa1
cbf0429
1c263b6
9827478
fe901b7
f8b1c0e
6fa7beb
9359535
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
import java.util.HashSet; | ||
import java.util.LinkedList; | ||
import java.util.Map; | ||
import java.util.Random; | ||
import java.util.Set; | ||
|
@@ -54,7 +55,8 @@ public class ProbabilisticPriorityAssigner extends TaskAssignerImpl { | |
private static final Logger LOG = LoggerFactory. | ||
getLogger(ProbabilisticPriorityAssigner.class); | ||
|
||
private final Storage storage; | ||
private static Iterable<IScheduledTask> pendindTasks = new LinkedList<>(); | ||
|
||
private Double exponent; | ||
|
||
@VisibleForTesting | ||
|
@@ -69,10 +71,8 @@ public ProbabilisticPriorityAssigner( | |
OfferManager offerManager, | ||
UpdateAgentReserver updateAgentReserver, | ||
StatsProvider statsProvider, | ||
Storage storage, | ||
@Exponent Double exponent) { | ||
super(stateManager, taskFactory, offerManager, updateAgentReserver, statsProvider); | ||
this.storage = requireNonNull(storage); | ||
this.exponent = requireNonNull(exponent); | ||
} | ||
|
||
|
@@ -87,12 +87,13 @@ public Set<String> maybeAssign( | |
|
||
// probabilistic priority queueing: may not schedule these tasks if | ||
// there are pending tasks with higher priority. | ||
Iterable<IScheduledTask> pendindTasks = getPendingTasks(); | ||
Set<Integer> prioritySet = new HashSet<>(); | ||
for (IScheduledTask t: pendindTasks) { | ||
prioritySet.add(t.getAssignedTask().getTask().getPriority()); | ||
synchronized (pendindTasks) { | ||
for (IScheduledTask t: pendindTasks) { | ||
prioritySet.add(t.getAssignedTask().getTask().getPriority()); | ||
} | ||
} | ||
//TODO(lenhattan86): Is the group is always included in the pending task set? | ||
//this group is not always included in the pending task set | ||
prioritySet.add(groupKey.getTask().getPriority()); | ||
|
||
if (!isScheduled(prioritySet, groupKey.getTask().getPriority())) { | ||
|
@@ -131,8 +132,9 @@ boolean isScheduled(Set<Integer> prioritySet, int priority) { | |
} | ||
|
||
@VisibleForTesting | ||
Iterable<IScheduledTask> getPendingTasks() { | ||
return Storage.Util.fetchTasks(storage, Query.unscoped().byStatus(ScheduleStatus.PENDING)); | ||
public static synchronized void fetchPendingTasks(Storage storage) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see the need for this method at all in this class. Your |
||
pendindTasks = | ||
Storage.Util.fetchTasks(storage, Query.unscoped().byStatus(ScheduleStatus.PENDING)); | ||
} | ||
|
||
@VisibleForTesting | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,26 +13,53 @@ | |
*/ | ||
package io.github.aurora.scheduler.scheduling; | ||
|
||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
import java.util.concurrent.ScheduledExecutorService; | ||
import java.util.concurrent.TimeUnit; | ||
|
||
import javax.inject.Inject; | ||
import javax.inject.Qualifier; | ||
import javax.inject.Singleton; | ||
|
||
import com.beust.jcommander.Parameter; | ||
import com.beust.jcommander.Parameters; | ||
import com.google.common.annotations.VisibleForTesting; | ||
import com.google.common.util.concurrent.AbstractIdleService; | ||
import com.google.inject.AbstractModule; | ||
|
||
import org.apache.aurora.common.quantity.Time; | ||
import org.apache.aurora.scheduler.SchedulerServicesModule; | ||
import org.apache.aurora.scheduler.base.AsyncUtil; | ||
import org.apache.aurora.scheduler.config.CliOptions; | ||
import org.apache.aurora.scheduler.config.CommandLine; | ||
import org.apache.aurora.scheduler.config.types.TimeAmount; | ||
import org.apache.aurora.scheduler.scheduling.TaskAssigner; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import static java.lang.annotation.ElementType.FIELD; | ||
import static java.lang.annotation.ElementType.METHOD; | ||
import static java.lang.annotation.ElementType.PARAMETER; | ||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | ||
import static java.util.Objects.requireNonNull; | ||
|
||
/** | ||
* The default TaskAssigner implementation. | ||
*/ | ||
public class ProbabilisticPriorityAssignerModule extends AbstractModule { | ||
private static final Logger LOG = | ||
LoggerFactory.getLogger(ProbabilisticPriorityAssignerModule.class); | ||
|
||
private final Options options; | ||
|
||
@Parameters(separators = "=") | ||
public static class Options { | ||
@Parameter(names = "-probabilistic_priority_assigner_exponent") | ||
Double probabilisticPriorityAssignerExponent = 0.0; | ||
|
||
@Parameter(names = "-probabilistic_priority_assigner_task_fetch_interval") | ||
TimeAmount probabilisticPriorityAssignerTaskFetchInterval = new TimeAmount(1, Time.SECONDS); | ||
} | ||
|
||
public ProbabilisticPriorityAssignerModule(CliOptions mOptions) { | ||
|
@@ -50,5 +77,53 @@ protected void configure() { | |
.annotatedWith(ProbabilisticPriorityAssigner.Exponent.class) | ||
.toInstance(options.probabilisticPriorityAssignerExponent); | ||
bind(TaskAssigner.class).to(ProbabilisticPriorityAssigner.class).in(Singleton.class); | ||
bind(TaskFetcher.class).in(com.google.inject.Singleton.class); | ||
bind(ScheduledExecutorService.class) | ||
.annotatedWith(Executor.class) | ||
.toInstance(AsyncUtil.singleThreadLoggingScheduledExecutor("HttpOfferSet-%d", LOG)); | ||
bind(Integer.class) | ||
.annotatedWith(TaskFetchInvervalMs.class) | ||
.toInstance(options.probabilisticPriorityAssignerTaskFetchInterval. | ||
as(Time.MILLISECONDS).intValue()); | ||
bind(StatUpdater.class).in(com.google.inject.Singleton.class); | ||
SchedulerServicesModule.addSchedulerActiveServiceBinding(binder()).to(StatUpdater.class); | ||
} | ||
|
||
// to bind an executor object to StatUpdater using @Executor | ||
@VisibleForTesting | ||
@Qualifier | ||
@Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) | ||
@interface Executor { } | ||
lenhattan86 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// to bind probabilisticPriorityAssignerTaskFetchInterval value to StatUpdater | ||
@VisibleForTesting | ||
@Qualifier | ||
@Target({ FIELD, PARAMETER, METHOD }) @Retention(RUNTIME) | ||
@interface TaskFetchInvervalMs { } | ||
|
||
static class StatUpdater extends AbstractIdleService { | ||
private final ScheduledExecutorService executor; | ||
private final TaskFetcher taskFetcher; | ||
private final Integer taskFetchIntervalMs; | ||
|
||
@Inject | ||
StatUpdater( | ||
@Executor ScheduledExecutorService mExecutor, | ||
TaskFetcher mTaskFetcher, | ||
@TaskFetchInvervalMs Integer mTaskFetchIntervalMs) { | ||
executor = requireNonNull(mExecutor); | ||
taskFetcher = requireNonNull(mTaskFetcher); | ||
taskFetchIntervalMs = mTaskFetchIntervalMs; | ||
} | ||
|
||
@Override | ||
protected void startUp() { | ||
executor.scheduleAtFixedRate(taskFetcher, 0, taskFetchIntervalMs, TimeUnit.MILLISECONDS); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the |
||
} | ||
|
||
@Override | ||
protected void shutDown() { | ||
// Ignored. | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.github.aurora.scheduler.scheduling; | ||
|
||
import javax.inject.Inject; | ||
|
||
import org.apache.aurora.scheduler.storage.Storage; | ||
|
||
public class TaskFetcher implements Runnable { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to fetch only pending tasks, why is it named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You seem to be having multiple classes doing similar things. You should use a single executor to fetch these tasks with whatever filters are needed and use them from different classes. Having multiple executors for the same thing is not a good idea. |
||
private final Storage storage; | ||
|
||
@Inject | ||
TaskFetcher(Storage mStorage) { | ||
storage = mStorage; | ||
} | ||
|
||
@Override | ||
public void run() { | ||
ProbabilisticPriorityAssigner.fetchPendingTasks(storage); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pendingTasks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use an
ArrayList
here for better performance, this is on a fast path and the size of the list can get significant putting pressure on memory pages. while iteratingThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also what makes you use a static variable here?