diff options
author | Peter Hartmann <phartmann@blackberry.com> | 2013-05-03 15:57:40 +0200 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-06-03 23:16:08 +0200 |
commit | 1c901913c0af79b2bbde1b9da71f5267cb4fc76a (patch) | |
tree | e83c7e1c10cc6262931f1d03b9deb06cf1585bae /tests/benchmarks/network/access/qnetworkreply | |
parent | 15da0a5af20fe6771bcb94ef8d46edbd5c8fb64c (diff) |
QNetworkAccessManager: add public methods to pre-TCP/pre-SSL-connect
If an app knows it needs to connect to a host beforehand, it can "warm up" the
connection cache by making DNS lookup, TCP (and if needed SSL) handshake before
the actual HTTP request is sent. When the HTTP request is made, it will be
considerably faster when there is already a working connection.
Here are some typical results from the benchmark:
* Linux desktop with Ethernet:
"http://www.google.com" full request: 279 ms, pre-connect request: 61 ms,
difference: 218 ms
"https://www.google.com" full request: 344 ms, pre-connect request: 60 ms,
difference: 284 ms
* mobile device (BlackBerry 10) with Wifi:
"https://www.google.com" full request: 898 ms, pre-connect request: 159 ms,
difference: 739 ms
"http://www.google.com" full request: 707 ms, pre-connect request: 200 ms,
difference: 507 ms
Task-number: QTBUG-30771
Change-Id: I3566b7f08216ab93a39e2024ae7d1ceb7ae21891
Reviewed-by: Jonas Gastal <gastal@intel.com>
Reviewed-by: Richard J. Moore <rich@kde.org>
Diffstat (limited to 'tests/benchmarks/network/access/qnetworkreply')
-rw-r--r-- | tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro | 2 | ||||
-rw-r--r-- | tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp | 109 |
2 files changed, 110 insertions, 1 deletions
diff --git a/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro b/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro index 7031b83210..92d20f50d0 100644 --- a/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro +++ b/tests/benchmarks/network/access/qnetworkreply/qnetworkreply.pro @@ -2,7 +2,7 @@ TEMPLATE = app TARGET = tst_bench_qnetworkreply QT -= gui -QT += network testlib +QT += core-private network network-private testlib CONFIG += release diff --git a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp index f62ce6bf5c..860bd3cf4d 100644 --- a/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/benchmarks/network/access/qnetworkreply/tst_qnetworkreply.cpp @@ -50,6 +50,9 @@ #include <QtNetwork/qtcpserver.h> #include "../../../../auto/network-settings.h" +#ifdef QT_BUILD_INTERNAL +#include <QtNetwork/private/qhostinfo_p.h> +#endif Q_DECLARE_METATYPE(QSharedPointer<char>) @@ -460,6 +463,7 @@ private slots: #ifndef QT_NO_SSL void echoPerformance_data(); void echoPerformance(); + void preConnectEncrypted(); #endif void downloadPerformance(); @@ -472,9 +476,12 @@ private slots: void httpDownloadPerformanceDownloadBuffer(); void httpsRequestChain(); void httpsUpload(); + void preConnect(); private: void runHttpsUploadRequest(const QByteArray &data, const QNetworkRequest &request); + QPair<QNetworkReply *, qint64> runGetRequest(QNetworkAccessManager *manager, + const QNetworkRequest &request); }; void tst_qnetworkreply::initTestCase() @@ -495,6 +502,19 @@ void tst_qnetworkreply::httpLatency() } } +QPair<QNetworkReply *, qint64> tst_qnetworkreply::runGetRequest( + QNetworkAccessManager *manager, const QNetworkRequest &request) +{ + QElapsedTimer timer; + timer.start(); + QNetworkReply *reply = manager->get(request); + connect(reply, SIGNAL(sslErrors(QList<QSslError>)), reply, SLOT(ignoreSslErrors())); + connect(reply, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + QTestEventLoop::instance().enterLoop(20); + qint64 elapsed = timer.elapsed(); + return qMakePair(reply, elapsed); +} + #ifndef QT_NO_SSL void tst_qnetworkreply::echoPerformance_data() { @@ -527,6 +547,51 @@ void tst_qnetworkreply::echoPerformance() delete reply; } } + +void tst_qnetworkreply::preConnectEncrypted() +{ + QString hostName = QLatin1String("www.google.com"); + + QNetworkAccessManager manager; + QNetworkRequest request(QUrl("https://" + hostName)); + + // make sure we have a full request including + // DNS lookup, TCP and SSL handshakes +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + + // first, benchmark a normal request + QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request); + QNetworkReply *normalReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(normalReply->error() == QNetworkReply::NoError); + qint64 normalElapsed = normalResult.second; + + // clear all caches again +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + manager.clearAccessCache(); + + // now try to make the connection beforehand + manager.connectToHostEncrypted(hostName); + QTestEventLoop::instance().enterLoop(2); + + // now make another request and hopefully use the existing connection + QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request); + QNetworkReply *preConnectReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(preConnectReply->error() == QNetworkReply::NoError); + qint64 preConnectElapsed = preConnectResult.second; + qDebug() << request.url().toString() << "full request:" << normalElapsed + << "ms, pre-connect request:" << preConnectElapsed << "ms, difference:" + << (normalElapsed - preConnectElapsed) << "ms"; +} #endif void tst_qnetworkreply::downloadPerformance() @@ -852,6 +917,50 @@ void tst_qnetworkreply::httpsUpload() } } +void tst_qnetworkreply::preConnect() +{ + QString hostName = QLatin1String("www.google.com"); + + QNetworkAccessManager manager; + QNetworkRequest request(QUrl("http://" + hostName)); + + // make sure we have a full request including + // DNS lookup and TCP handshake +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + + // first, benchmark a normal request + QPair<QNetworkReply *, qint64> normalResult = runGetRequest(&manager, request); + QNetworkReply *normalReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(normalReply->error() == QNetworkReply::NoError); + qint64 normalElapsed = normalResult.second; + + // clear all caches again +#ifdef QT_BUILD_INTERNAL + qt_qhostinfo_clear_cache(); +#else + qWarning("no internal build, could not clear DNS cache. Results may not be representative."); +#endif + manager.clearAccessCache(); + + // now try to make the connection beforehand + manager.connectToHost(hostName); + QTestEventLoop::instance().enterLoop(2); + + // now make another request and hopefully use the existing connection + QPair<QNetworkReply *, qint64> preConnectResult = runGetRequest(&manager, request); + QNetworkReply *preConnectReply = normalResult.first; + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(preConnectReply->error() == QNetworkReply::NoError); + qint64 preConnectElapsed = preConnectResult.second; + qDebug() << request.url().toString() << "full request:" << normalElapsed + << "ms, pre-connect request:" << preConnectElapsed << "ms, difference:" + << (normalElapsed - preConnectElapsed) << "ms"; +} QTEST_MAIN(tst_qnetworkreply) |