• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.caliper.runner;
18 
19 import static java.util.concurrent.TimeUnit.MINUTES;
20 import static org.junit.Assert.assertEquals;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import com.google.caliper.Benchmark;
25 import com.google.caliper.config.VmConfig;
26 import com.google.caliper.model.BenchmarkSpec;
27 import com.google.caliper.platform.jvm.JvmPlatform;
28 import com.google.caliper.worker.WorkerMain;
29 import com.google.common.collect.ImmutableMap;
30 import com.google.common.collect.ImmutableSet;
31 import com.google.common.collect.Iterables;
32 import com.google.common.collect.Sets;
33 
34 import org.junit.Before;
35 import org.junit.Test;
36 import org.junit.runner.RunWith;
37 import org.junit.runners.JUnit4;
38 
39 import java.io.File;
40 import java.lang.reflect.Method;
41 import java.util.Arrays;
42 import java.util.List;
43 import java.util.Set;
44 import java.util.UUID;
45 
46 /**
47  * Tests {@link WorkerProcess}.
48  *
49  * <p>TODO(lukes,gak): write more tests for how our specs get turned into commandlines
50  */
51 
52 @RunWith(JUnit4.class)
53 public class WorkerProcessTest {
54   private static final int PORT_NUMBER = 4004;
55   private static final UUID TRIAL_ID = UUID.randomUUID();
56 
57   private static class MockRegistrar implements ShutdownHookRegistrar {
58     Set<Thread> hooks = Sets.newHashSet();
addShutdownHook(Thread hook)59     @Override public void addShutdownHook(Thread hook) {
60       hooks.add(hook);
61     }
removeShutdownHook(Thread hook)62     @Override public boolean removeShutdownHook(Thread hook) {
63       return hooks.remove(hook);
64     }
65   }
66 
67   private final MockRegistrar registrar = new MockRegistrar();
68   private BenchmarkClass benchmarkClass;
69 
setUp()70   @Before public void setUp() throws InvalidBenchmarkException {
71     benchmarkClass = BenchmarkClass.forClass(TestBenchmark.class);
72   }
73 
simpleArgsTest()74   @Test public void simpleArgsTest() throws Exception {
75     Method method = TestBenchmark.class.getDeclaredMethods()[0];
76     AllocationInstrument allocationInstrument = new AllocationInstrument();
77     allocationInstrument.setOptions(ImmutableMap.of("trackAllocations", "true"));
78     VmConfig vmConfig = new VmConfig(
79         new File("foo"),
80         Arrays.asList("--doTheHustle"),
81         new File("java"),
82         new JvmPlatform());
83     Experiment experiment = new Experiment(
84         allocationInstrument.createInstrumentation(method),
85         ImmutableMap.<String, String>of(),
86         new VirtualMachine("foo-jvm", vmConfig));
87     BenchmarkSpec spec = new BenchmarkSpec.Builder()
88         .className(TestBenchmark.class.getName())
89         .methodName(method.getName())
90         .build();
91     ProcessBuilder builder = createProcess(experiment, spec);
92     List<String> commandLine = builder.command();
93     assertEquals(new File("java").getAbsolutePath(), commandLine.get(0));
94     assertEquals("--doTheHustle", commandLine.get(1));  // vm specific flags come next
95     assertEquals("-cp", commandLine.get(2));  // then the classpath
96     // should we assert on classpath contents?
97     ImmutableSet<String> extraCommandLineArgs =
98         allocationInstrument.getExtraCommandLineArgs(vmConfig);
99     assertEquals(extraCommandLineArgs.asList(),
100         commandLine.subList(4, 4 + extraCommandLineArgs.size()));
101     int index = 4 + extraCommandLineArgs.size();
102     assertEquals("-XX:+PrintFlagsFinal", commandLine.get(index));
103     assertEquals("-XX:+PrintCompilation", commandLine.get(++index));
104     assertEquals("-XX:+PrintGC", commandLine.get(++index));
105     assertEquals(WorkerMain.class.getName(), commandLine.get(++index));
106     // followed by worker args...
107   }
108 
shutdownHook_waitFor()109   @Test public void shutdownHook_waitFor() throws Exception {
110     Process worker = createWorkerProcess(FakeWorkers.Exit.class, "0").startWorker();
111     assertEquals("worker-shutdown-hook-" + TRIAL_ID,
112         Iterables.getOnlyElement(registrar.hooks).getName());
113     worker.waitFor();
114     assertTrue(registrar.hooks.isEmpty());
115   }
116 
shutdownHook_exitValueThrows()117   @Test public void shutdownHook_exitValueThrows() throws Exception {
118     Process worker = createWorkerProcess(
119         FakeWorkers.Sleeper.class, Long.toString(MINUTES.toMillis(1))).startWorker();
120     try {
121       Thread hook = Iterables.getOnlyElement(registrar.hooks);
122       assertEquals("worker-shutdown-hook-" + TRIAL_ID, hook.getName());
123       try {
124         worker.exitValue();
125         fail();
126       } catch (IllegalThreadStateException expected) {}
127       assertTrue(registrar.hooks.contains(hook));
128     } finally {
129       worker.destroy(); // clean up
130     }
131   }
132 
shutdownHook_exitValue()133   @Test public void shutdownHook_exitValue() throws Exception {
134     Process worker = createWorkerProcess(FakeWorkers.Exit.class, "0").startWorker();
135     while (true) {
136       try {
137         worker.exitValue();
138         assertTrue(registrar.hooks.isEmpty());
139         break;
140       } catch (IllegalThreadStateException e) {
141         Thread.sleep(10);  // keep polling
142       }
143     }
144   }
145 
shutdownHook_destroy()146   @Test public void shutdownHook_destroy() throws Exception {
147     Process worker = createWorkerProcess(
148         FakeWorkers.Sleeper.class, Long.toString(MINUTES.toMillis(1))).startWorker();
149     worker.destroy();
150     assertTrue(registrar.hooks.isEmpty());
151   }
152 
153   static final class TestBenchmark {
thing(long reps)154     @Benchmark long thing(long reps) {
155       long dummy = 0;
156       for (long i = 0; i < reps; i++) {
157         dummy += new Long(dummy).hashCode();
158       }
159       return dummy;
160     }
161   }
162 
createProcess(Experiment experiment, BenchmarkSpec benchmarkSpec)163   private ProcessBuilder createProcess(Experiment experiment, BenchmarkSpec benchmarkSpec) {
164     return WorkerProcess.buildProcess(TRIAL_ID, experiment, benchmarkSpec, PORT_NUMBER,
165         benchmarkClass);
166   }
167 
createWorkerProcess(Class<?> main, String ...args)168   private WorkerProcess createWorkerProcess(Class<?> main, String ...args) {
169     return new WorkerProcess(FakeWorkers.createProcessBuilder(main, args),
170         TRIAL_ID,
171         null,
172         registrar);
173   }
174 }
175