Repository: aurora Updated Branches: refs/heads/master a7b95d95b -> 1fdb7e32c
Add a benchmark for getRoleSummary. Reviewed at https://reviews.apache.org/r/32802/ Project: http://git-wip-us.apache.org/repos/asf/aurora/repo Commit: http://git-wip-us.apache.org/repos/asf/aurora/commit/1fdb7e32 Tree: http://git-wip-us.apache.org/repos/asf/aurora/tree/1fdb7e32 Diff: http://git-wip-us.apache.org/repos/asf/aurora/diff/1fdb7e32 Branch: refs/heads/master Commit: 1fdb7e32cde55ad08631e686328ea1d3414ea9fb Parents: a7b95d9 Author: Bill Farner <[email protected]> Authored: Fri Apr 3 11:26:22 2015 -0700 Committer: Bill Farner <[email protected]> Committed: Fri Apr 3 11:26:22 2015 -0700 ---------------------------------------------------------------------- build.gradle | 11 +- .../aurora/benchmark/SchedulingBenchmarks.java | 17 +- .../java/org/apache/aurora/benchmark/Tasks.java | 19 ++- .../aurora/benchmark/ThriftApiBenchmarks.java | 161 +++++++++++++++++++ .../aurora/scheduler/thrift/ThriftModule.java | 12 +- 5 files changed, 201 insertions(+), 19 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aurora/blob/1fdb7e32/build.gradle ---------------------------------------------------------------------- diff --git a/build.gradle b/build.gradle index 66dbdfd..d310e82 100644 --- a/build.gradle +++ b/build.gradle @@ -459,17 +459,10 @@ jacocoTestReport.finalizedBy analyzeReport def jmhHumanOutputPath = "$buildDir/reports/jmh/human.txt" jmh { - jmhVersion = '1.6.1' - jvmArgsPrepend = '-Xmx1024m' + jmhVersion = '1.7.1' + jvmArgsPrepend = '-Xmx2g' humanOutputFile = project.file("$jmhHumanOutputPath") resultsFile = project.file("$buildDir/reports/jmh/results.txt") - - // JMH run configuration parameters. - iterations = 100 - fork = 1 - warmupIterations = 10 - benchmarkMode = 'avgt' - timeUnit = 'ns' } tasks.getByName('jmh').doLast() { println "Benchmark report generated: file://$jmhHumanOutputPath" http://git-wip-us.apache.org/repos/asf/aurora/blob/1fdb7e32/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java ---------------------------------------------------------------------- diff --git a/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java b/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java index 75a67dc..88850d6 100644 --- a/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java +++ b/src/jmh/java/org/apache/aurora/benchmark/SchedulingBenchmarks.java @@ -16,6 +16,7 @@ package org.apache.aurora.benchmark; import java.util.Set; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import javax.inject.Singleton; @@ -64,10 +65,16 @@ import org.apache.aurora.scheduler.storage.entities.IHostAttributes; import org.apache.aurora.scheduler.storage.entities.IScheduledTask; import org.apache.aurora.scheduler.storage.mem.MemStorage; import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Level; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; /** * Performance benchmarks for the task scheduling loop. @@ -77,6 +84,11 @@ public class SchedulingBenchmarks { /** * Constructs scheduler objects and populates offers/tasks for the benchmark run. */ + @BenchmarkMode(Mode.Throughput) + @OutputTimeUnit(TimeUnit.SECONDS) + @Warmup(iterations=1, time=10, timeUnit=TimeUnit.SECONDS) + @Measurement(iterations=10, time=10, timeUnit=TimeUnit.SECONDS) + @Fork(1) @State(Scope.Thread) public abstract static class AbstractBase { private static final Amount<Long, Time> NO_DELAY = Amount.of(0L, Time.MILLISECONDS); @@ -241,7 +253,6 @@ public class SchedulingBenchmarks { .setTask(Iterables.getOnlyElement(new Tasks.Builder() .setProduction(true) .setCpu(32) - .setTaskIdFormat("test-%s") .build(1))).build(); } } @@ -257,7 +268,6 @@ public class SchedulingBenchmarks { .setTask(Iterables.getOnlyElement(new Tasks.Builder() .setProduction(true) .addValueConstraint("host", "denied") - .setTaskIdFormat("test-%s") .build(1))).build(); } } @@ -273,7 +283,6 @@ public class SchedulingBenchmarks { .setTask(Iterables.getOnlyElement(new Tasks.Builder() .setProduction(true) .addLimitConstraint("host", 0) - .setTaskIdFormat("test-%s") .build(1))).build(); } } @@ -292,7 +301,6 @@ public class SchedulingBenchmarks { .setTask(Iterables.getOnlyElement(new Tasks.Builder() .setProduction(true) .addLimitConstraint("host", 0) - .setTaskIdFormat("test-%s") .build(1))).build(); } } @@ -310,7 +318,6 @@ public class SchedulingBenchmarks { .setTask(Iterables.getOnlyElement(new Tasks.Builder() .setProduction(true) .addValueConstraint("host", "denied") - .setTaskIdFormat("test-%s") .build(1))).build(); } http://git-wip-us.apache.org/repos/asf/aurora/blob/1fdb7e32/src/jmh/java/org/apache/aurora/benchmark/Tasks.java ---------------------------------------------------------------------- diff --git a/src/jmh/java/org/apache/aurora/benchmark/Tasks.java b/src/jmh/java/org/apache/aurora/benchmark/Tasks.java index 491c687..23827ab 100644 --- a/src/jmh/java/org/apache/aurora/benchmark/Tasks.java +++ b/src/jmh/java/org/apache/aurora/benchmark/Tasks.java @@ -49,7 +49,7 @@ final class Tasks { private static final String USER_FORMAT = "user-%s"; private JobKey jobKey = new JobKey("jmh", "dev", "benchmark"); - private String taskIdFormat = "default_task-%s"; + private int uuidStart = 0; private boolean isProduction = false; private double cpu = 6.0; private Amount<Long, Data> ram = Amount.of(8L, Data.GB); @@ -62,8 +62,18 @@ final class Tasks { return this; } - Builder setTaskIdFormat(String newTaskIdFormat) { - taskIdFormat = newTaskIdFormat; + Builder setEnv(String env) { + jobKey.setEnvironment(env); + return this; + } + + Builder setJob(String job) { + jobKey.setName(job); + return this; + } + + Builder setUuidStart(int uuidStart) { + this.uuidStart = uuidStart; return this; } @@ -121,7 +131,8 @@ final class Tasks { ImmutableSet.Builder<IScheduledTask> tasks = ImmutableSet.builder(); for (int i = 0; i < count; i++) { - String taskId = String.format(taskIdFormat, i); + String taskId = + jobKey.getRole() + "-" + jobKey.getEnvironment() + "-" + i + "-" + (uuidStart + i); tasks.add(IScheduledTask.build(new ScheduledTask() .setTaskEvents(Lists.newArrayList(new TaskEvent(0, ScheduleStatus.PENDING))) http://git-wip-us.apache.org/repos/asf/aurora/blob/1fdb7e32/src/jmh/java/org/apache/aurora/benchmark/ThriftApiBenchmarks.java ---------------------------------------------------------------------- diff --git a/src/jmh/java/org/apache/aurora/benchmark/ThriftApiBenchmarks.java b/src/jmh/java/org/apache/aurora/benchmark/ThriftApiBenchmarks.java new file mode 100644 index 0000000..df053e2 --- /dev/null +++ b/src/jmh/java/org/apache/aurora/benchmark/ThriftApiBenchmarks.java @@ -0,0 +1,161 @@ +/** + * 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 org.apache.aurora.benchmark; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.concurrent.TimeUnit; + +import com.google.common.collect.ImmutableSet; +import com.google.gson.Gson; +import com.google.inject.AbstractModule; +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.twitter.common.inject.Bindings; +import com.twitter.common.util.Clock; + +import org.apache.aurora.gen.ReadOnlyScheduler; +import org.apache.aurora.gen.Response; +import org.apache.aurora.gen.ScheduleStatus; +import org.apache.aurora.scheduler.cron.CronPredictor; +import org.apache.aurora.scheduler.quota.QuotaManager; +import org.apache.aurora.scheduler.state.LockManager; +import org.apache.aurora.scheduler.storage.Storage; +import org.apache.aurora.scheduler.storage.db.DbModule; +import org.apache.aurora.scheduler.storage.entities.IScheduledTask; +import org.apache.aurora.scheduler.storage.mem.MemStorage; +import org.apache.aurora.scheduler.storage.mem.MemStorageModule; +import org.apache.aurora.scheduler.thrift.ThriftModule; +import org.apache.thrift.TException; +import org.openjdk.jmh.annotations.Benchmark; +import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Fork; +import org.openjdk.jmh.annotations.Measurement; +import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.OutputTimeUnit; +import org.openjdk.jmh.annotations.Param; +import org.openjdk.jmh.annotations.Scope; +import org.openjdk.jmh.annotations.Setup; +import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Warmup; + +public class ThriftApiBenchmarks { + + @BenchmarkMode(Mode.Throughput) + @OutputTimeUnit(TimeUnit.SECONDS) + @Warmup(iterations=1, time=10, timeUnit=TimeUnit.SECONDS) + @Measurement(iterations=5, time=5, timeUnit=TimeUnit.SECONDS) + @Fork(1) + @State(Scope.Thread) + public static class GetRoleSummaryBenchmark { + private ReadOnlyScheduler.Iface api; + + @Param({ + "{\"roles\": 1}", + "{\"roles\": 10}", + "{\"roles\": 100}", + "{\"roles\": 500}", + "{\"jobs\": 1}", + "{\"jobs\": 10}", + "{\"jobs\": 100}", + "{\"jobs\": 500}", + "{\"instances\": 1}", + "{\"instances\": 10}", + "{\"instances\": 100}", + "{\"instances\": 1000}", + "{\"instances\": 10000}"}) + private String testConfiguration; + + @Setup + public void setUp() { + final TestConfiguration config = + new Gson().fromJson(testConfiguration, TestConfiguration.class); + + Injector injector = Guice.createInjector( + new AbstractModule() { + @Override + protected void configure() { + bind(Clock.class).toInstance(Clock.SYSTEM_CLOCK); + bind(CronPredictor.class).toInstance(createThrowingFake(CronPredictor.class)); + bind(QuotaManager.class).toInstance(createThrowingFake(QuotaManager.class)); + bind(LockManager.class).toInstance(createThrowingFake(LockManager.class)); + } + }, + new MemStorageModule(Bindings.KeyFactory.PLAIN), + new DbModule(Bindings.annotatedKeyFactory(MemStorage.Delegated.class)), + new ThriftModule.ReadOnly()); + api = injector.getInstance(ReadOnlyScheduler.Iface.class); + + // Ideally we would use the API to populate the storage, but wiring in the writable thrift + // interface requires considerably more binding setup. + Storage storage = injector.getInstance(Storage.class); + storage.write(new Storage.MutateWork.NoResult.Quiet() { + @Override + protected void execute(Storage.MutableStoreProvider storeProvider) { + for (int roleId = 0; roleId < config.roles; roleId++) { + String role = "role" + roleId; + for (int envId = 0; envId < config.envs; envId++) { + String env = "env" + envId; + for (int jobId = 0; jobId < config.jobs; jobId++) { + String job = "job" + jobId; + ImmutableSet.Builder<IScheduledTask> tasks = ImmutableSet.builder(); + tasks.addAll(new Tasks.Builder() + .setRole(role) + .setEnv(env) + .setJob(job) + .setScheduleStatus(ScheduleStatus.RUNNING) + .build(config.instances)); + tasks.addAll(new Tasks.Builder() + .setRole(role) + .setEnv(env) + .setJob(job) + .setScheduleStatus(ScheduleStatus.FINISHED) + .setUuidStart(1) + .build(config.deadTasks)); + storeProvider.getUnsafeTaskStore().saveTasks(tasks.build()); + } + } + } + } + }); + } + + @Benchmark + public Response run() throws TException { + return api.getRoleSummary(); + } + } + + private static <T> T createThrowingFake(Class<T> clazz) { + InvocationHandler handler = new InvocationHandler() { + @Override + public Object invoke(Object o, Method method, Object[] objects) throws Throwable { + throw new UnsupportedOperationException("This fake has no behavior."); + } + }; + + @SuppressWarnings("unchecked") + T proxy = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, handler); + return proxy; + } + + private static class TestConfiguration { + private int roles = 1; + private int envs = 5; + private int jobs = 1; + private int instances = 100; + private int deadTasks = 100; + } +} http://git-wip-us.apache.org/repos/asf/aurora/blob/1fdb7e32/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java ---------------------------------------------------------------------- diff --git a/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java b/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java index c65e021..bd92ff7 100644 --- a/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java +++ b/src/main/java/org/apache/aurora/scheduler/thrift/ThriftModule.java @@ -27,7 +27,7 @@ public class ThriftModule extends AbstractModule { @Override protected void configure() { - bind(ReadOnlyScheduler.Iface.class).to(ReadOnlySchedulerImpl.class); + install(new ReadOnly()); bind(AuroraAdmin.Iface.class).to(SchedulerThriftInterface.class); bind(AnnotatedAuroraAdmin.class).to(SchedulerThriftInterface.class); @@ -36,4 +36,14 @@ public class ThriftModule extends AbstractModule { bind(SchedulerThriftInterface.class); install(new AopModule()); } + + /** + * Binding module for only the read-only scheduler interface. + */ + public static class ReadOnly extends AbstractModule { + @Override + protected void configure() { + bind(ReadOnlyScheduler.Iface.class).to(ReadOnlySchedulerImpl.class); + } + } }
