Skip to content

Commit

Permalink
Allowing JVM options to be set by test
Browse files Browse the repository at this point in the history
Allowing performance tests to set the JVM options for each role in the
test.
  • Loading branch information
upthewaterspout committed Nov 29, 2018
1 parent d473026 commit 26f1c40
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 31 deletions.
22 changes: 22 additions & 0 deletions harness/src/main/java/org/apache/geode/perftest/TestConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -36,6 +39,7 @@ public class TestConfig implements Serializable {

private final WorkloadConfig workloadConfig = new WorkloadConfig();
private Map<String, Integer> roles = new LinkedHashMap<>();
private Map<String, List<String>> jvmArgs = new HashMap<>();
private List<TestStep> before = new ArrayList<>();
private List<TestStep> workload = new ArrayList<>();
private List<TestStep> after = new ArrayList<>();
Expand Down Expand Up @@ -153,11 +157,29 @@ public int getTotalJVMs() {
return roles.values().stream().mapToInt(Integer::intValue).sum();
}

/**
* Add JVM arguments used to launch JVMs for a particular role
*
* If multiple calls to this method are made for the same role, the new JVM arguments
* are appended to the existing JVM args
*/
public void jvmArgs(String role, String ... jvmArgs) {
List<String> roleArgs = this.jvmArgs.computeIfAbsent(role, key -> new ArrayList<>());
roleArgs.addAll(Arrays.asList(jvmArgs));
}

public Map<String, List<String>> getJvmArgs() {
return Collections.unmodifiableMap(jvmArgs);
}

public static class TestStep {
private final Task task;
private final String[] roles;

public TestStep(Task task, String[] roles) {
if(roles == null || roles.length == 0) {
throw new IllegalStateException("Task " + task + " must be assigned to at least one role");
}
this.task = task;
this.roles = roles;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,28 +40,27 @@ CompletableFuture<Void> launchProcesses(Infrastructure infra, int rmiPort,
throws UnknownHostException {
List<CompletableFuture<Void>> futures = new ArrayList<CompletableFuture<Void>>();
for (JVMMapping entry : mapping) {
futures.add(launchWorker(infra, rmiPort, entry.getId(), entry.getNode(), libDir, entry.getOutputDir()));
CompletableFuture<Void> future = launchWorker(infra, rmiPort, libDir, entry);
futures.add(future);
}
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
}

CompletableFuture<Void> launchWorker(Infrastructure infra, int rmiPort,
int id, final Infrastructure.Node node, String libDir,
String outputDir)
CompletableFuture<Void> launchWorker(Infrastructure infra, int rmiPort, String libDir, JVMMapping jvmConfig)
throws UnknownHostException {
String[] shellCommand = buildCommand(InetAddress.getLocalHost().getHostAddress(), rmiPort, id,
libDir, outputDir);
String[] shellCommand = buildCommand(InetAddress.getLocalHost().getHostAddress(), rmiPort, libDir, jvmConfig);

CompletableFuture<Void> future = new CompletableFuture<Void>();
Thread thread = new Thread("Worker " + node.getAddress()) {
Thread thread = new Thread("Worker " + jvmConfig.getNode().getAddress()) {
public void run() {

try {
int result = infra.onNode(node, shellCommand);
int result = infra.onNode(jvmConfig.getNode(), shellCommand);
if (result != 0) {
logger.error("ChildJVM exited with error code " + result);
}
} catch (Throwable t) {
logger.error("Launching " + String.join(" ", shellCommand) + " on " + node + "Failed.", t);
logger.error("Launching " + String.join(" ", shellCommand) + " on " + jvmConfig.getNode() + "Failed.", t);
} finally {
future.complete(null);
}
Expand All @@ -72,17 +71,17 @@ public void run() {
return future;
}

String[] buildCommand(String rmiHost, int rmiPort, int id, String libDir,
String outputDir) {
String[] buildCommand(String rmiHost, int rmiPort, String libDir, JVMMapping jvmConfig) {

List<String> command = new ArrayList<String>();
command.add("java");
command.add("-classpath");
command.add(libDir + "/*");
command.add("-D" + RemoteJVMFactory.RMI_HOST + "=" + rmiHost);
command.add("-D" + RemoteJVMFactory.RMI_PORT_PROPERTY + "=" + rmiPort);
command.add("-D" + RemoteJVMFactory.JVM_ID + "=" + id);
command.add("-D" + RemoteJVMFactory.OUTPUT_DIR + "=" + outputDir);
command.add("-D" + RemoteJVMFactory.JVM_ID + "=" + jvmConfig.getId());
command.add("-D" + RemoteJVMFactory.OUTPUT_DIR + "=" + jvmConfig.getOutputDir());
command.addAll(jvmConfig.getJvmArgs());
command.add(ChildJVM.class.getName());

return command.toArray(new String[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,22 @@
package org.apache.geode.perftest.jvms;

import java.io.Serializable;
import java.util.List;

import org.apache.geode.perftest.infrastructure.Infrastructure;

public class JVMMapping implements Serializable {
private final Infrastructure.Node node;
private final String role;
private final int id;
private final List<String> jvmArgs;

public JVMMapping(Infrastructure.Node node, String role, int id) {
public JVMMapping(Infrastructure.Node node, String role, int id,
List<String> jvmArgs) {
this.node = node;
this.role = role;
this.id = id;
this.jvmArgs = jvmArgs;
}

public Infrastructure.Node getNode() {
Expand All @@ -47,4 +51,8 @@ public int getId() {
public String getOutputDir() {
return "output/" + role + "-" + id;
}

public List<String> getJvmArgs() {
return jvmArgs;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package org.apache.geode.perftest.jvms;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -74,9 +75,11 @@ public RemoteJVMFactory(InfrastructureFactory infrastructureFactory) {
* @param roles The JVMs to start. Keys a roles and values are the number
* of JVMs in that role.
*
* @param jvmArgs
* @return a {@link RemoteJVMs} object used to access the JVMs through RMI
*/
public RemoteJVMs launch(Map<String, Integer> roles) throws Exception {
public RemoteJVMs launch(Map<String, Integer> roles,
Map<String, List<String>> jvmArgs) throws Exception {
int numWorkers = roles.values().stream().mapToInt(Integer::intValue).sum();

Infrastructure infra = infrastructureFactory.create(numWorkers);
Expand All @@ -87,7 +90,7 @@ public RemoteJVMs launch(Map<String, Integer> roles) throws Exception {
throw new IllegalStateException("Too few nodes for test. Need " + numWorkers + ", have " + nodes.size());
}

List<JVMMapping> mapping = mapRolesToNodes(roles, nodes);
List<JVMMapping> mapping = mapRolesToNodes(roles, nodes, jvmArgs);

Controller controller = controllerFactory.createController(new SharedContext(mapping), numWorkers);

Expand All @@ -108,17 +111,18 @@ public InfrastructureFactory getInfrastructureFactory() {
}

private List<JVMMapping> mapRolesToNodes(Map<String, Integer> roles,
Set<Infrastructure.Node> nodes) {


Set<Infrastructure.Node> nodes,
Map<String, List<String>> jvmArgs) {
List<JVMMapping> mapping = new ArrayList<>();
Iterator<Infrastructure.Node> nodeItr = nodes.iterator();

int id = 0;
for(Map.Entry<String, Integer> roleEntry : roles.entrySet()) {
for(int i = 0; i < roleEntry.getValue(); i++) {
Infrastructure.Node node = nodeItr.next();
mapping.add(new JVMMapping(node, roleEntry.getKey(), id++));
String role = roleEntry.getKey();
List<String> roleArgs = jvmArgs.getOrDefault(role, Collections.emptyList());
mapping.add(new JVMMapping(node, role, id++, roleArgs));
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,11 @@ protected void runTest(TestConfig config)


Map<String, Integer> roles = config.getRoles();
Map<String, List<String>> jvmArgs = config.getJvmArgs();

logger.info("Lauching JVMs...");
//launch JVMs in parallel, hook them up
try (RemoteJVMs remoteJVMs = remoteJvmFactory.launch(roles)) {
try (RemoteJVMs remoteJVMs = remoteJvmFactory.launch(roles, jvmArgs)) {

logger.info("Starting before tasks...");
runTasks(config.getBefore(), remoteJVMs);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,19 @@ public void generatesOutputDirectoryPerBenchmark() throws Exception {
assertEquals(1, outputFiles.count());
}

@Test
public void configuresJVMOptions() throws Exception {
runner.runTest(testConfig -> {
testConfig.name(SAMPLE_BENCHMARK);
testConfig.role("all", 1);
testConfig.jvmArgs("all", "-Dprop1=true", "-Dprop2=5");
testConfig.before(context -> {
assertTrue("Expecting system property to be set in launched JVM, but it was not present.", Boolean.getBoolean("prop1"));
assertEquals("Expecting system property to be set in launched JVM, but it was not present.", 5, Integer.getInteger("prop2").intValue());
}, "all");
});
}

private Predicate<Path> nameMatches(String sensorOutputFile) {
return path -> path.toString().contains(sensorOutputFile);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,20 @@
package org.apache.geode.perftest;

import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.File;
import java.util.Collections;

import org.assertj.core.api.Assertions;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.mockito.InOrder;

import org.apache.geode.perftest.infrastructure.InfrastructureFactory;
import org.apache.geode.perftest.infrastructure.Infrastructure;
import org.apache.geode.perftest.jvms.RemoteJVMFactory;
import org.apache.geode.perftest.jvms.RemoteJVMs;
import org.apache.geode.perftest.runner.DefaultTestRunner;
Expand All @@ -49,7 +47,7 @@ public void testRunnerRunsBeforeAndAfterTasks() throws Exception {
RemoteJVMFactory remoteJvmFactory = mock(RemoteJVMFactory.class);

RemoteJVMs remoteJVMs = mock(RemoteJVMs.class);
when(remoteJvmFactory.launch(any())).thenReturn(remoteJVMs);
when(remoteJvmFactory.launch(any(), any())).thenReturn(remoteJVMs);

TestRunner runner = new DefaultTestRunner(remoteJvmFactory,
folder.newFolder());
Expand All @@ -73,4 +71,25 @@ public void testRunnerRunsBeforeAndAfterTasks() throws Exception {
inOrder.verify(remoteJVMs).execute(eq(after), any());
}

@Test
public void requiresAtLeastOneRole() throws Exception {

RemoteJVMFactory remoteJvmFactory = mock(RemoteJVMFactory.class);

RemoteJVMs remoteJVMs = mock(RemoteJVMs.class);
when(remoteJvmFactory.launch(any(), any())).thenReturn(remoteJVMs);

TestRunner runner = new DefaultTestRunner(remoteJvmFactory,
folder.newFolder());

Task before = mock(Task.class);

PerformanceTest test = config -> {
config.name("SampleBenchmark");
config.role("before", 1);

config.before(before);
};
Assertions.assertThatThrownBy(() -> runner.runTest(test)).isInstanceOf(IllegalStateException.class);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import org.apache.geode.perftest.infrastructure.local.LocalInfrastructure;
import org.apache.geode.perftest.infrastructure.local.LocalInfrastructureFactory;

public class RemoteJVMFactoryIntegrationTest {
Expand All @@ -38,7 +37,7 @@ public class RemoteJVMFactoryIntegrationTest {
public void canExecuteCodeOnWorker() throws Exception {
RemoteJVMFactory remoteJvmFactory = new RemoteJVMFactory(new LocalInfrastructureFactory());
Map<String, Integer> roles = Collections.singletonMap("worker", 1);
try (RemoteJVMs jvms = remoteJvmFactory.launch(roles)) {
try (RemoteJVMs jvms = remoteJvmFactory.launch(roles, Collections.emptyMap())) {
File tempFile = new File(temporaryFolder.newFolder(), "tmpfile").getAbsoluteFile();
jvms.execute(context -> {
tempFile.createNewFile();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public void launchMethodCreatesControllerAndLaunchesNodes() throws Exception {

when(controller.waitForWorkers(anyInt(), any())).thenReturn(true);

factory.launch(roles);
factory.launch(roles, Collections.emptyMap());

InOrder inOrder = inOrder(controller, controllerFactory, jvmLauncher, classPathCopier, infra);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand All @@ -42,10 +43,10 @@ public void getHostsForRoleShouldReturnCorrectList() throws UnknownHostException
InetAddress host2 = InetAddress.getByName("127.0.0.2");
Infrastructure.Node node1 = mock(Infrastructure.Node.class);
when(node1.getAddress()).thenReturn(host1);
JVMMapping mapping1 = new JVMMapping(node1, "role", 1);
JVMMapping mapping1 = new JVMMapping(node1, "role", 1, Collections.emptyList());
Infrastructure.Node node2 = mock(Infrastructure.Node.class);
when(node2.getAddress()).thenReturn(host2);
JVMMapping mapping2 = new JVMMapping(node2, "role", 2);
JVMMapping mapping2 = new JVMMapping(node2, "role", 2, Collections.emptyList());

SharedContext context = new SharedContext(Arrays.asList(mapping1, mapping2));

Expand Down

0 comments on commit 26f1c40

Please sign in to comment.