1/* 2 * Copyright (c) 2000, 2017, 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 52package bench.rmi; 53 54import bench.ConfigFormatException; 55import bench.Harness; 56import bench.HtmlReporter; 57import bench.Reporter; 58import bench.TextReporter; 59import bench.XmlReporter; 60import static bench.rmi.Main.OutputFormat.*; 61import java.io.File; 62import java.io.FileInputStream; 63import java.io.FileNotFoundException; 64import java.io.FileOutputStream; 65import java.io.InputStream; 66import java.io.IOException; 67import java.io.OutputStream; 68import java.io.PrintStream; 69import java.rmi.AlreadyBoundException; 70import java.rmi.NotBoundException; 71import java.rmi.RemoteException; 72import java.rmi.registry.LocateRegistry; 73import java.rmi.registry.Registry; 74import java.rmi.server.RemoteObject; 75import java.util.ArrayList; 76import java.util.List; 77import java.util.Timer; 78import java.util.TimerTask; 79 80/** 81 * RMI/Serialization benchmark tests. 82 */ 83public 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 try { 281 client.waitFor(); 282 int exitValue = client.exitValue(); 283 if (0 != exitValue) { 284 die("Error: error happened in client process, exitValue = " + exitValue); 285 } 286 } finally { 287 client.destroyForcibly(); 288 } 289 } catch (IOException ex) { 290 die("Error: Unable start client process, ex=" + ex.getMessage()); 291 } catch (InterruptedException ex) { 292 die("Error: Error happening to client process, ex=" + ex.getMessage()); 293 } 294 break; 295 } 296 } 297 } 298 299 /** 300 * Parse command-line arguments. 301 */ 302 static void parseArgs(String[] args) { 303 for (int i = 0; i < args.length; i++) { 304 switch (args[i]) { 305 case "-h": 306 usage(); 307 System.exit(0); 308 break; 309 case "-v": 310 verbose = true; 311 break; 312 case "-l": 313 list = true; 314 break; 315 case "-t": 316 if (++i >= args.length) { 317 die("Error: no timeout value specified"); 318 } 319 try { 320 exitOnTimer = true; 321 testDurationSeconds = Integer.parseInt(args[i]) * 3600; 322 } catch (NumberFormatException e) { 323 die("Error: unable to determine timeout value"); 324 } 325 break; 326 case "-o": 327 if (++i >= args.length) { 328 die("Error: no output file specified"); 329 } 330 try { 331 repFile = args[i]; 332 repstr = new FileOutputStream(repFile); 333 } catch (FileNotFoundException e) { 334 die("Error: unable to open \"" + args[i] + "\""); 335 } 336 break; 337 case "-c": 338 if (++i >= args.length) { 339 die("Error: no config file specified"); 340 } 341 confFile = args[i]; 342 String confFullPath = TEST_SRC_PATH + confFile; 343 try { 344 confstr = new FileInputStream(confFullPath); 345 } catch (FileNotFoundException e) { 346 die("Error: unable to open \"" + confFullPath + "\""); 347 } 348 break; 349 case "-html": 350 if (format != TEXT) { 351 die("Error: conflicting formats"); 352 } 353 format = HTML; 354 break; 355 case "-xml": 356 if (format != TEXT) { 357 die("Error: conflicting formats"); 358 } 359 format = XML; 360 break; 361 case "-client": 362 if (runmode == CLIENT) { 363 die("Error: multiple -client options"); 364 } 365 if (runmode == SERVER) { 366 die("Error: -client and -server options conflict"); 367 } 368 if (++i >= args.length) { 369 die("Error: -client missing host/port"); 370 } 371 try { 372 String[] hostAndPort = args[i].split(":"); 373 if (hostAndPort.length != 2) { 374 die("Error: Invalid format host/port:" + args[i]); 375 } 376 host = hostAndPort[0]; 377 port = Integer.parseInt(hostAndPort[1]); 378 } catch (NumberFormatException e) { 379 die("Error: illegal host/port specified for -client"); 380 } 381 runmode = CLIENT; 382 break; 383 case "-server": 384 if (runmode == CLIENT) { 385 die("Error: -client and -server options conflict"); 386 } 387 if (runmode == SERVER) { 388 die("Error: multiple -server options"); 389 } 390 try { 391 //This is the hack code because named package class has 392 //difficulty in accessing unamed package class. This 393 //should be removed ater JDK-8003358 is finished. 394 port = (int) Class.forName("TestLibrary") 395 .getMethod("getUnusedRandomPort") 396 .invoke(null); 397 } catch (ReflectiveOperationException ex) { 398 die("Error: can't get a free port " + ex); 399 } 400 runmode = SERVER; 401 break; 402 default: 403 usage(); 404 die("Illegal option: \"" + args[i] + "\""); 405 } 406 } 407 } 408 409 /** 410 * Set up security manager and policy, if not set already. 411 */ 412 static void setupSecurity() { 413 if (System.getSecurityManager() != null) { 414 return; 415 } 416 417 /* As of 1.4, it is too late to set the security policy 418 * file at this point so these line have been commented out. 419 */ 420 //System.setProperty("java.security.policy", 421 // Main.class.getResource("/bench/rmi/policy.all").toString()); 422 System.setSecurityManager(new SecurityManager()); 423 } 424 425 /** 426 * Set up configuration file and report streams, if not set already. 427 */ 428 static void setupStreams() { 429 if (repstr == null) { 430 repstr = System.out; 431 } 432 if (confstr == null) { 433 confstr = Main.class.getResourceAsStream(TEST_SRC_PATH + CONFFILE); 434 } 435 if (confstr == null) { 436 die("Error: unable to find default config file"); 437 } 438 } 439 440 /** 441 * Print contents of configuration file to selected output stream. 442 */ 443 static void listConfig() { 444 try { 445 byte[] buf = new byte[256]; 446 int len; 447 while ((len = confstr.read(buf)) != -1) 448 repstr.write(buf, 0, len); 449 } catch (IOException e) { 450 die("Error: failed to list config file"); 451 } 452 } 453 454 /** 455 * Setup benchmark server. 456 */ 457 static void setupServer() { 458 switch (runmode) { 459 case SAMEVM: 460 try { 461 serverImpl = new BenchServerImpl(); 462 server = (BenchServer) RemoteObject.toStub(serverImpl); 463 } catch (RemoteException e) { 464 die("Error: failed to create local server: " + e); 465 } 466 if (verbose) 467 System.out.println("Benchmark server created locally"); 468 break; 469 470 case CLIENT: 471 try { 472 Registry reg = LocateRegistry.getRegistry(host, port); 473 server = (BenchServer) reg.lookup(REGNAME); 474 } catch (NotBoundException | RemoteException e) { 475 die("Error: failed to connect to server: " + e); 476 } 477 if (server == null) { 478 die("Error: server not found"); 479 } 480 if (verbose) { 481 System.out.println("Connected to benchmark server on " + 482 host + ":" + port); 483 } 484 break; 485 486 case SERVER: 487 try { 488 Registry reg = LocateRegistry.createRegistry(port); 489 serverImpl = new BenchServerImpl(); 490 reg.bind(REGNAME, serverImpl); 491 } catch (AlreadyBoundException | RemoteException e) { 492 die("Error: failed to initialize server: " + e); 493 } 494 if (verbose) { 495 System.out.println("Benchmark server started on port " + 496 port); 497 } 498 break; 499 500 default: 501 throw new InternalError("illegal runmode"); 502 } 503 } 504 505 /** 506 * Set up the timer to end the test. 507 * 508 * @param delay the amount of delay, in seconds, before requesting the 509 * process exit 510 */ 511 static void setupTimer(int delay) { 512 timer = new Timer(true); 513 timer.schedule( 514 new TimerTask() { 515 @Override 516 public void run() { 517 exitRequested = true; 518 } 519 }, 520 delay * 1000); 521 } 522 523 /** 524 * Set up benchmark harness. 525 */ 526 static void setupHarness() { 527 try { 528 harness = new RMIHarness(confstr); 529 } catch (ConfigFormatException e) { 530 String errmsg = e.getMessage(); 531 if (errmsg != null) { 532 die("Error parsing config file: " + errmsg); 533 } else { 534 die("Error: illegal config file syntax"); 535 } 536 } catch (IOException e) { 537 die("Error: failed to read config file"); 538 } 539 } 540 541 /** 542 * Setup benchmark reporter. 543 */ 544 static void setupReporter() { 545 reporter = format.getReport("RMI Benchmark, v" + VERSION); 546 } 547 548 /** 549 * Run benchmarks. 550 */ 551 static void runBenchmarks() { 552 harness.runBenchmarks(reporter, verbose); 553 } 554} 555