mirror of https://github.com/apache/jclouds.git
added performance research tests
This commit is contained in:
parent
ac2c89f489
commit
8c0e387b3e
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* 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.jclouds.concurrent;
|
||||||
|
|
||||||
|
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
|
||||||
|
import static java.util.concurrent.Executors.newCachedThreadPool;
|
||||||
|
import static org.jclouds.concurrent.ConcurrentUtils.awaitCompletion;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.CALLABLE_DURATION;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.COUNT;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.FUDGE;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.checkTimeThresholds;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.runCallables;
|
||||||
|
import static org.testng.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import org.jclouds.logging.Logger;
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of ConcurrentUtils
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "unit", sequential = true, testName = "concurrent.ConcurrentUtilsTest")
|
||||||
|
public class ConcurrentUtilsTest {
|
||||||
|
|
||||||
|
public void testMakeListenableDoesntSerializeFutures() throws InterruptedException, ExecutionException {
|
||||||
|
long expectedMax = CALLABLE_DURATION;
|
||||||
|
long expectedMin = CALLABLE_DURATION;
|
||||||
|
long expectedOverhead = COUNT + FUDGE;
|
||||||
|
|
||||||
|
ExecutorService callableExecutor = newCachedThreadPool();
|
||||||
|
ExecutorService chainExecutor = sameThreadExecutor();
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
Map<String, ListenableFuture<Long>> responses = runCallables(callableExecutor, chainExecutor);
|
||||||
|
checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAwaitCompletionUsingSameThreadExecutorDoesntSerializeFutures() throws InterruptedException,
|
||||||
|
ExecutionException {
|
||||||
|
long expectedMax = CALLABLE_DURATION;
|
||||||
|
long expectedMin = CALLABLE_DURATION;
|
||||||
|
long expectedOverhead = COUNT + FUDGE;
|
||||||
|
|
||||||
|
ExecutorService callableExecutor = newCachedThreadPool();
|
||||||
|
ExecutorService chainExecutor = sameThreadExecutor();
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
Map<String, ListenableFuture<Long>> responses = runCallables(callableExecutor, chainExecutor);
|
||||||
|
Map<String, Exception> exceptions = awaitCompletion(responses, sameThreadExecutor(), null, Logger.CONSOLE,
|
||||||
|
"test same thread");
|
||||||
|
assertEquals(exceptions.size(), 0);
|
||||||
|
checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* 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.jclouds.concurrent;
|
||||||
|
|
||||||
|
import static com.google.common.util.concurrent.MoreExecutors.sameThreadExecutor;
|
||||||
|
import static java.util.concurrent.Executors.newCachedThreadPool;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.CALLABLE_DURATION;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.COUNT;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.FUDGE;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.LISTENER_DURATION;
|
||||||
|
import static org.jclouds.concurrent.FuturesTestingUtils.checkThresholds;
|
||||||
|
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import org.testng.annotations.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of ConcurrentUtils
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
@Test(groups = "performance", sequential = true, testName = "concurrent.ConcurrentUtilsTest")
|
||||||
|
public class FuturesComposePerformanceTest {
|
||||||
|
ExecutorService callableExecutor = newCachedThreadPool();
|
||||||
|
|
||||||
|
public void test1() throws InterruptedException, ExecutionException {
|
||||||
|
long expectedMax = CALLABLE_DURATION + LISTENER_DURATION;
|
||||||
|
long expectedMin = CALLABLE_DURATION + LISTENER_DURATION;
|
||||||
|
long expectedOverhead = COUNT * 4 + FUDGE;
|
||||||
|
|
||||||
|
ExecutorService chainExecutor = callableExecutor;
|
||||||
|
ExecutorService listenerExecutor = callableExecutor;
|
||||||
|
|
||||||
|
checkThresholds(expectedMin, expectedMax, expectedOverhead, callableExecutor, chainExecutor, listenerExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test2() throws InterruptedException, ExecutionException {
|
||||||
|
long expectedMax = CALLABLE_DURATION + LISTENER_DURATION;
|
||||||
|
long expectedMin = CALLABLE_DURATION + LISTENER_DURATION;
|
||||||
|
long expectedOverhead = COUNT + FUDGE;
|
||||||
|
|
||||||
|
ExecutorService chainExecutor = callableExecutor;
|
||||||
|
ExecutorService listenerExecutor = sameThreadExecutor();
|
||||||
|
|
||||||
|
checkThresholds(expectedMin, expectedMax, expectedOverhead, callableExecutor, chainExecutor, listenerExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test3() throws InterruptedException, ExecutionException {
|
||||||
|
long expectedMax = (CALLABLE_DURATION * COUNT) + LISTENER_DURATION;
|
||||||
|
long expectedMin = CALLABLE_DURATION + LISTENER_DURATION;
|
||||||
|
long expectedOverhead = COUNT + FUDGE;
|
||||||
|
|
||||||
|
ExecutorService chainExecutor = sameThreadExecutor();
|
||||||
|
ExecutorService listenerExecutor = callableExecutor;
|
||||||
|
|
||||||
|
checkThresholds(expectedMin, expectedMax, expectedOverhead, callableExecutor, chainExecutor, listenerExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void test4() throws InterruptedException, ExecutionException {
|
||||||
|
|
||||||
|
long expectedMax = (CALLABLE_DURATION * COUNT) + (LISTENER_DURATION * COUNT);
|
||||||
|
long expectedMin = CALLABLE_DURATION + LISTENER_DURATION;
|
||||||
|
long expectedOverhead = COUNT + FUDGE;
|
||||||
|
|
||||||
|
ExecutorService chainExecutor = sameThreadExecutor();
|
||||||
|
ExecutorService listenerExecutor = sameThreadExecutor();
|
||||||
|
|
||||||
|
checkThresholds(expectedMin, expectedMax, expectedOverhead, callableExecutor, chainExecutor, listenerExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,141 @@
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 Cloud Conscious, LLC. <info@cloudconscious.com>
|
||||||
|
*
|
||||||
|
* ====================================================================
|
||||||
|
* 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.jclouds.concurrent;
|
||||||
|
|
||||||
|
import static com.google.common.base.Throwables.propagate;
|
||||||
|
import static com.google.common.collect.Maps.newHashMap;
|
||||||
|
import static com.google.common.util.concurrent.Futures.compose;
|
||||||
|
import static org.jclouds.concurrent.ConcurrentUtils.makeListenable;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.concurrent.ExecutorService;
|
||||||
|
|
||||||
|
import com.google.common.base.Function;
|
||||||
|
import com.google.common.collect.Iterables;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests behavior of ConcurrentUtils
|
||||||
|
*
|
||||||
|
* @author Adrian Cole
|
||||||
|
*/
|
||||||
|
public class FuturesTestingUtils {
|
||||||
|
public static final int FUDGE = 5;
|
||||||
|
public static final int COUNT = 100;
|
||||||
|
public static final int CALLABLE_DURATION = 10;
|
||||||
|
public static final int LISTENER_DURATION = 10;
|
||||||
|
|
||||||
|
public static void checkThresholds(long expectedMin, long expectedMax, long expectedOverhead,
|
||||||
|
ExecutorService callableExecutor, ExecutorService chainExecutor, final ExecutorService listenerExecutor) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
Map<String, ListenableFuture<Long>> responses = newHashMap();
|
||||||
|
for (int i = 0; i < COUNT; i++)
|
||||||
|
responses.put(i + "", compose(createListenableFuture(callableExecutor, chainExecutor),
|
||||||
|
new Function<Long, Long>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long apply(Long from) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(LISTENER_DURATION);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
propagate(e);
|
||||||
|
}
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
}, listenerExecutor));
|
||||||
|
checkTimeThresholds(expectedMin, expectedMax, expectedOverhead, start, responses);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<String, ListenableFuture<Long>> runCallables(ExecutorService callableExecutor,
|
||||||
|
ExecutorService chainExecutor) {
|
||||||
|
Map<String, ListenableFuture<Long>> responses = newHashMap();
|
||||||
|
for (int i = 0; i < COUNT; i++)
|
||||||
|
responses.put(i + "", createListenableFuture(callableExecutor, chainExecutor));
|
||||||
|
return responses;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ListenableFuture<Long> createListenableFuture(ExecutorService callableExecutor,
|
||||||
|
ExecutorService chainExecutor) {
|
||||||
|
return makeListenable(callableExecutor.submit(new Callable<Long>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long call() throws Exception {
|
||||||
|
Thread.sleep(CALLABLE_DURATION);
|
||||||
|
return System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
|
||||||
|
}), chainExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getMaxIn(Map<String, ListenableFuture<Long>> responses) {
|
||||||
|
Iterable<Long> collection = Iterables.transform(responses.values(), new Function<ListenableFuture<Long>, Long>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long apply(ListenableFuture<Long> from) {
|
||||||
|
try {
|
||||||
|
return from.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
long time = Collections.max(Sets.newHashSet(collection));
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long getMinIn(Map<String, ListenableFuture<Long>> responses) {
|
||||||
|
Iterable<Long> collection = Iterables.transform(responses.values(), new Function<ListenableFuture<Long>, Long>() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long apply(ListenableFuture<Long> from) {
|
||||||
|
try {
|
||||||
|
return from.get();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
} catch (ExecutionException e) {
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
long time = Collections.min(Sets.newHashSet(collection));
|
||||||
|
return time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void checkTimeThresholds(long expectedMin, long expectedMax, long expectedOverhead, long start,
|
||||||
|
Map<String, ListenableFuture<Long>> responses) {
|
||||||
|
long time = getMaxIn(responses) - start;
|
||||||
|
assert time >= expectedMax && time < expectedMax + expectedOverhead : String.format("expected %d, was %d",
|
||||||
|
expectedMax, time);
|
||||||
|
|
||||||
|
time = getMinIn(responses) - start;
|
||||||
|
assert time >= expectedMin && time < expectedMin + expectedOverhead : String.format("expected %d, was %d",
|
||||||
|
expectedMin, time);
|
||||||
|
|
||||||
|
time = getMaxIn(responses) - start;
|
||||||
|
assert time >= expectedMax && time < expectedMax + expectedOverhead : String.format("expected %d, was %d",
|
||||||
|
expectedMax, time);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue