1 /* 2 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test @summary The RMI benchmark test. This java class is used to run the 26 * test under JTREG. 27 * @library ../../../../testlibrary ../../ 28 * @build TestLibrary bench.BenchInfo bench.HtmlReporter bench.Util 29 * bench.Benchmark bench.Reporter bench.XmlReporter bench.ConfigFormatException 30 * bench.Harness bench.TextReporter bench.rmi.BenchServer 31 * bench.rmi.DoubleArrayCalls bench.rmi.LongCalls bench.rmi.ShortCalls 32 * bench.rmi.BenchServerImpl bench.rmi.DoubleCalls bench.rmi.Main 33 * bench.rmi.SmallObjTreeCalls bench.rmi.BooleanArrayCalls 34 * bench.rmi.ExceptionCalls bench.rmi.NullCalls bench.rmi.BooleanCalls 35 * bench.rmi.ExportObjs bench.rmi.ObjArrayCalls bench.rmi.ByteArrayCalls 36 * bench.rmi.FloatArrayCalls bench.rmi.ObjTreeCalls bench.rmi.ByteCalls 37 * bench.rmi.FloatCalls bench.rmi.ProxyArrayCalls bench.rmi.CharArrayCalls 38 * bench.rmi.IntArrayCalls bench.rmi.RemoteObjArrayCalls bench.rmi.CharCalls 39 * bench.rmi.IntCalls bench.rmi.ClassLoading bench.rmi.LongArrayCalls 40 * bench.rmi.ShortArrayCalls 41 * bench.rmi.altroot.Node 42 * @run main/othervm/policy=policy.all/timeout=1800 bench.rmi.Main -server -c config 43 * @author Mike Warres, Nigel Daley 44 */ 45 46 package bench.rmi; 47 48 import bench.ConfigFormatException; 49 import bench.Harness; 50 import bench.HtmlReporter; 51 import bench.Reporter; 52 import bench.TextReporter; 53 import bench.XmlReporter; 54 import static bench.rmi.Main.OUTPUT_FORMAT.*; 55 import java.io.File; 56 import java.io.FileInputStream; 57 import java.io.FileNotFoundException; 58 import java.io.FileOutputStream; 59 import java.io.InputStream; 60 import java.io.IOException; 61 import java.io.OutputStream; 62 import java.io.PrintStream; 63 import java.lang.reflect.InvocationTargetException; 64 import java.lang.reflect.Method; 65 import java.rmi.AlreadyBoundException; 66 import java.rmi.NotBoundException; 67 import java.rmi.RemoteException; 68 import java.rmi.registry.LocateRegistry; 69 import java.rmi.registry.Registry; 70 import java.rmi.server.RemoteObject; 71 import java.util.ArrayList; 72 import java.util.List; 73 import java.util.Timer; 74 import java.util.TimerTask; 75 import java.util.logging.Level; 76 import java.util.logging.Logger; 77 78 /** 79 * RMI/Serialization benchmark tests. 80 */ 81 public class Main { 82 83 /** 84 * RMI-specific benchmark harness. 85 */ 86 static class RMIHarness extends Harness { 87 88 /** 89 * Construct new RMI benchmark harness. 90 */ 91 RMIHarness(InputStream in) throws IOException, ConfigFormatException { 92 super(in); 93 } 94 95 /** 96 * Cleanup both client and server side in between each benchmark. 97 */ 98 @Override 99 protected void cleanup() { 100 System.gc(); 101 if (Main.runmode == CLIENT) { 102 try { 103 Main.server.gc(); 104 } catch (RemoteException e) { 105 System.err.println("Warning: server gc failed: " + e); 106 } 107 } 108 } 109 } 110 111 static final String CONFFILE = "config"; 112 static final String VERSION = "1.3"; 113 static final String REGNAME = "server"; 114 115 static final int SAMEVM = 0; 116 static final int CLIENT = 1; 117 static final int SERVER = 2; 118 119 static enum OUTPUT_FORMAT { 120 121 TEXT { 122 @Override 123 Reporter getReport(String title) { 124 return new TextReporter(repstr, title); 125 } 126 }, HTML { 127 128 @Override 129 Reporter getReport(String title) { 130 return new HtmlReporter(repstr, title); 131 } 132 }, 133 XML { 134 @Override 135 Reporter getReport(String title) { 136 return new XmlReporter(repstr, title); 137 } 138 }; 139 140 abstract Reporter getReport(String title); 141 }; 142 143 static final String TEST_SRC_PATH = System.getProperty("test.src") + File.separator; 144 145 static boolean verbose; 146 static boolean list; 147 static boolean exitOnTimer; 148 static int testDurationSeconds; 149 static volatile boolean exitRequested; 150 static Timer timer; 151 static OUTPUT_FORMAT format = TEXT; 152 static int runmode; 153 static String confFile; 154 static InputStream confstr; 155 static String repFile; 156 static OutputStream repstr; 157 static String host; 158 static int port; 159 static RMIHarness harness; 160 static Reporter reporter; 161 static BenchServer server; 162 static BenchServerImpl serverImpl; 163 164 /** 165 * Returns reference to benchmark server. 166 * 167 * @return a benchmark server 168 */ 169 public static BenchServer getBenchServer() { 170 return server; 171 } 172 173 /** 174 * Prints help message. 175 */ 176 static void usage() { 177 PrintStream p = System.err; 178 p.println("\nUsage: java -jar rmibench.jar [-options]"); 179 p.println("\nwhere options are:"); 180 p.println(" -h print this message"); 181 p.println(" -v verbose mode"); 182 p.println(" -l list configuration file"); 183 p.println(" -t <num hours> repeat benchmarks for specified number of hours"); 184 p.println(" -o <file> specify output file"); 185 p.println(" -c <file> specify (non-default) " 186 + "configuration file"); 187 p.println(" -html format output as html " 188 + "(default is text)"); 189 p.println(" -xml format output as xml"); 190 p.println(" -client <host:port> run benchmark client using server " 191 + "on specified host/port"); 192 } 193 194 /** 195 * Throw RuntimeException that wrap message. 196 * 197 * @param mesg a message will be wrapped in the RuntimeException. 198 */ 199 static void die(String mesg) { 200 throw new RuntimeException(mesg); 201 } 202 203 /** 204 * Benchmark mainline. 205 * 206 * @param args 207 */ 208 public static void main(String[] args) { 209 setupSecurity(); 210 parseArgs(args); 211 setupStreams(); 212 if (list) { 213 listConfig(); 214 } else { 215 setupServer(); 216 switch (runmode) { 217 case SAMEVM: 218 case CLIENT: 219 setupHarness(); 220 setupReporter(); 221 if (exitOnTimer) { 222 setupTimer(testDurationSeconds); 223 do { 224 runBenchmarks(); 225 } while (!exitRequested); 226 } else { 227 runBenchmarks(); 228 } 229 break; 230 case SERVER: 231 //Setup for client mode, server will fork client process 232 //after its initiation. 233 List<String> clientProcessStr = new ArrayList<>(); 234 clientProcessStr.add(System.getProperty("java.home") + "/bin/java"); 235 String classpath = System.getProperty("java.class.path"); 236 if (classpath != null) { 237 clientProcessStr.add("-cp"); 238 clientProcessStr.add(classpath); 239 } 240 clientProcessStr.add("-Djava.security.policy=" + TEST_SRC_PATH + "policy.all"); 241 clientProcessStr.add("-Dtest.src=" + System.getProperty("test.src")); 242 clientProcessStr.add("bench.rmi.Main"); //Client mode 243 if (verbose) { 244 clientProcessStr.add("-v"); 245 } 246 if (list) { 247 clientProcessStr.add("-l"); 248 } 249 clientProcessStr.add("-client"); 250 clientProcessStr.add("localhost:" + port); 251 252 if (exitOnTimer) { 253 clientProcessStr.add("-t"); 254 clientProcessStr.add(String.valueOf(testDurationSeconds / 3600)); 255 } 256 if (repFile != null) { 257 clientProcessStr.add("-o"); 258 clientProcessStr.add(repFile); 259 } 260 if (confFile != null) { 261 clientProcessStr.add("-c"); 262 clientProcessStr.add(confFile); 263 } 264 switch (format) { 265 case HTML: 266 clientProcessStr.add("-html"); 267 break; 268 case XML: 269 clientProcessStr.add("-xml"); 270 break; 271 } 272 273 try { 274 Process client = new ProcessBuilder(clientProcessStr). 275 inheritIO().start(); 276 client.waitFor(); 277 int exitValue = client.exitValue(); 278 if (0 != exitValue) { 279 die("Error: error happened in client process, exitValue = " + exitValue); 280 } 281 } catch (IOException ex) { 282 die("Error: Unable start client process, ex=" + ex.getMessage()); 283 } catch (InterruptedException ex) { 284 die("Error: Error happening to client process, ex=" + ex.getMessage()); 285 } 286 break; 287 } 288 } 289 } 290 291 /** 292 * Parse command-line arguments. 293 */ 294 static void parseArgs(String[] args) { 295 for (int i = 0; i < args.length; i++) { 296 switch (args[i]) { 297 case "-h": 298 usage(); 299 System.exit(0); 300 break; 301 case "-v": 302 verbose = true; 303 break; 304 case "-l": 305 list = true; 306 break; 307 case "-t": 308 if (++i >= args.length) { 309 die("Error: no timeout value specified"); 310 } 311 try { 312 exitOnTimer = true; 313 testDurationSeconds = Integer.parseInt(args[i]) * 3600; 314 } catch (NumberFormatException e) { 315 die("Error: unable to determine timeout value"); 316 } 317 break; 318 case "-o": 319 if (++i >= args.length) { 320 die("Error: no output file specified"); 321 } 322 try { 323 repFile = args[i]; 324 repstr = new FileOutputStream(repFile); 325 } catch (FileNotFoundException e) { 326 die("Error: unable to open \"" + args[i] + "\""); 327 } 328 break; 329 case "-c": 330 if (++i >= args.length) { 331 die("Error: no config file specified"); 332 } 333 confFile = args[i]; 334 String confFullPath = TEST_SRC_PATH + confFile; 335 try { 336 confstr = new FileInputStream(confFullPath); 337 } catch (FileNotFoundException e) { 338 die("Error: unable to open \"" + confFullPath + "\""); 339 } 340 break; 341 case "-html": 342 if (format != TEXT) { 343 die("Error: conflicting formats"); 344 } 345 format = HTML; 346 break; 347 case "-xml": 348 if (format != TEXT) { 349 die("Error: conflicting formats"); 350 } 351 format = XML; 352 break; 353 case "-client": 354 if (runmode == CLIENT) { 355 die("Error: multiple -client options"); 356 } 357 if (runmode == SERVER) { 358 die("Error: -client and -server options conflict"); 359 } 360 if (++i >= args.length) { 361 die("Error: -client missing host/port"); 362 } 363 try { 364 String[] hostAndPort = args[i].split(":"); 365 if (hostAndPort.length != 2) { 366 die("Error: Invalid format host/port:" + args[i]); 367 } 368 host = hostAndPort[0]; 369 port = Integer.parseInt(hostAndPort[1]); 370 } catch (NumberFormatException e) { 371 die("Error: illegal host/port specified for -client"); 372 } 373 runmode = CLIENT; 374 break; 375 case "-server": 376 if (runmode == CLIENT) { 377 die("Error: -client and -server options conflict"); 378 } 379 if (runmode == SERVER) { 380 die("Error: multiple -server options"); 381 } 382 try { 383 //This is the hack code because named package class has 384 //difficulty in accessing unamed package class. This 385 //should be removed ater JDK-8003358 is finished. 386 Class tlCls = Class.forName("TestLibrary"); 387 Method gfpMethod = tlCls.getMethod("getUnusedRandomPort"); 388 port = (int) gfpMethod.invoke(null); 389 } catch (ClassNotFoundException | NoSuchMethodException | 390 IllegalAccessException | IllegalArgumentException | 391 InvocationTargetException ex) { 392 die("Error: can't get a free port " + ex); 393 } 394 runmode = SERVER; 395 break; 396 default: 397 usage(); 398 die("Illegal option: \"" + args[i] + "\""); 399 } 400 } 401 } 402 403 /** 404 * Set up security manager and policy, if not set already. 405 */ 406 static void setupSecurity() { 407 if (System.getSecurityManager() != null) { 408 return; 409 } 410 411 /* As of 1.4, it is too late to set the security policy 412 * file at this point so these line have been commented out. 413 */ 414 //System.setProperty("java.security.policy", 415 // Main.class.getResource("/bench/rmi/policy.all").toString()); 416 //RMISecurityManager has been deprecated, replace it with SecurityManager 417 System.setSecurityManager(new SecurityManager()); 418 } 419 420 /** 421 * Set up configuration file and report streams, if not set already. 422 */ 423 static void setupStreams() { 424 if (repstr == null) { 425 repstr = System.out; 426 } 427 if (confstr == null) { 428 confstr = Main.class.getResourceAsStream(TEST_SRC_PATH + CONFFILE); 429 } 430 if (confstr == null) { 431 die("Error: unable to find default config file"); 432 } 433 } 434 435 /** 436 * Print contents of configuration file to selected output stream. 437 */ 438 static void listConfig() { 439 try { 440 byte[] buf = new byte[256]; 441 int len; 442 while ((len = confstr.read(buf)) != -1) { 443 repstr.write(buf, 0, len); 444 } 445 } catch (IOException e) { 446 die("Error: failed to list config file"); 447 } 448 } 449 450 /** 451 * Setup benchmark server. 452 */ 453 static void setupServer() { 454 switch (runmode) { 455 case SAMEVM: 456 try { 457 serverImpl = new BenchServerImpl(); 458 server = (BenchServer) RemoteObject.toStub(serverImpl); 459 } catch (RemoteException e) { 460 die("Error: failed to create local server: " + e); 461 } 462 if (verbose) { 463 System.out.println("Benchmark server created locally"); 464 } 465 break; 466 467 case CLIENT: 468 try { 469 Registry reg = LocateRegistry.getRegistry(host, port); 470 server = (BenchServer) reg.lookup(REGNAME); 471 } catch (NotBoundException | RemoteException e) { 472 die("Error: failed to connect to server: " + e); 473 } 474 if (server == null) { 475 die("Error: server not found"); 476 } 477 if (verbose) { 478 System.out.println("Connected to benchmark server on " 479 + host + ":" + port); 480 } 481 break; 482 483 case SERVER: 484 try { 485 Registry reg = LocateRegistry.createRegistry(port); 486 serverImpl = new BenchServerImpl(); 487 reg.bind(REGNAME, serverImpl); 488 } catch (AlreadyBoundException | RemoteException e) { 489 die("Error: failed to initialize server: " + e); 490 } 491 if (verbose) { 492 System.out.println("Benchmark server started on port " 493 + port); 494 } 495 break; 496 497 default: 498 throw new InternalError("illegal runmode"); 499 } 500 } 501 502 /** 503 * Set up the timer to end the test. 504 * 505 * @param delay the amount of delay, in seconds, before requesting the 506 * process exit 507 */ 508 static void setupTimer(int delay) { 509 timer = new Timer(true); 510 timer.schedule( 511 new TimerTask() { 512 @Override 513 public void run() { 514 exitRequested = true; 515 } 516 }, 517 delay * 1000); 518 } 519 520 /** 521 * Set up benchmark harness. 522 */ 523 static void setupHarness() { 524 try { 525 harness = new RMIHarness(confstr); 526 } catch (ConfigFormatException e) { 527 String errmsg = e.getMessage(); 528 if (errmsg != null) { 529 die("Error parsing config file: " + errmsg); 530 } else { 531 die("Error: illegal config file syntax"); 532 } 533 } catch (IOException e) { 534 die("Error: failed to read config file"); 535 } 536 } 537 538 /** 539 * Setup benchmark reporter. 540 */ 541 static void setupReporter() { 542 reporter = format.getReport("RMI Benchmark, v" + VERSION); 543 } 544 545 /** 546 * Run benchmarks. 547 */ 548 static void runBenchmarks() { 549 harness.runBenchmarks(reporter, verbose); 550 } 551 }