1 /*
   2  * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 package j2dbench;
  33 
  34 import java.io.PrintWriter;
  35 import java.io.FileReader;
  36 import java.io.FileWriter;
  37 import java.io.LineNumberReader;
  38 import java.io.FileNotFoundException;
  39 import java.io.IOException;
  40 import java.io.File;
  41 import java.awt.Frame;
  42 import java.awt.Dimension;
  43 import java.awt.BorderLayout;
  44 import java.awt.event.ActionListener;
  45 import java.awt.event.ActionEvent;
  46 import java.awt.event.WindowAdapter;
  47 import java.awt.event.WindowEvent;
  48 import javax.swing.JFrame;
  49 import javax.swing.JButton;
  50 import javax.swing.JPanel;
  51 import javax.swing.BoxLayout;
  52 import javax.swing.JFileChooser;
  53 import javax.swing.JOptionPane;
  54 import java.text.SimpleDateFormat;
  55 import java.util.Date;
  56 
  57 import j2dbench.tests.GraphicsTests;
  58 import j2dbench.tests.ImageTests;
  59 import j2dbench.tests.MiscTests;
  60 import j2dbench.tests.RenderTests;
  61 import j2dbench.tests.PixelTests;
  62 import j2dbench.tests.iio.IIOTests;
  63 import j2dbench.tests.text.TextConstructionTests;
  64 import j2dbench.tests.text.TextMeasureTests;
  65 import j2dbench.tests.text.TextRenderTests;
  66 import j2dbench.tests.text.TextTests;
  67 
  68 public class J2DBench {
  69     static Group progoptroot;
  70 
  71     static Option.Enable verbose;
  72     static Option.Enable printresults;
  73 
  74     static boolean looping = false;
  75 
  76     static JFrame guiFrame;
  77 
  78     static final SimpleDateFormat sdf =
  79         new SimpleDateFormat("MM.dd.yyyy 'at' HH:mm aaa z");
  80 
  81     public static void init() {
  82         progoptroot = new Group("prog", "Program Options");
  83         progoptroot.setHidden();
  84 
  85         verbose =
  86             new Option.Enable(progoptroot,
  87                               "verbose", "Verbose print statements",
  88                               false);
  89         printresults =
  90             new Option.Enable(progoptroot,
  91                               "printresults", "Print results after each run",
  92                               true);
  93     }
  94 
  95     public static void usage(int exitcode) {
  96         System.out.println("usage: java -jar J2DBench.jar "+
  97                            "[<optionname>=<value>]");
  98         System.out.println("    "+
  99                            "[-list] "+
 100                            "[-gui | -interactive] "+
 101                            "[-batch] "+
 102                            "[-noshow] "+
 103                            "[-nosave] "+
 104                            "[-report:[NMKAUOsmuna/]] "+
 105                            "[-usage | -help] "+
 106                            "\n    "+
 107                            "\n    "+
 108                            "[-loadopts | -loadoptions] <optfile> "+
 109                            "[-saveopts | -saveoptions] <optfile> "+
 110                            "\n    "+
 111                            "[-saveres | -saveresults] <resfile> "+
 112                            "[-appres | -appendresults] <resfile> "+
 113                            "\n    "+
 114                            "[-title] <title> "+
 115                            "[-desc | -description] <description> "+
 116                            "\n    "+
 117                            "[-loop] <duration> [-loopdef | -loopdefault] "+
 118                            "");
 119         System.out.println("        -list      "+
 120                            "List the option settings on stdout");
 121         System.out.println("        -gui       "+
 122                            "Run the program in interactive mode (launch GUI)");
 123         System.out.println("        -batch     "+
 124                            "Run the program in batch mode (do not launch GUI)");
 125         System.out.println("        -noshow    "+
 126                            "Do not show output on the screen (batch mode)");
 127         System.out.println("        -nosave    "+
 128                            "Do not show save results to a file (batch mode)");
 129         System.out.println("        -report    "+
 130                            "Rate format to report 'X per Y' (default u/s)");
 131         System.out.println("                   "+
 132                            "  N = report in single units or ops");
 133         System.out.println("                   "+
 134                            "  M = report in millions of units or ops");
 135         System.out.println("                   "+
 136                            "  K = report in thousands of units or ops");
 137         System.out.println("                   "+
 138                            "  A = (auto) M or K as needed");
 139         System.out.println("                   "+
 140                            "  U = units as defined by the operation");
 141         System.out.println("                   "+
 142                            "  O = operations");
 143         System.out.println("                   "+
 144                            "  s = report by whole seconds");
 145         System.out.println("                   "+
 146                            "  m = report by milliseconds");
 147         System.out.println("                   "+
 148                            "  u = report by microseconds");
 149         System.out.println("                   "+
 150                            "  n = report by nanoseconds");
 151         System.out.println("                   "+
 152                            "  a = (auto) milli/micro/nanoseconds as needed");
 153         System.out.println("                   "+
 154                            "  / = invert (N/sec or secs/N)");
 155         System.out.println("        -usage     "+
 156                            "Print out this usage message");
 157         System.out.println("        -saveres   "+
 158                            "Save the results to the indicated file");
 159         System.out.println("        -appres    "+
 160                            "Append the results to the indicated file");
 161         System.out.println("        -title     "+
 162                            "Use the title for the saved results");
 163         System.out.println("        -desc      "+
 164                            "Use the description for the saved results");
 165         System.out.println("        -loop      "+
 166                            "Loop for the specified duration"+
 167                            "\n                   "+
 168                            "Duration specified as :"+
 169                            "\n                     "+
 170                            "<days>d / <hours>h / <minutes>m / dd:hh:mm");
 171         System.out.println("        -loopdef   "+
 172                            "Loop for a default duration of 72 hours");
 173 
 174         System.exit(exitcode);
 175     }
 176 
 177     public static void main(String argv[]) {
 178         init();
 179         TestEnvironment.init();
 180         Result.init();
 181 
 182         Destinations.init();
 183         GraphicsTests.init();
 184         RenderTests.init();
 185         PixelTests.init();
 186         ImageTests.init();
 187         MiscTests.init();
 188         TextTests.init();
 189         TextRenderTests.init();
 190         TextMeasureTests.init();
 191         TextConstructionTests.init();
 192         IIOTests.init();
 193 
 194         boolean gui = true;
 195         boolean showresults = true;
 196         boolean saveresults = true;
 197         String resfilename = null;
 198         String title = null;
 199         String desc = null;
 200         boolean appendres = false;
 201         long requiredLoopTime = 259200000; // 72 hrs * 60 * 60 * 1000
 202         for (int i = 0; i < argv.length; i++) {
 203             String arg = argv[i];
 204             if (arg.equalsIgnoreCase("-list")) {
 205                 PrintWriter pw = new PrintWriter(System.out);
 206                 Node.Iterator iter = Group.root.getRecursiveChildIterator();
 207                 while (iter.hasNext()) {
 208                     Node n = iter.next();
 209                     n.write(pw);
 210                 }
 211                 pw.flush();
 212             } else if (arg.equalsIgnoreCase("-gui") ||
 213                        arg.equalsIgnoreCase("-interactive"))
 214             {
 215                 gui = true;
 216             } else if (arg.equalsIgnoreCase("-batch")) {
 217                 gui = false;
 218             } else if (arg.equalsIgnoreCase("-noshow")) {
 219                 showresults = false;
 220             } else if (arg.equalsIgnoreCase("-nosave")) {
 221                 saveresults = false;
 222             } else if (arg.equalsIgnoreCase("-usage") ||
 223                        arg.equalsIgnoreCase("-help"))
 224             {
 225                 usage(0);
 226             } else if (arg.equalsIgnoreCase("-loadoptions") ||
 227                        arg.equalsIgnoreCase("-loadopts"))
 228             {
 229                 if (++i < argv.length) {
 230                     String file = argv[i];
 231                     String reason = loadOptions(file);
 232                     if (reason != null) {
 233                         System.err.println(reason);
 234                         System.exit(1);
 235                     }
 236                 } else {
 237                     usage(1);
 238                 }
 239             } else if (arg.equalsIgnoreCase("-saveoptions") ||
 240                        arg.equalsIgnoreCase("-saveopts"))
 241             {
 242                 if (++i < argv.length) {
 243                     String file = argv[i];
 244                     String reason = saveOptions(file);
 245                     if (reason != null) {
 246                         System.err.println(reason);
 247                         System.exit(1);
 248                     }
 249                 } else {
 250                     usage(1);
 251                 }
 252             } else if (arg.equalsIgnoreCase("-saveresults") ||
 253                        arg.equalsIgnoreCase("-saveres") ||
 254                        arg.equalsIgnoreCase("-appendresults") ||
 255                        arg.equalsIgnoreCase("-appres"))
 256             {
 257                 if (++i < argv.length) {
 258                     resfilename = argv[i];
 259                     appendres = arg.substring(0, 4).equalsIgnoreCase("-app");
 260                 } else {
 261                     usage(1);
 262                 }
 263             } else if (arg.equalsIgnoreCase("-title")) {
 264                 if (++i < argv.length) {
 265                     title = argv[i];
 266                 } else {
 267                     usage(1);
 268                 }
 269             } else if (arg.equalsIgnoreCase("-desc") ||
 270                        arg.equalsIgnoreCase("-description"))
 271             {
 272                 if (++i < argv.length) {
 273                     desc = argv[i];
 274                 } else {
 275                     usage(1);
 276                 }
 277             } else if (arg.equalsIgnoreCase("-loopdef") ||
 278                        arg.equalsIgnoreCase("-loopdefault"))
 279             {
 280                 requiredLoopTime = 259200000; // 72 hrs * 60 * 60 * 1000
 281                 J2DBench.looping = true;
 282             } else if (arg.equalsIgnoreCase("-loop")) {
 283 
 284                 if (++i >= argv.length) {
 285                     usage(1);
 286                 }
 287 
 288                 J2DBench.looping = true;
 289 
 290                 /*
 291                  * d or D    ->  Days
 292                  * h or H    ->  Hours
 293                  * m or M    ->  Minutes
 294                  * dd:hh:mm  ->  Days:Hours:Minutes
 295                  */
 296 
 297                 if (argv[i].indexOf(":") >= 0) {
 298 
 299                     String values[] = argv[i].split(":");
 300                     int intVals[] = new int[3];
 301 
 302                     for(int j=0; j<values.length; j++) {
 303                         try {
 304                             intVals[j] = Integer.parseInt(values[j]);
 305                         } catch(Exception e) {}
 306                     }
 307 
 308                     System.out.println("\nLoop for " + intVals[0] +
 309                                        " days " + intVals[1] +
 310                                        " hours and " + intVals[2] + " minutes.\n");
 311 
 312                     requiredLoopTime = ((intVals[0] * 24 * 60 * 60) +
 313                                         (intVals[1] * 60 * 60) +
 314                                         (intVals[2] * 60)) * 1000;
 315 
 316                 } else {
 317 
 318                     String type = argv[i].substring(argv[i].length() - 1);
 319 
 320                     int multiplyWith = 1;
 321 
 322                     if (type.equalsIgnoreCase("d")) {
 323                         multiplyWith = 24 * 60 * 60;
 324                     } else if (type.equalsIgnoreCase("h")) {
 325                         multiplyWith = 60 * 60;
 326                     } else if (type.equalsIgnoreCase("m")) {
 327                         multiplyWith = 60;
 328                     } else {
 329                         System.err.println("Invalid \"-loop\" option specified.");
 330                         usage(1);
 331                     }
 332 
 333                     int val = 1;
 334                     try {
 335                         val = Integer.parseInt(argv[i].substring(0, argv[i].length() - 1));
 336                     } catch(Exception e) {
 337                         System.err.println("Invalid \"-loop\" option specified.");
 338                         usage(1);
 339                     }
 340 
 341                     requiredLoopTime = val * multiplyWith * 1000;
 342                 }
 343 
 344            } else if (arg.length() > 8 &&
 345                         arg.substring(0, 8).equalsIgnoreCase("-report:"))
 346            {
 347                 String error = Result.parseRateOpt(arg.substring(8));
 348                 if (error != null) {
 349                      System.err.println("Invalid rate: "+error);
 350                      usage(1);
 351                 }
 352             } else {
 353                 String reason = Group.root.setOption(arg);
 354                 if (reason != null) {
 355                     System.err.println("Option "+arg+" ignored: "+reason);
 356                 }
 357             }
 358         }
 359         if (verbose.isEnabled()) {
 360             Group.root.traverse(new Node.Visitor() {
 361                 public void visit(Node node) {
 362                     System.out.println(node);
 363                 }
 364             });
 365         }
 366 
 367         if (gui) {
 368             startGUI();
 369         } else {
 370 
 371             long start = System.currentTimeMillis();
 372 
 373             int nLoopCount = 1;
 374 
 375             if (saveresults) {
 376                 if (title == null) {
 377                     title = inputUserStr("title");
 378                 }
 379                 if (desc == null) {
 380                     desc = inputUserStr("description");
 381                 }
 382             }
 383 
 384             PrintWriter writer = null;
 385 
 386             if (J2DBench.looping) {
 387 
 388                 System.out.println("\nAbout to run tests for : " +
 389                                    (requiredLoopTime/1000) + " seconds.\n");
 390 
 391                 if(resfilename != null) {
 392 
 393                     try {
 394                         String loopReportFileName =
 395                             resfilename.substring(0, resfilename.lastIndexOf(".xml"));
 396                         writer = new PrintWriter(
 397                             new FileWriter(loopReportFileName + "_Loop.html"));
 398                         writer.println("<html><head><title>" + title + "</title></head>");
 399                         writer.println("<body bgcolor=\"#ffffff\"><hr size=\"1\">");
 400                         writer.println("<center><h2>" + title + "</h2>");
 401                         writer.println("</center><hr size=\"1\"><br>");
 402                         writer.flush();
 403                     } catch(IOException ioe) {
 404                         ioe.printStackTrace();
 405                         System.err.println("\nERROR : Could not create Loop-Report. Exit");
 406                         System.exit(1);
 407                     }
 408                 }
 409             }
 410 
 411             do {
 412 
 413                 Date loopStart = new Date();
 414                 if (J2DBench.looping) {
 415                     writer.println("<b>Loop # " + nLoopCount + "</b><br>");
 416                     writer.println("<b>Start : </b>" + sdf.format(loopStart) + "<br>");
 417                     writer.flush();
 418                 }
 419 
 420                 runTests(showresults);
 421                 if (saveresults) {
 422                     if (resfilename != null) {
 423                         lastResults.setTitle(title);
 424                         lastResults.setDescription(desc);
 425                         String reason = saveResults(resfilename, appendres);
 426                         if (reason != null) {
 427                             System.err.println(reason);
 428                         }
 429                     } else {
 430                         saveResults(title, desc);
 431                     }
 432                 }
 433 
 434                 if (J2DBench.looping) {
 435 
 436                     Date loopEnd = new Date();
 437 
 438                     System.out.println("\n================================================================");
 439                     System.out.println("-- Completed Loop " + nLoopCount + " at " + sdf.format(loopEnd) + " --");
 440                     System.out.println("================================================================\n");
 441 
 442                     writer.println("<b>End : </b>" + sdf.format(loopEnd) + "<br>");
 443                     writer.println("<b>Duration </b>: " + (loopEnd.getTime() - loopStart.getTime())/1000 + " Seconds<br>");
 444                     writer.println("<b>Total : " + (loopEnd.getTime() - start)/1000 + " Seconds</b><br>");
 445                     writer.println("</center><hr size=\"1\">");
 446                     writer.flush();
 447 
 448                     if ((loopEnd.getTime() - start) > requiredLoopTime) {
 449                         break;
 450                     }
 451 
 452                     //Append results for looping - mode
 453                     appendres = true;
 454 
 455                     nLoopCount++;
 456                 }
 457 
 458             } while(J2DBench.looping);
 459 
 460             if (J2DBench.looping) {
 461                 writer.println("</html>");
 462                 writer.flush();
 463                 writer.close();
 464             }
 465         }
 466     }
 467 
 468     public static String loadOptions(String filename) {
 469         FileReader fr;
 470         try {
 471             fr = new FileReader(filename);
 472         } catch (FileNotFoundException e) {
 473             return "file "+filename+" not found";
 474         }
 475         return loadOptions(fr, filename);
 476     }
 477 
 478     public static String loadOptions(File file) {
 479         FileReader fr;
 480         try {
 481             fr = new FileReader(file);
 482         } catch (FileNotFoundException e) {
 483             return "file "+file.getPath()+" not found";
 484         }
 485         return loadOptions(fr, file.getPath());
 486     }
 487 
 488     public static String loadOptions(FileReader fr, String filename) {
 489         LineNumberReader lnr = new LineNumberReader(fr);
 490         Group.restoreAllDefaults();
 491         String line;
 492         try {
 493             while ((line = lnr.readLine()) != null) {
 494                 String reason = Group.root.setOption(line);
 495                 if (reason != null) {
 496                     System.err.println("Option "+line+
 497                                        " at line "+lnr.getLineNumber()+
 498                                        " ignored: "+reason);
 499                 }
 500             }
 501         } catch (IOException e) {
 502             Group.restoreAllDefaults();
 503             return ("IO Error reading "+filename+
 504                     " at line "+lnr.getLineNumber());
 505         }
 506         return null;
 507     }
 508 
 509     public static String saveOptions(String filename) {
 510         return saveOptions(new File(filename));
 511     }
 512 
 513     public static String saveOptions(File file) {
 514         if (file.exists()) {
 515             if (!file.isFile()) {
 516                 return "Cannot save options to a directory!";
 517             }
 518             int ret = JOptionPane.showOptionDialog
 519                 (guiFrame,
 520                  new String[] {
 521                      "The file '"+file.getName()+"' already exists!",
 522                      "",
 523                      "Do you wish to overwrite this file?",
 524                  },
 525                  "File exists!",
 526                  JOptionPane.DEFAULT_OPTION,
 527                  JOptionPane.WARNING_MESSAGE,
 528                  null, new String[] {
 529                      "Overwrite",
 530                      "Cancel",
 531                  }, "Cancel");
 532             if (ret == 1) {
 533                 return null;
 534             }
 535         }
 536         FileWriter fw;
 537         try {
 538             fw = new FileWriter(file);
 539         } catch (IOException e) {
 540             return "Error opening option file "+file.getPath();
 541         }
 542         return saveOptions(fw, file.getPath());
 543     }
 544 
 545     public static String saveOptions(FileWriter fw, String filename) {
 546         PrintWriter pw = new PrintWriter(fw);
 547         Group.writeAll(pw);
 548         return null;
 549     }
 550 
 551     public static JFileChooser theFC;
 552     public static JFileChooser getFileChooser() {
 553         if (theFC == null) {
 554             theFC = new JFileChooser(System.getProperty("user.dir"));
 555         }
 556         theFC.rescanCurrentDirectory();
 557         return theFC;
 558     }
 559 
 560     public static ResultSet lastResults;
 561     public static boolean saveOrDiscardLastResults() {
 562         if (lastResults != null) {
 563             int ret = JOptionPane.showConfirmDialog
 564                 (guiFrame,
 565                  "The results of the last test will be "+
 566                  "discarded if you continue!  Do you want "+
 567                  "to save them?",
 568                  "Discard last results?",
 569                  JOptionPane.YES_NO_CANCEL_OPTION);
 570             if (ret == JOptionPane.CANCEL_OPTION) {
 571                 return false;
 572             } else if (ret == JOptionPane.YES_OPTION) {
 573                 if (saveResults()) {
 574                     lastResults = null;
 575                 } else {
 576                     return false;
 577                 }
 578             }
 579         }
 580         return true;
 581     }
 582 
 583     public static String inputUserStr(String type) {
 584         return JOptionPane.showInputDialog("Enter a "+
 585                                            type+
 586                                            " for this result set:");
 587     }
 588 
 589     public static boolean saveResults() {
 590         return saveResults(inputUserStr("title"), inputUserStr("description"));
 591     }
 592 
 593     public static boolean saveResults(String title, String desc) {
 594         lastResults.setTitle(title);
 595         lastResults.setDescription(desc);
 596         JFileChooser fc = getFileChooser();
 597         int ret = fc.showSaveDialog(guiFrame);
 598         if (ret == JFileChooser.APPROVE_OPTION) {
 599             File file = fc.getSelectedFile();
 600             boolean append = false;
 601             if (file.exists()) {
 602                 if (!file.isFile()) {
 603                     System.err.println("Cannot save results to a directory!");
 604                     return false;
 605                 }
 606                 ret = JOptionPane.showOptionDialog
 607                     (guiFrame,
 608                      new String[] {
 609                          "The file '"+file.getName()+"' already exists!",
 610                          "",
 611                          "Do you wish to overwrite or append to this file?",
 612                      },
 613                      "File exists!",
 614                      JOptionPane.DEFAULT_OPTION,
 615                      JOptionPane.WARNING_MESSAGE,
 616                      null, new String[] {
 617                          "Overwrite",
 618                          "Append",
 619                          "Cancel",
 620                      }, "Cancel");
 621                 if (ret == 0) {
 622                     append = false;
 623                 } else if (ret == 1) {
 624                     append = true;
 625                 } else {
 626                     return false;
 627                 }
 628             }
 629             String reason = saveResults(file, append);
 630             if (reason == null) {
 631                 return true;
 632             } else {
 633                 System.err.println(reason);
 634             }
 635         }
 636         return false;
 637     }
 638 
 639     public static String saveResults(String filename, boolean append) {
 640         FileWriter fw;
 641         try {
 642             fw = new FileWriter(filename, append);
 643         } catch (IOException e) {
 644             return "Error opening results file "+filename;
 645         }
 646         return saveResults(fw, filename, append);
 647     }
 648 
 649     public static String saveResults(File file, boolean append) {
 650         FileWriter fw;
 651         try {
 652             fw = new FileWriter(file, append);
 653         } catch (IOException e) {
 654             return "Error opening results file "+file.getName();
 655         }
 656         return saveResults(fw, file.getName(), append);
 657     }
 658 
 659     public static String saveResults(FileWriter fw, String filename,
 660                                      boolean append)
 661     {
 662         PrintWriter pw = new PrintWriter(fw);
 663         if (!append) {
 664             pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
 665             pw.println("<!--For Entertainment Purposes Only-->");
 666         }
 667         pw.println();
 668         lastResults.write(pw);
 669         pw.flush();
 670         pw.close();
 671         return null;
 672     }
 673 
 674     public static void startGUI() {
 675         final JFrame f = new JFrame("J2DBench") {
 676             public Dimension getPreferredSize() {
 677                 Dimension pref = super.getPreferredSize();
 678                 pref.width = Math.max(pref.width, 800);
 679                 pref.height = Math.max(pref.height, 600);
 680                 return pref;
 681             }
 682         };
 683         guiFrame = f;
 684         f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 685         f.getContentPane().setLayout(new BorderLayout());
 686         f.getContentPane().add(Group.root.getJComponent(), BorderLayout.CENTER);
 687         JPanel p = new JPanel();
 688         p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS));
 689         JButton b = new JButton("Run Tests...");
 690         b.addActionListener(new ActionListener() {
 691             public void actionPerformed(ActionEvent e) {
 692                 if (!saveOrDiscardLastResults()) {
 693                     return;
 694                 }
 695                 if (verbose.isEnabled()) {
 696                     System.out.println(e);
 697                     System.out.println("running tests...");
 698                 }
 699                 new Thread(new Runnable() {
 700                     public void run() {
 701                         runTests(true);
 702                     }
 703                 }).start();
 704                 if (verbose.isEnabled()) {
 705                     System.out.println("done");
 706                 }
 707             }
 708         });
 709         p.add(b);
 710 
 711         b = new JButton("Load Options");
 712         b.addActionListener(new ActionListener() {
 713             public void actionPerformed(ActionEvent e) {
 714                 JFileChooser fc = getFileChooser();
 715                 int ret = fc.showOpenDialog(f);
 716                 if (ret == JFileChooser.APPROVE_OPTION) {
 717                     String reason = loadOptions(fc.getSelectedFile());
 718                     if (reason != null) {
 719                         System.err.println(reason);
 720                     }
 721                 }
 722             }
 723         });
 724         p.add(b);
 725 
 726         b = new JButton("Save Options");
 727         b.addActionListener(new ActionListener() {
 728             public void actionPerformed(ActionEvent e) {
 729                 JFileChooser fc = getFileChooser();
 730                 int ret = fc.showSaveDialog(f);
 731                 if (ret == JFileChooser.APPROVE_OPTION) {
 732                     String reason = saveOptions(fc.getSelectedFile());
 733                     if (reason != null) {
 734                         System.err.println(reason);
 735                     }
 736                 }
 737             }
 738         });
 739         p.add(b);
 740 
 741         b = new JButton("Save Results");
 742         b.addActionListener(new ActionListener() {
 743             public void actionPerformed(ActionEvent e) {
 744                 if (saveResults()) {
 745                     lastResults = null;
 746                 }
 747             }
 748         });
 749         p.add(b);
 750 
 751         b = new JButton("Quit");
 752         b.addActionListener(new ActionListener() {
 753             public void actionPerformed(ActionEvent e) {
 754                 if (!saveOrDiscardLastResults()) {
 755                     return;
 756                 }
 757                 System.exit(0);
 758             }
 759         });
 760         p.add(b);
 761 
 762         f.getContentPane().add(p, BorderLayout.SOUTH);
 763         f.pack();
 764         f.show();
 765     }
 766 
 767     public static void runTests(boolean showresults) {
 768         final TestEnvironment env = new TestEnvironment();
 769         Frame f = null;
 770         if (showresults) {
 771             f = new Frame("J2DBench test run");
 772             f.addWindowListener(new WindowAdapter() {
 773                 public void windowClosing(WindowEvent e) {
 774                     env.stop();
 775                 }
 776             });
 777             f.add(env.getCanvas());
 778             f.pack();
 779             f.show();
 780         }
 781         for (int i = 0; i < 5; i++) {
 782             env.idle();
 783         }
 784         env.runAllTests();
 785         if (showresults) {
 786             f.hide();
 787             f.dispose();
 788         }
 789         lastResults = env.results;
 790         if (J2DBench.printresults.isEnabled()) {
 791             System.out.println();
 792         }
 793         System.out.println("All test results:");
 794         env.summarize();
 795         System.out.println();
 796     }
 797 }