Home | History | Annotate | Download | only in runner
      1 /*
      2  * Copyright (C) 2014 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package com.google.caliper.runner;
     16 
     17 import com.google.caliper.bridge.LogMessage;
     18 import com.google.caliper.bridge.LogMessageVisitor;
     19 import com.google.caliper.bridge.OpenedSocket;
     20 import com.google.caliper.config.CaliperConfig;
     21 import com.google.caliper.config.InvalidConfigurationException;
     22 import com.google.caliper.platform.Platform;
     23 import com.google.caliper.platform.jvm.JvmPlatform;
     24 import com.google.caliper.util.Util;
     25 import com.google.common.annotations.VisibleForTesting;
     26 import com.google.common.collect.ImmutableMap;
     27 
     28 import java.io.IOException;
     29 import java.io.Serializable;
     30 import java.net.InetAddress;
     31 import java.net.Socket;
     32 import java.util.Collections;
     33 import java.util.List;
     34 import java.util.concurrent.CountDownLatch;
     35 
     36 import javax.annotation.concurrent.GuardedBy;
     37 
     38 /**
     39  * A collection of Simple java executables and a helper method for creating process builders for
     40  * them.
     41  */
     42 final class FakeWorkers {
     43 
     44   @GuardedBy("FakeWorkers.class")
     45   private static VirtualMachine jvm;
     46 
     47   /**
     48    * Try to find the currently executing jvm binary, N.B. This isn't guaranteed to be cross
     49    * platform.
     50    */
     51   private static synchronized VirtualMachine init() {
     52     if (jvm == null) {
     53       try {
     54         Platform platform = new JvmPlatform();
     55         jvm = new VirtualMachine("default",
     56             new CaliperConfig(ImmutableMap.<String, String>of()).getDefaultVmConfig(platform));
     57       } catch (InvalidConfigurationException e) {
     58         throw new RuntimeException();
     59       }
     60     }
     61     return jvm;
     62   }
     63 
     64   /**
     65    * Returns a ProcessBuilder that attempts to invoke the given class as main in a JVM configured
     66    * with a classpath equivalent to the currently executing JVM.
     67    */
     68   static ProcessBuilder createProcessBuilder(Class<?> mainClass, String ...mainArgs) {
     69     VirtualMachine jvm = init();
     70     List<String> args;
     71     try {
     72       args = WorkerProcess.getJvmArgs(jvm, BenchmarkClass.forClass(mainClass));
     73     } catch (InvalidBenchmarkException e) {
     74       throw new RuntimeException(e);
     75     }
     76     args.add(mainClass.getName());
     77     Collections.addAll(args, mainArgs);
     78     return new ProcessBuilder().command(args);
     79   }
     80 
     81   public static VirtualMachine getVirtualMachine() {
     82     return init();
     83   }
     84 
     85   /**
     86    * A simple main method that will sleep for the number of milliseconds specified in the first
     87    * argument.
     88    */
     89   static final class Sleeper {
     90     public static void main(String[] args) throws NumberFormatException, InterruptedException {
     91       Thread.sleep(Long.parseLong(args[0]));
     92     }
     93   }
     94 
     95   /**
     96    * A simple main method that exits immediately with the code provided by the first argument
     97    */
     98   static final class Exit {
     99     public static void main(String[] args) {
    100       System.exit(Integer.parseInt(args[0]));
    101     }
    102   }
    103 
    104   /**
    105    * A simple main method that exits immediately with the code provided by the first argument
    106    */
    107   static final class CloseAndSleep {
    108     public static void main(String[] args) throws IOException, InterruptedException {
    109       System.err.close();
    110       System.in.close();
    111       System.out.close();
    112       new CountDownLatch(1).await();  // wait forever
    113     }
    114   }
    115 
    116   /**
    117    * Prints alternating arguments to standard out and standard error.
    118    */
    119   static final class PrintClient {
    120     public static void main(String[] args)  {
    121       for (int i = 0; i < args.length; i++) {
    122         if (i % 2 == 0) {
    123           System.out.println(args[i]);
    124           System.out.flush();
    125         } else {
    126           System.err.println(args[i]);
    127           System.err.flush();
    128         }
    129       }
    130     }
    131   }
    132 
    133   /**
    134    * Prints alternating arguments to standard out and standard error.
    135    */
    136   @VisibleForTesting
    137   static final class LoadBenchmarkClass {
    138 
    139     public static void main(String[] args) throws ClassNotFoundException {
    140         String benchmarkClassName = args[0];
    141         Util.loadClass(benchmarkClassName);
    142     }
    143   }
    144 
    145   static final class DummyLogMessage extends LogMessage implements Serializable {
    146     private final String content;
    147 
    148     DummyLogMessage(String content) {
    149       this.content = content;
    150     }
    151 
    152     @Override public void accept(LogMessageVisitor visitor) {}
    153 
    154     @Override public String toString() {
    155       return content;
    156     }
    157 
    158     @Override public boolean equals(Object obj) {
    159       return obj instanceof DummyLogMessage && ((DummyLogMessage) obj).content.equals(content);
    160     }
    161 
    162     @Override public int hashCode() {
    163       return content.hashCode();
    164     }
    165   }
    166 
    167   /**
    168    * Connects to a socket on localhost on the port provided as the first argument and echos all
    169    * data.
    170    *
    171    * <p>Once the connection has been closed it prints the remaining args to stdout
    172    */
    173   static final class SocketEchoClient {
    174     public static void main(String[] args) throws Exception {
    175       int port = Integer.parseInt(args[0]);
    176       OpenedSocket openedSocket = OpenedSocket.fromSocket(
    177           new Socket(InetAddress.getLocalHost(), port));
    178       OpenedSocket.Reader reader = openedSocket.reader();
    179       OpenedSocket.Writer writer = openedSocket.writer();
    180       writer.write(new DummyLogMessage("start"));
    181       writer.flush();
    182       Serializable obj;
    183       while ((obj = reader.read()) != null) {
    184         writer.write(obj);
    185         writer.flush();
    186       }
    187       writer.close();
    188       reader.close();
    189       for (int i = 1; i < args.length; i++) {
    190         System.out.println(args[i]);
    191         System.out.flush();
    192       }
    193     }
    194   }
    195 }
    196