| // |
| // ======================================================================== |
| // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.websocket.server.pathmap; |
| |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.eclipse.jetty.http.PathMap; |
| import org.eclipse.jetty.toolchain.test.AdvancedRunner; |
| import org.eclipse.jetty.toolchain.test.annotation.Stress; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| |
| @RunWith(AdvancedRunner.class) |
| public class PathMappingsBenchmarkTest |
| { |
| public static abstract class AbstractPathMapThread extends Thread |
| { |
| private int iterations; |
| private CyclicBarrier barrier; |
| @SuppressWarnings("unused") |
| private long success; |
| @SuppressWarnings("unused") |
| private long error; |
| |
| public AbstractPathMapThread(int iterations, CyclicBarrier barrier) |
| { |
| this.iterations = iterations; |
| this.barrier = barrier; |
| } |
| |
| public abstract String getMatchedResource(String path); |
| |
| @Override |
| public void run() |
| { |
| int llen = LOOKUPS.length; |
| String path; |
| String expectedResource; |
| String matchedResource; |
| await(barrier); |
| for (int iter = 0; iter < iterations; iter++) |
| { |
| for (int li = 0; li < llen; li++) |
| { |
| path = LOOKUPS[li][0]; |
| expectedResource = LOOKUPS[li][1]; |
| matchedResource = getMatchedResource(path); |
| if (matchedResource.equals(expectedResource)) |
| { |
| success++; |
| } |
| else |
| { |
| error++; |
| } |
| } |
| } |
| await(barrier); |
| } |
| } |
| |
| public static class PathMapMatchThread extends AbstractPathMapThread |
| { |
| private PathMap<String> pathmap; |
| |
| public PathMapMatchThread(PathMap<String> pathmap, int iters, CyclicBarrier barrier) |
| { |
| super(iters,barrier); |
| this.pathmap = pathmap; |
| } |
| |
| @Override |
| public String getMatchedResource(String path) |
| { |
| return pathmap.getMatch(path).getValue(); |
| } |
| } |
| |
| public static class PathMatchThread extends AbstractPathMapThread |
| { |
| private PathMappings<String> pathmap; |
| |
| public PathMatchThread(PathMappings<String> pathmap, int iters, CyclicBarrier barrier) |
| { |
| super(iters,barrier); |
| this.pathmap = pathmap; |
| } |
| |
| @Override |
| public String getMatchedResource(String path) |
| { |
| return pathmap.getMatch(path).getResource(); |
| } |
| } |
| |
| private static final Logger LOG = Log.getLogger(PathMappingsBenchmarkTest.class); |
| private static final String[][] LOOKUPS; |
| private int runs = 20; |
| private int threads = 200; |
| private int iters = 10000; |
| |
| static |
| { |
| LOOKUPS = new String[][] |
| { |
| // @formatter:off |
| { "/abs/path", "path" }, |
| { "/abs/path/longer","longpath" }, |
| { "/abs/path/foo","default" }, |
| { "/main.css","default" }, |
| { "/downloads/script.gz","gzipped" }, |
| { "/downloads/distribution.tar.gz","tarball" }, |
| { "/downloads/readme.txt","default" }, |
| { "/downloads/logs.tgz","default" }, |
| { "/animal/horse/mustang","animals" }, |
| { "/animal/bird/eagle/bald","birds" }, |
| { "/animal/fish/shark/hammerhead","fishes" }, |
| { "/animal/insect/ladybug","animals" }, |
| // @formatter:on |
| }; |
| } |
| |
| private static void await(CyclicBarrier barrier) |
| { |
| try |
| { |
| barrier.await(); |
| } |
| catch (Exception x) |
| { |
| throw new RuntimeException(x); |
| } |
| } |
| |
| @Stress("High CPU") |
| @Test |
| public void testServletPathMap() |
| { |
| // Setup (old) PathMap |
| |
| PathMap<String> p = new PathMap<>(); |
| |
| p.put("/abs/path","path"); |
| p.put("/abs/path/longer","longpath"); |
| p.put("/animal/bird/*","birds"); |
| p.put("/animal/fish/*","fishes"); |
| p.put("/animal/*","animals"); |
| p.put("*.tar.gz","tarball"); |
| p.put("*.gz","gzipped"); |
| p.put("/","default"); |
| |
| final CyclicBarrier barrier = new CyclicBarrier(threads + 1); |
| |
| for (int r = 0; r < runs; r++) |
| { |
| for (int t = 0; t < threads; t++) |
| { |
| PathMapMatchThread thread = new PathMapMatchThread(p,iters,barrier); |
| thread.start(); |
| } |
| await(barrier); |
| long begin = System.nanoTime(); |
| await(barrier); |
| long end = System.nanoTime(); |
| long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); |
| int totalMatches = threads * iters * LOOKUPS.length; |
| LOG.info("jetty-http/PathMap (Servlet only) threads:{}/iters:{}/total-matches:{} => {} ms",threads,iters,totalMatches,elapsed); |
| } |
| } |
| |
| @Stress("High CPU") |
| @Test |
| public void testServletPathMappings() |
| { |
| // Setup (new) PathMappings |
| |
| PathMappings<String> p = new PathMappings<>(); |
| |
| p.put(new ServletPathSpec("/abs/path"),"path"); |
| p.put(new ServletPathSpec("/abs/path/longer"),"longpath"); |
| p.put(new ServletPathSpec("/animal/bird/*"),"birds"); |
| p.put(new ServletPathSpec("/animal/fish/*"),"fishes"); |
| p.put(new ServletPathSpec("/animal/*"),"animals"); |
| p.put(new ServletPathSpec("*.tar.gz"),"tarball"); |
| p.put(new ServletPathSpec("*.gz"),"gzipped"); |
| p.put(new ServletPathSpec("/"),"default"); |
| |
| final CyclicBarrier barrier = new CyclicBarrier(threads + 1); |
| |
| for (int r = 0; r < runs; r++) |
| { |
| for (int t = 0; t < threads; t++) |
| { |
| PathMatchThread thread = new PathMatchThread(p,iters,barrier); |
| thread.start(); |
| } |
| await(barrier); |
| long begin = System.nanoTime(); |
| await(barrier); |
| long end = System.nanoTime(); |
| long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin); |
| int totalMatches = threads * iters * LOOKUPS.length; |
| LOG.info("jetty-websocket/PathMappings (Servlet only) threads:{}/iters:{}/total-matches:{} => {} ms",threads,iters,totalMatches,elapsed); |
| |
| } |
| } |
| } |