From 7c21992db56623b9d77f682d7e4edea078c3985b Mon Sep 17 00:00:00 2001 From: jwilson Date: Sat, 1 Feb 2014 00:52:44 -0500 Subject: [PATCH] New benchmark targets for Apache HTTP Client and URLConnection. OkHttp [HTTP_11] bodyByteCount=1048576 headerCount=20 threadCount=10 Requests per second: 690.9 UrlConnection [HTTP_11] bodyByteCount=1048576 headerCount=20 threadCount=10 Requests per second: 671.3 ApacheHttpClient [HTTP_11] bodyByteCount=1048576 headerCount=20 threadCount=10 Requests per second: 317.4 --- benchmarks/pom.xml | 4 ++ .../benchmarks/ApacheHttpClientRequest.java | 64 ++++++++++++++++++ .../squareup/okhttp/benchmarks/Benchmark.java | 56 +++++++++++++--- ...nectionRequest.java => OkHttpRequest.java} | 12 ++-- .../benchmarks/UrlConnectionRequest.java | 66 +++++++++++++++++++ 5 files changed, 190 insertions(+), 12 deletions(-) create mode 100644 benchmarks/src/main/java/com/squareup/okhttp/benchmarks/ApacheHttpClientRequest.java rename benchmarks/src/main/java/com/squareup/okhttp/benchmarks/{HttpURLConnectionRequest.java => OkHttpRequest.java} (84%) create mode 100644 benchmarks/src/main/java/com/squareup/okhttp/benchmarks/UrlConnectionRequest.java diff --git a/benchmarks/pom.xml b/benchmarks/pom.xml index e606d7f84d12..7b8ce5278531 100644 --- a/benchmarks/pom.xml +++ b/benchmarks/pom.xml @@ -32,5 +32,9 @@ npn-boot provided + + org.apache.httpcomponents + httpclient + diff --git a/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/ApacheHttpClientRequest.java b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/ApacheHttpClientRequest.java new file mode 100644 index 000000000000..a507738dfe2e --- /dev/null +++ b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/ApacheHttpClientRequest.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2014 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.benchmarks; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; + +class ApacheHttpClientRequest implements Runnable { + private static final boolean VERBOSE = false; + private final HttpClient client; + private final String url; + + public ApacheHttpClientRequest(String url, HttpClient client) { + this.client = client; + this.url = url; + } + + public void run() { + byte[] buffer = new byte[1024]; + long start = System.nanoTime(); + try { + HttpResponse response = client.execute(new HttpGet(url)); + InputStream in = response.getEntity().getContent(); + Header contentEncoding = response.getFirstHeader("Content-Encoding"); + if (contentEncoding != null && contentEncoding.getValue().equals("gzip")) { + in = new GZIPInputStream(in); + } + + // Consume the response body. + int total = 0; + for (int count; (count = in.read(buffer)) != -1; ) { + total += count; + } + in.close(); + long finish = System.nanoTime(); + + if (VERBOSE) { + System.out.println(String.format("Transferred % 8d bytes in %4d ms", + total, TimeUnit.NANOSECONDS.toMillis(finish - start))); + } + } catch (IOException e) { + System.out.println("Failed: " + e); + } + } +} diff --git a/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/Benchmark.java b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/Benchmark.java index 7637a3ba2482..3b0887af8a8d 100644 --- a/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/Benchmark.java +++ b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/Benchmark.java @@ -18,6 +18,7 @@ import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Protocol; import com.squareup.okhttp.internal.SslContextBuilder; +import com.squareup.okhttp.internal.http.HttpsURLConnectionImpl; import com.squareup.okhttp.mockwebserver.Dispatcher; import com.squareup.okhttp.mockwebserver.MockResponse; import com.squareup.okhttp.mockwebserver.MockWebServer; @@ -25,7 +26,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStream; -import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -40,6 +40,11 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocketFactory; +import org.apache.http.client.HttpClient; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.conn.PoolingClientConnectionManager; /** * This benchmark is fake, but may be useful for certain relative comparisons. @@ -51,8 +56,7 @@ public class Benchmark { private final Random random = new Random(0); /** Which client to run.*/ - // TODO: implement additional candidates for other HTTP client libraries. - Candidate candidate = new OkHttp(); + Candidate candidate = new UrlConnection(); // new OkHttp(); // new ApacheHttpClient(); /** How many concurrent threads to execute. */ int threadCount = 10; @@ -62,10 +66,10 @@ public class Benchmark { boolean tls = false; /** True to use gzip content-encoding for the response body. */ - boolean gzip = true; + boolean gzip = false; /** Don't combine chunked with SPDY_3 or HTTP_2; that's not allowed. */ - boolean chunked = true; + boolean chunked = false; /** The size of the HTTP response body, in uncompressed bytes. */ int bodyByteCount = 1024 * 1024; @@ -216,8 +220,6 @@ class OkHttp implements Candidate { client = new OkHttpClient(); client.setProtocols(protocols); - URL.setURLStreamHandlerFactory(client); - if (tls) { SSLContext sslContext = SslContextBuilder.localhost(); SSLSocketFactory socketFactory = sslContext.getSocketFactory(); @@ -232,7 +234,45 @@ class OkHttp implements Candidate { } @Override public Runnable request(String url) { - return new HttpURLConnectionRequest(url); + return new OkHttpRequest(client, url); + } + } + + class UrlConnection implements Candidate { + @Override public void prepare() { + if (tls) { + SSLContext sslContext = SslContextBuilder.localhost(); + SSLSocketFactory socketFactory = sslContext.getSocketFactory(); + HostnameVerifier hostnameVerifier = new HostnameVerifier() { + @Override public boolean verify(String s, SSLSession session) { + return true; + } + }; + HttpsURLConnectionImpl.setDefaultHostnameVerifier(hostnameVerifier); + HttpsURLConnectionImpl.setDefaultSSLSocketFactory(socketFactory); + } + } + + @Override public Runnable request(String url) { + return new UrlConnectionRequest(url); + } + } + + class ApacheHttpClient implements Candidate { + private HttpClient client; + + @Override public void prepare() { + ClientConnectionManager connectionManager = new PoolingClientConnectionManager(); + if (tls) { + SSLContext sslContext = SslContextBuilder.localhost(); + connectionManager.getSchemeRegistry().register( + new Scheme("https", 443, new org.apache.http.conn.ssl.SSLSocketFactory(sslContext))); + } + client = new DefaultHttpClient(connectionManager); + } + + @Override public Runnable request(String url) { + return new ApacheHttpClientRequest(url, client); } } } diff --git a/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/HttpURLConnectionRequest.java b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/OkHttpRequest.java similarity index 84% rename from benchmarks/src/main/java/com/squareup/okhttp/benchmarks/HttpURLConnectionRequest.java rename to benchmarks/src/main/java/com/squareup/okhttp/benchmarks/OkHttpRequest.java index b1eb99eceda1..e4ab485627ed 100644 --- a/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/HttpURLConnectionRequest.java +++ b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/OkHttpRequest.java @@ -15,6 +15,7 @@ */ package com.squareup.okhttp.benchmarks; +import com.squareup.okhttp.OkHttpClient; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; @@ -22,12 +23,15 @@ import java.net.URL; import java.util.concurrent.TimeUnit; -public class HttpURLConnectionRequest implements Runnable { +class OkHttpRequest implements Runnable { private static final boolean VERBOSE = false; + + private final OkHttpClient client; private final URL url; - public HttpURLConnectionRequest(String url) { + public OkHttpRequest(OkHttpClient client, String url) { try { + this.client = client; this.url = new URL(url); } catch (MalformedURLException e) { throw new AssertionError(); @@ -38,10 +42,10 @@ public void run() { byte[] buffer = new byte[1024]; long start = System.nanoTime(); try { - HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + HttpURLConnection urlConnection = client.open(url); InputStream in = urlConnection.getInputStream(); - // Discard the response body. + // Consume the response body. int total = 0; for (int count; (count = in.read(buffer)) != -1; ) { total += count; diff --git a/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/UrlConnectionRequest.java b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/UrlConnectionRequest.java new file mode 100644 index 000000000000..ab5c9b43e078 --- /dev/null +++ b/benchmarks/src/main/java/com/squareup/okhttp/benchmarks/UrlConnectionRequest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2014 Square, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.squareup.okhttp.benchmarks; + +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; + +/** Uses the default java.net.HttpURLConnection implementation. */ +class UrlConnectionRequest implements Runnable { + private static final boolean VERBOSE = false; + + private final URL url; + + public UrlConnectionRequest(String url) { + try { + this.url = new URL(url); + } catch (MalformedURLException e) { + throw new AssertionError(); + } + } + + public void run() { + byte[] buffer = new byte[1024]; + long start = System.nanoTime(); + try { + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); + InputStream in = urlConnection.getInputStream(); + if ("gzip".equals(urlConnection.getHeaderField("Content-Encoding"))) { + in = new GZIPInputStream(in); + } + + // Consume the response body. + int total = 0; + for (int count; (count = in.read(buffer)) != -1; ) { + total += count; + } + in.close(); + long finish = System.nanoTime(); + + if (VERBOSE) { + System.out.println(String.format("Transferred % 8d bytes in %4d ms", + total, TimeUnit.NANOSECONDS.toMillis(finish - start))); + } + } catch (IOException e) { + System.out.println("Failed: " + e); + } + } +}