001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2016 ForgeRock AS.
015 */
016
017package org.forgerock.http.handler;
018
019import java.util.concurrent.TimeUnit;
020
021import org.forgerock.http.Filter;
022import org.forgerock.http.Handler;
023import org.forgerock.http.protocol.Request;
024import org.forgerock.http.protocol.Response;
025import org.forgerock.http.protocol.Status;
026import org.forgerock.services.context.Context;
027import org.forgerock.services.context.RootContext;
028import org.forgerock.util.promise.NeverThrowsException;
029import org.forgerock.util.promise.Promise;
030import org.openjdk.jmh.annotations.Benchmark;
031import org.openjdk.jmh.annotations.BenchmarkMode;
032import org.openjdk.jmh.annotations.Fork;
033import org.openjdk.jmh.annotations.Measurement;
034import org.openjdk.jmh.annotations.Mode;
035import org.openjdk.jmh.annotations.OutputTimeUnit;
036import org.openjdk.jmh.annotations.Scope;
037import org.openjdk.jmh.annotations.State;
038import org.openjdk.jmh.annotations.Threads;
039import org.openjdk.jmh.annotations.Warmup;
040import org.openjdk.jmh.runner.Runner;
041import org.openjdk.jmh.runner.RunnerException;
042import org.openjdk.jmh.runner.options.Options;
043import org.openjdk.jmh.runner.options.OptionsBuilder;
044
045@State(Scope.Thread)
046@BenchmarkMode(Mode.Throughput)
047@OutputTimeUnit(TimeUnit.MILLISECONDS)
048@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
049@Measurement(iterations = 1, time = 2, timeUnit = TimeUnit.MINUTES)
050@Fork(1)
051@Threads(50)
052public class HandlersChainOfBenchmark {
053
054    private Promise<Response, NeverThrowsException> OK_RESPONSE =
055            Response.newResponsePromise(new Response(Status.OK));
056
057    private Handler OK_HANDLER = new Handler() {
058        @Override
059        public Promise<Response, NeverThrowsException> handle(final Context context, final Request request) {
060            return OK_RESPONSE;
061        }
062    };
063
064    // use a non-final, non-static variable in order to prevent JVM optimization
065    private double x = Math.PI;
066
067    private final Filter PASS_THROUGH = new Filter() {
068        @Override
069        public Promise<Response, NeverThrowsException> filter(final Context context,
070                final Request request,
071                final Handler next) {
072            // Prevent constant folding by the JVM
073            if (x == Double.MAX_VALUE) { return null; }
074            return next.handle(context, request);
075        }
076    };
077    private Request REQUEST = new Request();
078    private RootContext CONTEXT = new RootContext();
079
080    private Handler original = Handlers.chainOf(OK_HANDLER, PASS_THROUGH, PASS_THROUGH, PASS_THROUGH, PASS_THROUGH, PASS_THROUGH);
081
082    @Benchmark
083    public Promise<Response, NeverThrowsException> testOriginalChainOf() {
084        return original.handle(CONTEXT, REQUEST);
085    }
086
087    public static void main(String[] args) throws RunnerException {
088        Options opt = new OptionsBuilder()
089                .include(HandlersChainOfBenchmark.class.getSimpleName())
090                .build();
091
092        new Runner(opt).run();
093    }
094
095}