changeset 3073:f81c37805b5b

Merge
author lana
date Tue, 30 Nov 2010 14:49:26 -0800
parents 37d74e29687c 23a6ba383fd7
children 5fc778c913e7
files
diffstat 6 files changed, 677 insertions(+), 96 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/J2DBench.java	Mon Nov 29 13:38:12 2010 -0800
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/J2DBench.java	Tue Nov 30 14:49:26 2010 -0800
@@ -75,7 +75,8 @@
 
     static JFrame guiFrame;
 
-    static final SimpleDateFormat sdf = new SimpleDateFormat("MM.dd.yyyy 'at' HH:mm aaa z");
+    static final SimpleDateFormat sdf =
+        new SimpleDateFormat("MM.dd.yyyy 'at' HH:mm aaa z");
 
     public static void init() {
         progoptroot = new Group("prog", "Program Options");
@@ -176,6 +177,8 @@
     public static void main(String argv[]) {
         init();
         TestEnvironment.init();
+        Result.init();
+
         Destinations.init();
         GraphicsTests.init();
         RenderTests.init();
@@ -323,7 +326,7 @@
                     } else if (type.equalsIgnoreCase("m")) {
                         multiplyWith = 60;
                     } else {
-                        System.out.println("Invalid \"-loop\" option specified.");
+                        System.err.println("Invalid \"-loop\" option specified.");
                         usage(1);
                     }
 
@@ -331,32 +334,20 @@
                     try {
                         val = Integer.parseInt(argv[i].substring(0, argv[i].length() - 1));
                     } catch(Exception e) {
-                        System.out.println("Invalid \"-loop\" option specified.");
+                        System.err.println("Invalid \"-loop\" option specified.");
                         usage(1);
                     }
 
                     requiredLoopTime = val * multiplyWith * 1000;
                 }
 
-            } else if (arg.length() > 7 &&
-                       arg.substring(0, 7).equalsIgnoreCase("-report"))
-            {
-                for (int j = 7; j < arg.length(); j++) {
-                    char c = arg.charAt(j);
-                    switch (c) {
-                    case 'N': Result.unitScale = Result.UNITS_WHOLE;     break;
-                    case 'M': Result.unitScale = Result.UNITS_MILLIONS;  break;
-                    case 'K': Result.unitScale = Result.UNITS_THOUSANDS; break;
-                    case 'A': Result.unitScale = Result.UNITS_AUTO;      break;
-                    case 'U': Result.useUnits = true; break;
-                    case 'O': Result.useUnits = false; break;
-                    case 's': Result.timeScale = Result.SECONDS_WHOLE;  break;
-                    case 'm': Result.timeScale = Result.SECONDS_MILLIS; break;
-                    case 'u': Result.timeScale = Result.SECONDS_MICROS; break;
-                    case 'n': Result.timeScale = Result.SECONDS_NANOS;  break;
-                    case 'a': Result.timeScale = Result.SECONDS_AUTO;   break;
-                    case '/': Result.invertRate = !Result.invertRate; break;
-                    }
+           } else if (arg.length() > 8 &&
+                        arg.substring(0, 8).equalsIgnoreCase("-report:"))
+           {
+                String error = Result.parseRateOpt(arg.substring(8));
+                if (error != null) {
+                     System.err.println("Invalid rate: "+error);
+                     usage(1);
                 }
             } else {
                 String reason = Group.root.setOption(arg);
@@ -411,7 +402,7 @@
                         writer.flush();
                     } catch(IOException ioe) {
                         ioe.printStackTrace();
-                        System.out.println("\nERROR : Could not create Loop-Report. Exit");
+                        System.err.println("\nERROR : Could not create Loop-Report. Exit");
                         System.exit(1);
                     }
                 }
@@ -466,7 +457,7 @@
 
             } while(J2DBench.looping);
 
-            if(J2DBench.looping) {
+            if (J2DBench.looping) {
                 writer.println("</html>");
                 writer.flush();
                 writer.close();
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/Option.java	Mon Nov 29 13:38:12 2010 -0800
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/Option.java	Tue Nov 30 14:49:26 2010 -0800
@@ -170,7 +170,7 @@
                 updateGUI();
                 jcb.addItemListener(new ItemListener() {
                     public void itemStateChanged(ItemEvent e) {
-                        if (e.getStateChange() == e.SELECTED) {
+                        if (e.getStateChange() == ItemEvent.SELECTED) {
                             JComboBox jcb = (JComboBox) e.getItemSelectable();
                             value = jcb.getSelectedIndex();
                             if (J2DBench.verbose.isEnabled()) {
@@ -261,7 +261,7 @@
                 updateGUI();
                 jcb.addItemListener(new ItemListener() {
                     public void itemStateChanged(ItemEvent e) {
-                        value = (e.getStateChange() == e.SELECTED);
+                        value = (e.getStateChange() == ItemEvent.SELECTED);
                         if (J2DBench.verbose.isEnabled()) {
                             System.out.println(getOptionString());
                         }
@@ -569,8 +569,6 @@
         }
 
         public String setValueFromString(String value) {
-            int prev = 0;
-            int next = 0;
             int enabled = 0;
             StringTokenizer st = new StringTokenizer(value, ",");
             while (st.hasMoreTokens()) {
@@ -588,7 +586,6 @@
                 if (s != null) {
                     return "Bad value in list ("+s+")";
                 }
-                prev = next+1;
             }
             this.enabled = enabled;
             updateGUI();
@@ -623,6 +620,175 @@
         }
     }
 
+    public static class ObjectChoice extends Option {
+         int size;
+         String optionnames[];
+         Object optionvalues[];
+         String abbrevnames[];
+         String descnames[];
+         int defaultselected;
+         int selected;
+         JPanel jp;
+         JComboBox jcombo;
+
+         public ObjectChoice(Group parent, String nodeName, String description,
+                             String optionnames[],
+                             Object optionvalues[],
+                             String abbrevnames[],
+                             String descnames[],
+                             int defaultselected)
+         {
+             this(parent, nodeName, description,
+                  Math.min(Math.min(optionnames.length,
+                                    optionvalues.length),
+                           Math.min(abbrevnames.length,
+                                    descnames.length)),
+                  optionnames, optionvalues,
+                  abbrevnames, descnames, defaultselected);
+         }
+
+         public ObjectChoice(Group parent, String nodeName, String description,
+                             int size,
+                             String optionnames[],
+                             Object optionvalues[],
+                             String abbrevnames[],
+                             String descnames[],
+                             int defaultselected)
+         {
+             super(parent, nodeName, description);
+             this.size = size;
+             this.optionnames = trim(optionnames, size);
+             this.optionvalues = trim(optionvalues, size);
+             this.abbrevnames = trim(abbrevnames, size);
+             this.descnames = trim(descnames, size);
+             this.selected = this.defaultselected = defaultselected;
+         }
+
+         private static String[] trim(String list[], int size) {
+             if (list.length == size) {
+                 return list;
+             }
+             String newlist[] = new String[size];
+             System.arraycopy(list, 0, newlist, 0, size);
+             return newlist;
+         }
+
+         private static Object[] trim(Object list[], int size) {
+             if (list.length == size) {
+                 return list;
+             }
+             Object newlist[] = new Object[size];
+             System.arraycopy(list, 0, newlist, 0, size);
+             return newlist;
+         }
+
+         public void restoreDefault() {
+             if (selected != defaultselected) {
+                 selected = defaultselected;
+                 updateGUI();
+             }
+         }
+
+         public void updateGUI() {
+             if (jcombo != null) {
+                 jcombo.setSelectedIndex(this.selected);
+             }
+         }
+
+         public boolean isDefault() {
+             return (selected == defaultselected);
+         }
+
+         public Modifier.Iterator getIterator(TestEnvironment env) {
+             return new SwitchIterator(optionvalues, 1 << selected);
+         }
+
+         public JComponent getJComponent() {
+             if (jp == null) {
+                 jp = new JPanel();
+                 jp.setLayout(new BorderLayout());
+                 jp.add(new JLabel(getDescription()), BorderLayout.WEST);
+                 jcombo = new JComboBox(descnames);
+                 updateGUI();
+                 jcombo.addItemListener(new ItemListener() {
+                     public void itemStateChanged(ItemEvent e) {
+                         if (e.getStateChange() == ItemEvent.SELECTED) {
+                             selected = jcombo.getSelectedIndex();
+                             if (J2DBench.verbose.isEnabled()) {
+                                 System.out.println(getOptionString());
+                             }
+                         }
+                     }
+                 });
+                 jp.add(jcombo, BorderLayout.EAST);
+             }
+             return jp;
+         }
+
+         public Object getValue() {
+             return optionvalues[selected];
+         }
+
+         public int getIntValue() {
+             return ((Integer) optionvalues[selected]).intValue();
+         }
+
+         public boolean getBooleanValue() {
+             return ((Boolean) optionvalues[selected]).booleanValue();
+         }
+
+         public String getValString() {
+             return optionnames[selected];
+         }
+
+         int findValueIndex(Object value) {
+             for (int i = 0; i < size; i++) {
+                 if (optionvalues[i] == value) {
+                     return i;
+                 }
+             }
+             return -1;
+         }
+
+         public String getValString(Object value) {
+             return optionnames[findValueIndex(value)];
+         }
+
+         public String getAbbreviatedModifierDescription(Object value) {
+             return abbrevnames[findValueIndex(value)];
+         }
+
+         public String setValue(int v) {
+             return setValue(new Integer(v));
+         }
+
+         public String setValue(boolean v) {
+             return setValue(new Boolean(v));
+         }
+
+         public String setValue(Object value) {
+             for (int i = 0; i < size; i++) {
+                 if (optionvalues[i].equals(value)) {
+                     this.selected = i;
+                     updateGUI();
+                     return null;
+                 }
+             }
+             return "Bad value";
+         }
+
+         public String setValueFromString(String value) {
+             for (int i = 0; i < size; i++) {
+                 if (optionnames[i].equals(value)) {
+                     this.selected = i;
+                     updateGUI();
+                     return null;
+                 }
+             }
+             return "Bad value";
+         }
+    }
+
     public static class BooleanIterator implements Modifier.Iterator {
         private Boolean list[];
         private int index;
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/Result.java	Mon Nov 29 13:38:12 2010 -0800
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/Result.java	Tue Nov 30 14:49:26 2010 -0800
@@ -35,23 +35,199 @@
 import java.util.Hashtable;
 import java.util.Enumeration;
 import java.io.PrintWriter;
+import java.util.HashMap;
 
 public class Result {
-    public static final int UNITS_WHOLE      = 0;
-    public static final int UNITS_THOUSANDS  = 1;
-    public static final int UNITS_MILLIONS   = 2;
-    public static final int UNITS_AUTO       = 3;
+    public static final int RATE_UNKNOWN    = 0;
 
-    public static final int SECONDS_WHOLE = 0;
-    public static final int SECONDS_MILLIS = 1;
-    public static final int SECONDS_MICROS = 2;
-    public static final int SECONDS_NANOS  = 3;
-    public static final int SECONDS_AUTO  = 4;
+    public static final int WORK_OPS        = 1;
+    public static final int WORK_UNITS      = 2;
+    public static final int WORK_THOUSANDS  = 4;
+    public static final int WORK_MILLIONS   = 6;
+    public static final int WORK_AUTO       = 8;
 
-    public static int unitScale = UNITS_WHOLE;
-    public static int timeScale = SECONDS_WHOLE;
-    public static boolean useUnits = true;
-    public static boolean invertRate = false;
+    public static final int TIME_SECONDS    = 10;
+    public static final int TIME_MILLIS     = 11;
+    public static final int TIME_MICROS     = 12;
+    public static final int TIME_NANOS      = 13;
+    public static final int TIME_AUTO       = 14;
+
+    static Group resultoptroot;
+    static Option.ObjectChoice timeOpt;
+    static Option.ObjectChoice workOpt;
+    static Option.ObjectChoice rateOpt;
+
+    public static void init() {
+        resultoptroot = new Group(TestEnvironment.globaloptroot,
+                                  "results", "Result Options");
+
+        String workStrings[] = {
+            "units",
+            "kilounits",
+            "megaunits",
+            "autounits",
+            "ops",
+            "kiloops",
+            "megaops",
+            "autoops",
+        };
+        String workDescriptions[] = {
+            "Test Units",
+            "Thousands of Test Units",
+            "Millions of Test Units",
+            "Auto-scaled Test Units",
+            "Operations",
+            "Thousands of Operations",
+            "Millions of Operations",
+            "Auto-scaled Operations",
+        };
+        Integer workObjects[] = {
+            new Integer(WORK_UNITS),
+            new Integer(WORK_THOUSANDS),
+            new Integer(WORK_MILLIONS),
+            new Integer(WORK_AUTO),
+            new Integer(WORK_OPS | WORK_UNITS),
+            new Integer(WORK_OPS | WORK_THOUSANDS),
+            new Integer(WORK_OPS | WORK_MILLIONS),
+            new Integer(WORK_OPS | WORK_AUTO),
+        };
+        workOpt = new Option.ObjectChoice(resultoptroot,
+                                          "workunits", "Work Units",
+                                          workStrings, workObjects,
+                                          workStrings, workDescriptions,
+                                          0);
+        String timeStrings[] = {
+            "sec",
+            "msec",
+            "usec",
+            "nsec",
+            "autosec",
+        };
+        String timeDescriptions[] = {
+            "Seconds",
+            "Milliseconds",
+            "Microseconds",
+            "Nanoseconds",
+            "Auto-scaled seconds",
+        };
+        Integer timeObjects[] = {
+            new Integer(TIME_SECONDS),
+            new Integer(TIME_MILLIS),
+            new Integer(TIME_MICROS),
+            new Integer(TIME_NANOS),
+            new Integer(TIME_AUTO),
+        };
+        timeOpt = new Option.ObjectChoice(resultoptroot,
+                                          "timeunits", "Time Units",
+                                          timeStrings, timeObjects,
+                                          timeStrings, timeDescriptions,
+                                          0);
+        String rateStrings[] = {
+            "unitspersec",
+            "secsperunit",
+        };
+        String rateDescriptions[] = {
+            "Work units per Time",
+            "Time units per Work",
+        };
+        Boolean rateObjects[] = {
+            Boolean.FALSE,
+            Boolean.TRUE,
+        };
+        rateOpt = new Option.ObjectChoice(resultoptroot,
+                                          "ratio", "Rate Ratio",
+                                          rateStrings, rateObjects,
+                                          rateStrings, rateDescriptions,
+                                          0);
+    }
+
+    public static boolean isTimeUnit(int unit) {
+        return (unit >= TIME_SECONDS && unit <= TIME_AUTO);
+    }
+
+    public static boolean isWorkUnit(int unit) {
+        return (unit >= WORK_OPS && unit <= (WORK_AUTO | WORK_OPS));
+    }
+
+    public static String parseRateOpt(String opt) {
+        int timeScale = timeOpt.getIntValue();
+        int workScale = workOpt.getIntValue();
+        boolean invertRate = rateOpt.getBooleanValue();
+        int divindex = opt.indexOf('/');
+        if (divindex < 0) {
+            int unit = parseUnit(opt);
+            if (isTimeUnit(unit)) {
+                timeScale = unit;
+            } else if (isWorkUnit(unit)) {
+                workScale = unit;
+            } else {
+                return "Bad unit: "+opt;
+            }
+        } else {
+            int unit1 = parseUnit(opt.substring(0,divindex));
+            int unit2 = parseUnit(opt.substring(divindex+1));
+            if (isTimeUnit(unit1)) {
+                if (isWorkUnit(unit2)) {
+                    timeScale = unit1;
+                    workScale = unit2;
+                    invertRate = true;
+                } else if (isTimeUnit(unit2)) {
+                    return "Both time units: "+opt;
+                } else {
+                    return "Bad denominator: "+opt;
+                }
+            } else if (isWorkUnit(unit1)) {
+                if (isWorkUnit(unit2)) {
+                    return "Both work units: "+opt;
+                } else if (isTimeUnit(unit2)) {
+                    timeScale = unit2;
+                    workScale = unit1;
+                    invertRate = false;
+                } else {
+                    return "Bad denominator: "+opt;
+                }
+            } else {
+                return "Bad numerator: "+opt;
+            }
+        }
+        timeOpt.setValue(timeScale);
+        workOpt.setValue(workScale);
+        rateOpt.setValue(invertRate);
+        return null;
+    }
+
+    private static HashMap unitMap;
+
+    static {
+        unitMap = new HashMap();
+        unitMap.put("U",  new Integer(WORK_UNITS));
+        unitMap.put("M",  new Integer(WORK_MILLIONS));
+        unitMap.put("K",  new Integer(WORK_THOUSANDS));
+        unitMap.put("A",  new Integer(WORK_AUTO));
+        unitMap.put("MU", new Integer(WORK_MILLIONS));
+        unitMap.put("KU", new Integer(WORK_THOUSANDS));
+        unitMap.put("AU", new Integer(WORK_AUTO));
+
+        unitMap.put("O",  new Integer(WORK_UNITS | WORK_OPS));
+        unitMap.put("NO", new Integer(WORK_UNITS | WORK_OPS));
+        unitMap.put("MO", new Integer(WORK_MILLIONS | WORK_OPS));
+        unitMap.put("KO", new Integer(WORK_THOUSANDS | WORK_OPS));
+        unitMap.put("AO", new Integer(WORK_AUTO | WORK_OPS));
+
+        unitMap.put("s",  new Integer(TIME_SECONDS));
+        unitMap.put("m",  new Integer(TIME_MILLIS));
+        unitMap.put("u",  new Integer(TIME_MICROS));
+        unitMap.put("n",  new Integer(TIME_NANOS));
+        unitMap.put("a",  new Integer(TIME_AUTO));
+    }
+
+    public static int parseUnit(String c) {
+        Integer u = (Integer) unitMap.get(c);
+        if (u != null) {
+            return u.intValue();
+        }
+        return RATE_UNKNOWN;
+    }
 
     String unitname = "unit";
     Test test;
@@ -157,69 +333,76 @@
     }
 
     public String getAverageString() {
-        double units = (useUnits ? getTotalUnits() : getTotalReps());
+        int timeScale = timeOpt.getIntValue();
+        int workScale = workOpt.getIntValue();
+        boolean invertRate = rateOpt.getBooleanValue();
         double time = getTotalTime();
+        String timeprefix = "";
+        switch (timeScale) {
+        case TIME_AUTO:
+        case TIME_SECONDS:
+            time /= 1000;
+            break;
+        case TIME_MILLIS:
+            timeprefix = "m";
+            break;
+        case TIME_MICROS:
+            time *= 1000.0;
+            timeprefix = "u";
+            break;
+        case TIME_NANOS:
+            time *= 1000000.0;
+            timeprefix = "n";
+            break;
+        }
+
+        String workprefix = "";
+        boolean isOps = (workScale & WORK_OPS) != 0;
+        String workname = isOps ? "op" : unitname;
+        double work = isOps ? getTotalReps() : getTotalUnits();
+        switch (workScale & (~WORK_OPS)) {
+        case WORK_AUTO:
+        case WORK_UNITS:
+            break;
+        case WORK_THOUSANDS:
+            work /= 1000.0;
+            workprefix = "K";
+            break;
+        case WORK_MILLIONS:
+            work /= 1000000.0;
+            workprefix = "M";
+            break;
+        }
         if (invertRate) {
-            double rate = time / units;
-            String prefix = "";
-            switch (timeScale) {
-            case SECONDS_WHOLE:
-                rate /= 1000;
-                break;
-            case SECONDS_MILLIS:
-                prefix = "m";
-                break;
-            case SECONDS_MICROS:
-                rate *= 1000.0;
-                prefix = "u";
-                break;
-            case SECONDS_NANOS:
-                rate *= 1000000.0;
-                prefix = "n";
-                break;
-            case SECONDS_AUTO:
-                rate /= 1000.0;
+            double rate = time / work;
+            if (timeScale == TIME_AUTO) {
                 if (rate < 1.0) {
                     rate *= 1000.0;
-                    prefix = "m";
+                    timeprefix = "m";
                     if (rate < 1.0) {
                         rate *= 1000.0;
-                        prefix = "u";
+                        timeprefix = "u";
                         if (rate < 1.0) {
                             rate *= 1000.0;
-                            prefix = "n";
+                            timeprefix = "n";
                         }
                     }
                 }
-                break;
             }
-            return rate+" "+prefix+"secs/"+(useUnits ? unitname : "op");
+            return rate+" "+timeprefix+"secs/"+workprefix+workname;
         } else {
-            double rate = units / (time / 1000.0);
-            String prefix = "";
-            switch (unitScale) {
-            case UNITS_WHOLE:
-                break;
-            case UNITS_THOUSANDS:
-                rate /= 1000.0;
-                prefix = "K";
-                break;
-            case UNITS_MILLIONS:
-                rate /= 1000000.0;
-                prefix = "M";
-                break;
-            case UNITS_AUTO:
+            double rate = work / time;
+            if (workScale == WORK_AUTO) {
                 if (rate > 1000.0) {
                     rate /= 1000.0;
-                    prefix = "K";
+                    workprefix = "K";
                     if (rate > 1000.0) {
                         rate /= 1000.0;
-                        prefix = "M";
+                        workprefix = "M";
                     }
                 }
-                break;
             }
-            return rate+" "+prefix+(useUnits ? unitname : "op")+"s/sec";
+            return rate+" "+workprefix+workname+"s/"+timeprefix+"sec";
         }
     }
 
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/report/J2DAnalyzer.java	Mon Nov 29 13:38:12 2010 -0800
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/report/J2DAnalyzer.java	Tue Nov 30 14:49:26 2010 -0800
@@ -61,6 +61,8 @@
                     "the following result sets are combined into a group");
         out.println("   -NoGroup              "+
                     "the following result sets stand on their own");
+        out.println("   -ShowUncontested      "+
+                    "show results even when only result set has a result");
         out.println("   -Graph                "+
                     "graph the results visually (using lines of *'s)");
         out.println("   -Best                 "+
@@ -83,6 +85,7 @@
     public static void main(String argv[]) {
         boolean gavehelp = false;
         boolean graph = false;
+        boolean ignoreuncontested = true;
         if (argv.length > 0 && argv[0].equalsIgnoreCase("-html")) {
             String newargs[] = new String[argv.length-1];
             System.arraycopy(argv, 1, newargs, 0, newargs.length);
@@ -97,6 +100,8 @@
                 results.add(groupHolder);
             } else if (arg.equalsIgnoreCase("-NoGroup")) {
                 groupHolder = null;
+            } else if (arg.equalsIgnoreCase("-ShowUncontested")) {
+                ignoreuncontested = false;
             } else if (arg.equalsIgnoreCase("-Graph")) {
                 graph = true;
             } else if (arg.equalsIgnoreCase("-Best")) {
@@ -171,18 +176,23 @@
             String key = keys[k];
             ResultHolder rh = base.getResultByKey(key);
             double score = rh.getScore();
-            System.out.println(rh.getShortKey()+":");
             double maxscore = score;
-            if (graph) {
-                for (int i = 0; i < numsets; i++) {
-                    ResultSetHolder rsh =
-                        (ResultSetHolder) results.elementAt(i);
-                    ResultHolder rh2 = rsh.getResultByKey(key);
-                    if (rh2 != null) {
+            int numcontesting = 0;
+            for (int i = 0; i < numsets; i++) {
+                ResultSetHolder rsh =
+                    (ResultSetHolder) results.elementAt(i);
+                ResultHolder rh2 = rsh.getResultByKey(key);
+                if (rh2 != null) {
+                    if (graph) {
                         maxscore = Math.max(maxscore, rh2.getBestScore());
                     }
+                    numcontesting++;
                 }
             }
+            if (ignoreuncontested && numcontesting < 2) {
+                continue;
+            }
+            System.out.println(rh.getShortKey()+":");
             for (int i = 0; i < numsets; i++) {
                 ResultSetHolder rsh = (ResultSetHolder) results.elementAt(i);
                 System.out.print(rsh.getTitle()+": ");
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/tests/GraphicsTests.java	Mon Nov 29 13:38:12 2010 -0800
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/tests/GraphicsTests.java	Tue Nov 30 14:49:26 2010 -0800
@@ -38,6 +38,8 @@
 import java.awt.Polygon;
 import java.awt.Color;
 import java.awt.Dimension;
+import java.awt.geom.Point2D;
+import java.awt.geom.AffineTransform;
 import java.lang.reflect.Field;
 
 import j2dbench.Destinations;
@@ -74,6 +76,7 @@
     static Option animList;
     static Option sizeList;
     static Option compRules;
+    static Option transforms;
     static Option doExtraAlpha;
     static Option doXor;
     static Option doClipping;
@@ -167,6 +170,29 @@
                                       j, rulenames, rules, rulenames,
                                       ruledescs, (1 << defrule));
             ((Option.ObjectList) compRules).setNumRows(4);
+
+            Transform xforms[] = {
+                Identity.instance,
+                FTranslate.instance,
+                Scale2x2.instance,
+                Rotate15.instance,
+                ShearX.instance,
+                ShearY.instance,
+            };
+            String xformnames[] = new String[xforms.length];
+            String xformdescs[] = new String[xforms.length];
+            for (int i = 0; i < xforms.length; i++) {
+                xformnames[i] = xforms[i].getShortName();
+                xformdescs[i] = xforms[i].getDescription();
+            }
+            transforms =
+                new Option.ObjectList(groptroot, "transform",
+                                      "Affine Transform",
+                                      xforms.length,
+                                      xformnames, xforms, xformnames,
+                                      xformdescs, 0x1);
+            ((Option.ObjectList) transforms).setNumRows(3);
+
             doExtraAlpha =
                 new Option.Toggle(groptroot, "extraalpha",
                                   "Render with an \"extra alpha\" of 0.125",
@@ -200,6 +226,7 @@
         int orgX, orgY;
         int initX, initY;
         int maxX, maxY;
+        double pixscale;
     }
 
     public GraphicsTests(Group parent, String nodeName, String description) {
@@ -211,7 +238,7 @@
     public Object initTest(TestEnvironment env, Result result) {
         Context ctx = createContext();
         initContext(env, ctx);
-        result.setUnits(pixelsTouched(ctx));
+        result.setUnits((int) (ctx.pixscale * pixelsTouched(ctx)));
         result.setUnitName("pixel");
         return ctx;
     }
@@ -232,6 +259,9 @@
         ctx.graphics = env.getGraphics();
         int w = env.getWidth();
         int h = env.getHeight();
+        ctx.size = env.getIntValue(sizeList);
+        ctx.outdim = getOutputSize(ctx.size, ctx.size);
+        ctx.pixscale = 1.0;
         if (hasGraphics2D) {
             Graphics2D g2d = (Graphics2D) ctx.graphics;
             AlphaComposite ac = (AlphaComposite) env.getModifier(compRules);
@@ -251,11 +281,14 @@
                 p.addPoint(0, 0);
                 g2d.clip(p);
             }
+            Transform tx = (Transform) env.getModifier(transforms);
+            Dimension envdim = new Dimension(w, h);
+            tx.init(g2d, ctx, envdim);
+            w = envdim.width;
+            h = envdim.height;
             g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
                                  env.getModifier(renderHint));
         }
-        ctx.size = env.getIntValue(sizeList);
-        ctx.outdim = getOutputSize(ctx.size, ctx.size);
         switch (env.getIntValue(animList)) {
         case 0:
             ctx.animate = false;
@@ -290,4 +323,201 @@
         graphics.dispose();
         ((Context) ctx).graphics = null;
     }
+
+    public abstract static class Transform {
+        public abstract String getShortName();
+        public abstract String getDescription();
+        public abstract void init(Graphics2D g2d, Context ctx, Dimension dim);
+
+        public static double scaleForPoint(AffineTransform at,
+                                           double xorig, double yorig,
+                                           double x, double y,
+                                           int w, int h)
+        {
+            Point2D.Double ptd = new Point2D.Double(x, y);
+            at.transform(ptd, ptd);
+            x = ptd.getX();
+            y = ptd.getY();
+            double scale = 1.0;
+            if (x < 0) {
+                scale = Math.min(scale, xorig / (xorig - x));
+            } else if (x > w) {
+                scale = Math.min(scale, (w - xorig) / (x - xorig));
+            }
+            if (y < 0) {
+                scale = Math.min(scale, yorig / (yorig - y));
+            } else if (y > h) {
+                scale = Math.min(scale, (h - yorig) / (y - yorig));
+            }
+            return scale;
+        }
+
+        public static Dimension scaleForTransform(AffineTransform at,
+                                                  Dimension dim)
+        {
+            int w = dim.width;
+            int h = dim.height;
+            Point2D.Double ptd = new Point2D.Double(0, 0);
+            at.transform(ptd, ptd);
+            double ox = ptd.getX();
+            double oy = ptd.getY();
+            if (ox < 0 || ox > w || oy < 0 || oy > h) {
+                throw new InternalError("origin outside destination");
+            }
+            double scalex = scaleForPoint(at, ox, oy, w, h, w, h);
+            double scaley = scalex;
+            scalex = Math.min(scaleForPoint(at, ox, oy, w, 0, w, h), scalex);
+            scaley = Math.min(scaleForPoint(at, ox, oy, 0, h, w, h), scaley);
+            if (scalex < 0 || scaley < 0) {
+                throw new InternalError("could not fit dims to transform");
+            }
+            return new Dimension((int) Math.floor(w * scalex),
+                                 (int) Math.floor(h * scaley));
+        }
+    }
+
+    public static class Identity extends Transform {
+        public static final Identity instance = new Identity();
+
+        private Identity() {}
+
+        public String getShortName() {
+            return "ident";
+        }
+
+        public String getDescription() {
+            return "Identity";
+        }
+
+        public void init(Graphics2D g2d, Context ctx, Dimension dim) {
+        }
+    }
+
+    public static class FTranslate extends Transform {
+        public static final FTranslate instance = new FTranslate();
+
+        private FTranslate() {}
+
+        public String getShortName() {
+            return "ftrans";
+        }
+
+        public String getDescription() {
+            return "FTranslate 1.5";
+        }
+
+        public void init(Graphics2D g2d, Context ctx, Dimension dim) {
+            int w = dim.width;
+            int h = dim.height;
+            AffineTransform at = new AffineTransform();
+            at.translate(1.5, 1.5);
+            g2d.transform(at);
+            dim.setSize(w-3, h-3);
+        }
+    }
+
+    public static class Scale2x2 extends Transform {
+        public static final Scale2x2 instance = new Scale2x2();
+
+        private Scale2x2() {}
+
+        public String getShortName() {
+            return "scale2x2";
+        }
+
+        public String getDescription() {
+            return "Scale 2x by 2x";
+        }
+
+        public void init(Graphics2D g2d, Context ctx, Dimension dim) {
+            int w = dim.width;
+            int h = dim.height;
+            AffineTransform at = new AffineTransform();
+            at.scale(2.0, 2.0);
+            g2d.transform(at);
+            dim.setSize(w/2, h/2);
+            ctx.pixscale = 4;
+        }
+    }
+
+    public static class Rotate15 extends Transform {
+        public static final Rotate15 instance = new Rotate15();
+
+        private Rotate15() {}
+
+        public String getShortName() {
+            return "rot15";
+        }
+
+        public String getDescription() {
+            return "Rotate 15 degrees";
+        }
+
+        public void init(Graphics2D g2d, Context ctx, Dimension dim) {
+            int w = dim.width;
+            int h = dim.height;
+            double theta = Math.toRadians(15);
+            double cos = Math.cos(theta);
+            double sin = Math.sin(theta);
+            double xsize = sin * h + cos * w;
+            double ysize = sin * w + cos * h;
+            double scale = Math.min(w / xsize, h / ysize);
+            xsize *= scale;
+            ysize *= scale;
+            AffineTransform at = new AffineTransform();
+            at.translate((w - xsize) / 2.0, (h - ysize) / 2.0);
+            at.translate(sin * h * scale, 0.0);
+            at.rotate(theta);
+            g2d.transform(at);
+            dim.setSize(scaleForTransform(at, dim));
+        }
+    }
+
+    public static class ShearX extends Transform {
+        public static final ShearX instance = new ShearX();
+
+        private ShearX() {}
+
+        public String getShortName() {
+            return "shearx";
+        }
+
+        public String getDescription() {
+            return "Shear X to the right";
+        }
+
+        public void init(Graphics2D g2d, Context ctx, Dimension dim) {
+            int w = dim.width;
+            int h = dim.height;
+            AffineTransform at = new AffineTransform();
+            at.translate(0.0, (h - (w*h)/(w + h*0.1)) / 2);
+            at.shear(0.1, 0.0);
+            g2d.transform(at);
+            dim.setSize(scaleForTransform(at, dim));
+        }
+    }
+
+    public static class ShearY extends Transform {
+        public static final ShearY instance = new ShearY();
+
+        private ShearY() {}
+
+        public String getShortName() {
+            return "sheary";
+        }
+
+        public String getDescription() {
+            return "Shear Y down";
+        }
+
+        public void init(Graphics2D g2d, Context ctx, Dimension dim) {
+            int w = dim.width;
+            int h = dim.height;
+            AffineTransform at = new AffineTransform();
+            at.translate((w - (w*h)/(h + w*0.1)) / 2, 0.0);
+            at.shear(0.0, 0.1);
+            g2d.transform(at);
+            dim.setSize(scaleForTransform(at, dim));
+        }
+    }
 }
--- a/src/share/demo/java2d/J2DBench/src/j2dbench/tests/text/TextTests.java	Mon Nov 29 13:38:12 2010 -0800
+++ b/src/share/demo/java2d/J2DBench/src/j2dbench/tests/text/TextTests.java	Tue Nov 30 14:49:26 2010 -0800
@@ -454,7 +454,7 @@
                                             taaNames, taaHints,
                                             taaNames, taaNames,
                                             0x1);
-            ((Option.ObjectList) taaList).setNumRows(2);
+            ((Option.ObjectList) taaList).setNumRows(6);
             // add special TextAAOpt for backwards compatibility with
             // older options files
             new TextAAOpt();
@@ -707,3 +707,4 @@
         }
     }
 }
+