changeset 1136:bab1bf789b5b

7901300: Profiler methods should be called in a specific order Summary: Profiler start in the specified order, and stops in reverse order.
author shade
date Wed, 18 Feb 2015 21:08:07 +0300
parents e0f24b563ae3
children 4546bb1275b5
files jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTest.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractExternalProfiler.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractInternalProfiler.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ExternalProfiler1.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ExternalProfiler2.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ExternalProfiler3.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/InternalProfiler1.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/InternalProfiler2.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/InternalProfiler3.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ProfilerOrderTest.java jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ProfilerTimestamp.java jmh-core-it/src/test/resources/META-INF/services/org.openjdk.jmh.profile.Profiler jmh-core/src/main/java/org/openjdk/jmh/runner/BaseBenchmarkHandler.java jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/CommandLineOptions.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java
diffstat 17 files changed, 614 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTest.java	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/ProfilerTest.java	Wed Feb 18 21:08:07 2015 +0300
@@ -39,7 +39,7 @@
 import org.openjdk.jmh.runner.options.Options;
 import org.openjdk.jmh.runner.options.OptionsBuilder;
 
-import java.util.Set;
+import java.util.List;
 import java.util.concurrent.TimeUnit;
 
 public class ProfilerTest {
@@ -72,16 +72,16 @@
 
     @Test
     public void testInternal_CLI() throws RunnerException, CommandLineOptionException {
-        Set<Class<? extends Profiler>> ps = new CommandLineOptions("-prof", "itinternal").getProfilers();
+        List<Class<? extends Profiler>> ps = new CommandLineOptions("-prof", "itinternal").getProfilers();
         Assert.assertEquals(1, ps.size());
-        Assert.assertEquals(ItInternalProfiler.class.getName(), ps.iterator().next().getName());
+        Assert.assertEquals(ItInternalProfiler.class.getName(), ps.get(0).getName());
     }
 
     @Test
     public void testExternal_CLI() throws RunnerException, CommandLineOptionException {
-        Set<Class<? extends Profiler>> ps = new CommandLineOptions("-prof", "itexternal").getProfilers();
+        List<Class<? extends Profiler>> ps = new CommandLineOptions("-prof", "itexternal").getProfilers();
         Assert.assertEquals(1, ps.size());
-        Assert.assertEquals(ItExternalProfiler.class.getName(), ps.iterator().next().getName());
+        Assert.assertEquals(ItExternalProfiler.class.getName(), ps.get(0).getName());
     }
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractExternalProfiler.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.profile.ExternalProfiler;
+import org.openjdk.jmh.results.Result;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public abstract class AbstractExternalProfiler implements ExternalProfiler {
+
+    private final String pfx;
+    protected long start, stop;
+
+    protected AbstractExternalProfiler(String pfx) {
+        this.pfx = pfx;
+    }
+
+    @Override
+    public boolean allowPrintErr() {
+        return true;
+    }
+
+    @Override
+    public boolean allowPrintOut() {
+        return true;
+    }
+
+    @Override
+    public Collection<String> addJVMOptions(BenchmarkParams params) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public Collection<String> addJVMInvokeOptions(BenchmarkParams params) {
+        return Collections.emptyList();
+    }
+
+    @Override
+    public void beforeTrial(BenchmarkParams benchmarkParams) {
+        start = System.nanoTime();
+        try {
+            TimeUnit.MILLISECONDS.sleep(100);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public Collection<? extends Result> afterTrial(BenchmarkParams benchmarkParams, long pid, File stdOut, File stdErr) {
+        stop = System.nanoTime();
+        try {
+            TimeUnit.MILLISECONDS.sleep(100);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        return Arrays.asList(
+                new ProfilerTimestamp(pfx + "start", start),
+                new ProfilerTimestamp(pfx + "stop", stop)
+        );
+    }
+
+    @Override
+    public boolean checkSupport(List<String> msgs) {
+        return true;
+    }
+
+    @Override
+    public String getDescription() {
+        return "Integration Test External Profiler";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/AbstractInternalProfiler.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+import org.openjdk.jmh.infra.BenchmarkParams;
+import org.openjdk.jmh.infra.IterationParams;
+import org.openjdk.jmh.profile.InternalProfiler;
+import org.openjdk.jmh.results.Result;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+public abstract class AbstractInternalProfiler implements InternalProfiler {
+
+    private final String pfx;
+    protected long start, stop;
+
+    protected AbstractInternalProfiler(String pfx) {
+        this.pfx = pfx;
+    }
+
+    @Override
+    public void beforeIteration(BenchmarkParams benchmarkParams, IterationParams iterationParams) {
+        start = System.nanoTime();
+        try {
+            TimeUnit.MILLISECONDS.sleep(100);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public Collection<? extends Result> afterIteration(BenchmarkParams benchmarkParams, IterationParams iterationParams) {
+        stop = System.nanoTime();
+        try {
+            TimeUnit.MILLISECONDS.sleep(100);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+        return Arrays.asList(
+                new ProfilerTimestamp(pfx + "start", start),
+                new ProfilerTimestamp(pfx + "stop", stop)
+        );
+    }
+
+    @Override
+    public boolean checkSupport(List<String> msgs) {
+        return true;
+    }
+
+    @Override
+    public String getDescription() {
+        return "Integration Test Internal Profiler";
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ExternalProfiler1.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+public class ExternalProfiler1 extends AbstractExternalProfiler {
+    public ExternalProfiler1() {
+        super("prof1");
+    }
+
+    @Override
+    public String label() {
+        return "itexternal1";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ExternalProfiler2.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+public class ExternalProfiler2 extends AbstractExternalProfiler {
+    public ExternalProfiler2() {
+        super("prof2");
+    }
+
+    @Override
+    public String label() {
+        return "itexternal2";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ExternalProfiler3.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+public class ExternalProfiler3 extends AbstractExternalProfiler {
+    public ExternalProfiler3() {
+        super("prof3");
+    }
+
+    @Override
+    public String label() {
+        return "itexternal3";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/InternalProfiler1.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+public class InternalProfiler1 extends AbstractInternalProfiler {
+    public InternalProfiler1() {
+        super("prof1");
+    }
+
+    @Override
+    public String label() {
+        return "itinternal1";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/InternalProfiler2.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+public class InternalProfiler2 extends AbstractInternalProfiler {
+    public InternalProfiler2() {
+        super("prof2");
+    }
+
+    @Override
+    public String label() {
+        return "itinternal2";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/InternalProfiler3.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+public class InternalProfiler3 extends AbstractInternalProfiler {
+    public InternalProfiler3() {
+        super("prof3");
+    }
+
+    @Override
+    public String label() {
+        return "itinternal3";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ProfilerOrderTest.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Fork;
+import org.openjdk.jmh.annotations.Measurement;
+import org.openjdk.jmh.annotations.Warmup;
+import org.openjdk.jmh.it.Fixtures;
+import org.openjdk.jmh.results.Result;
+import org.openjdk.jmh.results.RunResult;
+import org.openjdk.jmh.runner.Runner;
+import org.openjdk.jmh.runner.RunnerException;
+import org.openjdk.jmh.runner.options.CommandLineOptionException;
+import org.openjdk.jmh.runner.options.CommandLineOptions;
+import org.openjdk.jmh.runner.options.Options;
+import org.openjdk.jmh.runner.options.OptionsBuilder;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+public class ProfilerOrderTest {
+
+    @Benchmark
+    @Warmup(iterations = 0)
+    @Measurement(iterations = 1, time = 1, timeUnit = TimeUnit.MILLISECONDS)
+    @Fork(1)
+    public void bench() {
+      // intentionally left blank
+    }
+
+    @Test
+    public void testInternal_API() throws RunnerException {
+        Options opts = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass()))
+                .addProfiler(InternalProfiler1.class)
+                .addProfiler(InternalProfiler2.class)
+                .addProfiler(InternalProfiler3.class)
+                .build();
+
+        runWith(opts);
+    }
+
+    @Test
+    public void testInternal_CLI() throws RunnerException, CommandLineOptionException {
+        CommandLineOptions opts = new CommandLineOptions(
+                Fixtures.getTestMask(this.getClass()),
+                "-prof", "itinternal1,itinternal2,itinternal3");
+        runWith(opts);
+    }
+
+    @Test
+    public void testExternal_API() throws RunnerException {
+        Options opts = new OptionsBuilder()
+                .include(Fixtures.getTestMask(this.getClass()))
+                .addProfiler(ExternalProfiler1.class)
+                .addProfiler(ExternalProfiler2.class)
+                .addProfiler(ExternalProfiler3.class)
+                .build();
+
+        runWith(opts);
+    }
+
+    @Test
+    public void testExternal_CLI() throws RunnerException, CommandLineOptionException {
+        CommandLineOptions opts = new CommandLineOptions(
+                Fixtures.getTestMask(this.getClass()),
+                "-prof", "itexternal1,itexternal2,itexternal3");
+        runWith(opts);
+    }
+
+    private void runWith(Options opts) throws RunnerException {Collection<RunResult> results = new Runner(opts).run();
+        for (RunResult r : results) {
+            Map<String, Result> sec = r.getSecondaryResults();
+            double prof1start = sec.get("prof1start").getScore();
+            double prof2start = sec.get("prof2start").getScore();
+            double prof3start = sec.get("prof3start").getScore();
+
+            double prof1stop = sec.get("prof1stop").getScore();
+            double prof2stop = sec.get("prof2stop").getScore();
+            double prof3stop = sec.get("prof3stop").getScore();
+
+            Assert.assertTrue("start(1) < start(2)", prof1start < prof2start);
+            Assert.assertTrue("start(2) < start(3)", prof2start < prof3start);
+
+            Assert.assertTrue("stop(3) < stop(2)", prof3stop < prof2stop);
+            Assert.assertTrue("stop(2) < stop(1)", prof2stop < prof1stop);
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jmh-core-it/src/test/java/org/openjdk/jmh/it/profilers/order/ProfilerTimestamp.java	Wed Feb 18 21:08:07 2015 +0300
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.jmh.it.profilers.order;
+
+import org.openjdk.jmh.results.AggregationPolicy;
+import org.openjdk.jmh.results.Aggregator;
+import org.openjdk.jmh.results.Result;
+import org.openjdk.jmh.results.ResultRole;
+
+import java.util.Collection;
+
+public class ProfilerTimestamp extends Result<ProfilerTimestamp> {
+
+    public ProfilerTimestamp(String label, double ts) {
+        super(ResultRole.SECONDARY, label, of(ts), "N/A", AggregationPolicy.MAX);
+    }
+
+    @Override
+    protected Aggregator<ProfilerTimestamp> getThreadAggregator() {
+        return new LogAggregator();
+    }
+
+    @Override
+    protected Aggregator<ProfilerTimestamp> getIterationAggregator() {
+        return new LogAggregator();
+    }
+
+    public static class LogAggregator implements Aggregator<ProfilerTimestamp> {
+        @Override
+        public ProfilerTimestamp aggregate(Collection<ProfilerTimestamp> results) {
+            String label = null;
+            double d = Double.MIN_VALUE;
+            for (ProfilerTimestamp r : results) {
+                label = r.label;
+                d = Math.max(d, r.getScore());
+            }
+            return new ProfilerTimestamp(label, d);
+        }
+    }
+
+}
--- a/jmh-core-it/src/test/resources/META-INF/services/org.openjdk.jmh.profile.Profiler	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core-it/src/test/resources/META-INF/services/org.openjdk.jmh.profile.Profiler	Wed Feb 18 21:08:07 2015 +0300
@@ -1,2 +1,8 @@
 org.openjdk.jmh.it.profilers.ItInternalProfiler
-org.openjdk.jmh.it.profilers.ItExternalProfiler
\ No newline at end of file
+org.openjdk.jmh.it.profilers.ItExternalProfiler
+org.openjdk.jmh.it.profilers.order.InternalProfiler1
+org.openjdk.jmh.it.profilers.order.InternalProfiler2
+org.openjdk.jmh.it.profilers.order.InternalProfiler3
+org.openjdk.jmh.it.profilers.order.ExternalProfiler1
+org.openjdk.jmh.it.profilers.order.ExternalProfiler2
+org.openjdk.jmh.it.profilers.order.ExternalProfiler3
\ No newline at end of file
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseBenchmarkHandler.java	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/BaseBenchmarkHandler.java	Wed Feb 18 21:08:07 2015 +0300
@@ -38,6 +38,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -59,10 +60,14 @@
 
     protected final OutputFormat out;
 
-    private final List<InternalProfiler> registeredProfilers;
+    private final List<InternalProfiler> profilers;
+    private final List<InternalProfiler> profilersRev;
 
     public BaseBenchmarkHandler(OutputFormat out, final Class<?> clazz, Options options, BenchmarkParams executionParams) {
-        this.registeredProfilers = createProfilers(options);
+        this.profilers = createProfilers(options);
+        this.profilersRev = new ArrayList<InternalProfiler>(profilers);
+        Collections.reverse(profilersRev);
+
         this.instances = new ThreadLocal<Object>() {
             @Override
             protected Object initialValue() {
@@ -204,22 +209,22 @@
         }
     }
 
-    protected void stopProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams, IterationResult iterationResults) {
-        // stop profilers
-        for (InternalProfiler prof : registeredProfilers) {
+    protected void startProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams) {
+        // start profilers
+        for (InternalProfiler prof : profilers) {
             try {
-                iterationResults.addResults(prof.afterIteration(benchmarkParams, iterationParams));
+                prof.beforeIteration(benchmarkParams, iterationParams);
             } catch (Throwable ex) {
                 throw new BenchmarkException(ex);
             }
         }
     }
 
-    protected void startProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams) {
-        // start profilers
-        for (InternalProfiler prof : registeredProfilers) {
+    protected void stopProfilers(BenchmarkParams benchmarkParams, IterationParams iterationParams, IterationResult iterationResults) {
+        // stop profilers
+        for (InternalProfiler prof : profilersRev) {
             try {
-                prof.beforeIteration(benchmarkParams, iterationParams);
+                iterationResults.addResults(prof.afterIteration(benchmarkParams, iterationParams));
             } catch (Throwable ex) {
                 throw new BenchmarkException(ex);
             }
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/Runner.java	Wed Feb 18 21:08:07 2015 +0300
@@ -592,6 +592,9 @@
                 printErr &= prof.allowPrintErr();
             }
 
+            List<ExternalProfiler> profilersRev = new ArrayList<ExternalProfiler>(profilers);
+            Collections.reverse(profilersRev);
+
             boolean forcePrint = options.verbosity().orElse(Defaults.VERBOSITY).equalsOrHigherThan(VerboseMode.EXTRA);
             printOut = forcePrint || printOut;
             printErr = forcePrint || printErr;
@@ -656,9 +659,9 @@
 
                     BenchmarkResult br = new BenchmarkResult(result);
 
-                    if (!profilers.isEmpty()) {
+                    if (!profilersRev.isEmpty()) {
                         out.print("# Processing profiler results: ");
-                        for (ExternalProfiler profiler : profilers) {
+                        for (ExternalProfiler profiler : profilersRev) {
                             out.print(profiler.label() + " ");
                             for (Result profR : profiler.afterTrial(params, pid, stdOut, stdErr)) {
                                 br.addBenchmarkResult(profR);
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/CommandLineOptions.java	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/CommandLineOptions.java	Wed Feb 18 21:08:07 2015 +0300
@@ -42,9 +42,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 /**
@@ -67,7 +65,7 @@
     private final Optional<Boolean> gcEachIteration;
     private final Optional<VerboseMode> verbose;
     private final Optional<Boolean> failOnError;
-    private final Set<Class<? extends Profiler>> profilers = new LinkedHashSet<Class<? extends Profiler>>();
+    private final List<Class<? extends Profiler>> profilers = new ArrayList<Class<? extends Profiler>>();
     private final Optional<TimeUnit> timeUnit;
     private final Optional<Integer> opsPerInvocation;
     private final List<String> regexps = new ArrayList<String>();
@@ -672,7 +670,7 @@
     }
 
     @Override
-    public Set<Class<? extends Profiler>> getProfilers() {
+    public List<Class<? extends Profiler>> getProfilers() {
         return profilers;
     }
 
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/Options.java	Wed Feb 18 21:08:07 2015 +0300
@@ -74,9 +74,10 @@
 
     /**
      * Profilers to use for the run.
+     * Profilers will start in the order specified by collection, and will stop in the reverse order.
      * @return profilers to use; empty collection if no profilers are required
      */
-    Collection<Class<? extends Profiler>> getProfilers();
+    List<Class<? extends Profiler>> getProfilers();
 
     /**
      * How verbose should we be?
--- a/jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java	Fri Feb 13 17:44:02 2015 +0300
+++ b/jmh-core/src/main/java/org/openjdk/jmh/runner/options/OptionsBuilder.java	Wed Feb 18 21:08:07 2015 +0300
@@ -36,9 +36,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumSet;
-import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 public class OptionsBuilder implements Options, ChainedOptionsBuilder {
@@ -181,7 +179,7 @@
 
     // ---------------------------------------------------------------------------
 
-    private Set<Class<? extends Profiler>> profilers = new LinkedHashSet<Class<? extends Profiler>>();
+    private List<Class<? extends Profiler>> profilers = new ArrayList<Class<? extends Profiler>>();
 
     @Override
     public ChainedOptionsBuilder addProfiler(Class<? extends Profiler> prof) {
@@ -190,7 +188,7 @@
     }
 
     @Override
-    public Set<Class<? extends Profiler>> getProfilers() {
+    public List<Class<? extends Profiler>> getProfilers() {
         if (otherOptions != null) {
             profilers.addAll(otherOptions.getProfilers());
         }