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