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