Index: trunk/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java
===================================================================
--- trunk/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java	(revision 10222)
+++ trunk/test/performance/org/openstreetmap/josm/PerformanceTestUtils.java	(revision 10674)
@@ -1,4 +1,7 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm;
+
+import java.util.ArrayList;
+import java.util.Collections;
 
 import org.openstreetmap.josm.io.XmlWriter;
@@ -11,16 +14,37 @@
  */
 public final class PerformanceTestUtils {
+    private static final int TIMES_WARMUP = 2;
+    private static final int TIMES_RUN = 8;
+
+    /**
+     * A helper class that captures the time from object creation until #done() was called.
+     * @author Michael Zangl
+     */
+    public static class PerformanceTestTimerCapture {
+        private final long time;
+
+        protected PerformanceTestTimerCapture() {
+            time = System.nanoTime();
+        }
+
+        /**
+         * Get the time since this object was created.
+         * @return The time.
+         */
+        public long getTimeSinceCreation() {
+            return (System.nanoTime() - time) / 1000000;
+        }
+    }
+
     /**
      * A timer that measures the time from it's creation to the {@link #done()} call.
      * @author Michael Zangl
      */
-    public static class PerformanceTestTimer {
+    public static class PerformanceTestTimer extends PerformanceTestTimerCapture {
         private final String name;
-        private final long time;
-        private boolean measurementPlotsPlugin = false;
+        private boolean measurementPlotsPlugin = true;
 
         protected PerformanceTestTimer(String name) {
             this.name = name;
-            time = System.nanoTime();
         }
 
@@ -37,5 +61,5 @@
          */
         public void done() {
-            long dTime = (System.nanoTime() - time) / 1000000;
+            long dTime = getTimeSinceCreation();
             if (measurementPlotsPlugin) {
                 measurementPlotsPluginOutput(name + "(ms)", dTime);
@@ -50,5 +74,7 @@
 
     /**
-     * Starts a new performance timer.
+     * Starts a new performance timer. The timer will output the measurements in a format understood by Jenkins.
+     * <p>
+     * The timer can only be used to meassure one value.
      * @param name The name/description of the timer.
      * @return A {@link PerformanceTestTimer} object of which you can call {@link PerformanceTestTimer#done()} when done.
@@ -56,7 +82,37 @@
     @SuppressFBWarnings(value = "DM_GC", justification = "Performance test code")
     public static PerformanceTestTimer startTimer(String name) {
+        cleanSystem();
+        return new PerformanceTestTimer(name);
+    }
+
+    /**
+     * Runs the given performance test several (approx. 10) times and prints the median run time.
+     * @param name The name to use in the output
+     * @param testRunner The test to run
+     */
+    public static void runPerformanceTest(String name, Runnable testRunner) {
+        for (int i = 0; i < TIMES_WARMUP; i++) {
+            cleanSystem();
+            PerformanceTestTimerCapture capture = new PerformanceTestTimerCapture();
+            testRunner.run();
+            capture.getTimeSinceCreation();
+        }
+        ArrayList<Long> times = new ArrayList<>();
+        for (int i = 0; i < TIMES_RUN; i++) {
+            cleanSystem();
+            PerformanceTestTimerCapture capture = new PerformanceTestTimerCapture();
+            testRunner.run();
+            times.add(capture.getTimeSinceCreation());
+        }
+        System.out.println(times);
+        Collections.sort(times);
+        // Sort out e.g. GC during test run.
+        double avg = times.subList(2, times.size() - 2).stream().mapToLong(l -> l).average().getAsDouble();
+        measurementPlotsPluginOutput(name, avg);
+    }
+
+    private static void cleanSystem() {
         System.gc();
         System.runFinalization();
-        return new PerformanceTestTimer(name);
     }
 
@@ -68,5 +124,5 @@
      * @param name the name / title of the measurement
      * @param value the value
-     * @see https://wiki.jenkins-ci.org/display/JENKINS/Measurement+Plots+Plugin
+     * @see "https://wiki.jenkins-ci.org/display/JENKINS/Measurement+Plots+Plugin"
      */
     public static void measurementPlotsPluginOutput(String name, double value) {
Index: trunk/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSConditionPerformanceTest.java
===================================================================
--- trunk/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSConditionPerformanceTest.java	(revision 10674)
+++ trunk/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSConditionPerformanceTest.java	(revision 10674)
@@ -0,0 +1,68 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.mappaint.mapcss;
+
+import java.util.EnumSet;
+
+import org.junit.Test;
+import org.openstreetmap.josm.PerformanceTestUtils;
+import org.openstreetmap.josm.gui.mappaint.mapcss.Condition.Op;
+
+/**
+ * Performance test of MapCSS Condition objects.
+ * @author Michael Zangl
+ */
+public class MapCSSConditionPerformanceTest {
+    /**
+     * Test the performance of all OP entries.
+     */
+    @Test
+    public void testAllOps() {
+        // The JIT does some really heavy optimisations if it notices that other values are not used.
+        // If we want to simulate a real scenario, we need to invoke every op several times to let the compiler
+        // build the jump tables.
+        for (Op op : Op.values()) {
+            getRunner(op).run();
+        }
+        for (Op op : Op.values()) {
+            runTest(op);
+        }
+    }
+
+    private void runTest(Op op) {
+        Runnable r = getRunner(op);
+        PerformanceTestUtils.runPerformanceTest("Condition.Op." + op, r);
+    }
+
+    private Runnable getRunner(Op op) {
+        Runnable r;
+        if (EnumSet.of(Op.LESS, Op.LESS_OR_EQUAL, Op.GREATER, Op.GREATER_OR_EQUAL).contains(op)) {
+            r = () -> {
+                for (int i = 0; i < 10000; i++) {
+                        op.eval(null, "0.2");
+                        op.eval("nan", "0.1");
+                        op.eval("0.2983", "192.312");
+                        op.eval("0.2983", "0.2983");
+                        op.eval("2983", "1000");
+                        op.eval("1000", "1000");
+                }
+            };
+        } else {
+            // regexp are slow
+            int runs = EnumSet.of(Op.ONE_OF, Op.REGEX, Op.NREGEX).contains(op) ? 10000 : 100000;
+            r = () -> {
+                for (int i = 0; i < runs; i++) {
+                    op.eval("k1", "v1");
+                    op.eval("k1", "k1");
+                    op.eval("", "v1");
+                    op.eval(null, "abc");
+                    op.eval("extreamlylongkeyextreamlylongkeyextreamlylongkeyextreamlylongkey",
+                            "longvaluelongvaluelongvaluelongvalue");
+                    op.eval("0.2983", "192.312");
+                    op.eval("0.2983", "0.2983");
+                    op.eval("2983", "\\d+");
+                }
+            };
+        }
+        return r;
+    }
+}
Index: trunk/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java
===================================================================
--- trunk/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java	(revision 10222)
+++ trunk/test/performance/org/openstreetmap/josm/gui/mappaint/mapcss/MapCSSStyleSourceFilterTest.java	(revision 10674)
@@ -104,5 +104,5 @@
         data.generateDataSet();
         CssGenerator css = new CssGenerator(data).addKeyValueRules(TEST_RULE_COUNT);
-        runTest(data, css, "only key=value rules", false);
+        runTest(data, css, "only key=value rules");
     }
 
@@ -115,5 +115,5 @@
         data.generateDataSet();
         CssGenerator css = new CssGenerator(data).addHasKeyRules(TEST_RULE_COUNT);
-        runTest(data, css, "only has key rules", false);
+        runTest(data, css, "only has key rules");
     }
 
@@ -126,5 +126,5 @@
         data.generateDataSet();
         CssGenerator css = new CssGenerator(data).addKeyRegexpRules(TEST_RULE_COUNT);
-        runTest(data, css, "regular expressions", true);
+        runTest(data, css, "regular expressions");
     }
 
@@ -137,8 +137,8 @@
         data.generateDataSet();
         CssGenerator css = new CssGenerator(data).addIsTrueRules(TEST_RULE_COUNT);
-        runTest(data, css, "is true", false);
+        runTest(data, css, "is true");
     }
 
-    private void runTest(KeyValueDataGenerator data, CssGenerator css, String description, boolean measurementPlotsPlugin) {
+    private void runTest(KeyValueDataGenerator data, CssGenerator css, String description) {
         MapCSSStyleSource source = new MapCSSStyleSource(css.getCss());
         PerformanceTestTimer timer = PerformanceTestUtils.startTimer("MapCSSStyleSource#loadStyleSource(...) for " + description);
@@ -146,10 +146,5 @@
         timer.done();
 
-        if (measurementPlotsPlugin) {
-            timer = PerformanceTestUtils.startTimer(description);
-            timer.setMeasurementPlotsPluginOutput(true);
-        } else {
-            timer = PerformanceTestUtils.startTimer(APPLY_CALLS + "x MapCSSStyleSource#apply(...) for " + description);
-        }
+        timer = PerformanceTestUtils.startTimer(APPLY_CALLS + "x MapCSSStyleSource#apply(...) for " + description);
         for (int i = 0; i < APPLY_CALLS; i++) {
             MultiCascade mc = new MultiCascade();
