Index: net/tools/fetch/fetch_client.cc |
=================================================================== |
--- net/tools/fetch/fetch_client.cc (revision 0) |
+++ net/tools/fetch/fetch_client.cc (revision 0) |
@@ -0,0 +1,185 @@ |
+// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "base/at_exit.h" |
+#include "base/command_line.h" |
+#include "base/message_loop.h" |
+#include "base/singleton.h" |
+#include "base/stats_counters.h" |
+#include "base/string_util.h" |
+#include "net/base/completion_callback.h" |
+#include "net/base/io_buffer.h" |
+#include "net/base/net_errors.h" |
+#include "net/http/http_cache.h" |
+#include "net/http/http_network_layer.h" |
+#include "net/http/http_request_info.h" |
+#include "net/http/http_transaction.h" |
+#include "net/proxy/proxy_service.h" |
+ |
+void usage(const char* program_name) { |
+ printf("usage: %s --url=<url> [--n=<clients>] [--stats] [--use_cache]\n", |
+ program_name); |
+ exit(1); |
+} |
+ |
+// Test Driver |
+class Driver { |
+ public: |
+ Driver() |
+ : clients_(0) {} |
+ |
+ void ClientStarted() { clients_++; } |
+ void ClientStopped() { |
+ if (!--clients_) { |
+ MessageLoop::current()->Quit(); |
+ } |
+ } |
+ |
+ private: |
+ int clients_; |
+}; |
+ |
+// A network client |
+class Client { |
+ public: |
+ Client(net::HttpTransactionFactory* factory, const std::string& url) : |
+ url_(url), |
+ transaction_(factory->CreateTransaction()), |
+ buffer_(new net::IOBuffer(kBufferSize)), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ connect_callback_(this, &Client::OnConnectComplete)), |
+ ALLOW_THIS_IN_INITIALIZER_LIST( |
+ read_callback_(this, &Client::OnReadComplete)) { |
+ buffer_->AddRef(); |
+ driver_->ClientStarted(); |
+ request_info_.url = url_; |
+ request_info_.method = "GET"; |
+ int state = transaction_->Start(&request_info_, &connect_callback_); |
+ DCHECK(state == net::ERR_IO_PENDING); |
+ }; |
+ |
+ private: |
+ void OnConnectComplete(int result) { |
+ // Do work here. |
+ int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); |
+ if (state == net::ERR_IO_PENDING) |
+ return; // IO has started. |
+ if (state < 0) |
+ return; // ERROR! |
+ OnReadComplete(state); |
+ } |
+ |
+ void OnReadComplete(int result) { |
+ if (result == 0) { |
+ OnRequestComplete(result); |
+ return; |
+ } |
+ |
+ // Deal with received data here. |
+ static StatsCounter bytes_read("FetchClient.bytes_read"); |
+ bytes_read.Add(result); |
+ |
+ // Issue a read for more data. |
+ int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); |
+ if (state == net::ERR_IO_PENDING) |
+ return; // IO has started. |
+ if (state < 0) |
+ return; // ERROR! |
+ OnReadComplete(state); |
+ } |
+ |
+ void OnRequestComplete(int result) { |
+ static StatsCounter requests("FetchClient.requests"); |
+ requests.Increment(); |
+ driver_->ClientStopped(); |
+ printf("."); |
+ } |
+ |
+ static const int kBufferSize = (16 * 1024); |
+ GURL url_; |
+ net::HttpRequestInfo request_info_; |
+ scoped_ptr<net::HttpTransaction> transaction_; |
+ scoped_ptr<net::IOBuffer> buffer_; |
+ net::CompletionCallbackImpl<Client> connect_callback_; |
+ net::CompletionCallbackImpl<Client> read_callback_; |
+ Singleton<Driver> driver_; |
+}; |
+ |
+int main(int argc, char**argv) { |
+ base::AtExitManager exit; |
+ StatsTable table("fetchclient", 50, 1000); |
+ table.set_current(&table); |
+ |
+ CommandLine::Init(0, NULL); |
+ const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
+ std::string url = WideToASCII(parsed_command_line.GetSwitchValue(L"url")); |
+ if (!url.length()) |
+ usage(argv[0]); |
+ int client_limit = 1; |
+ if (parsed_command_line.HasSwitch(L"n")) |
+ StringToInt(WideToASCII(parsed_command_line.GetSwitchValue(L"n")), |
+ &client_limit); |
+ bool use_cache = parsed_command_line.HasSwitch(L"use-cache"); |
+ |
+ // Do work here. |
+ MessageLoop loop; |
+ |
+ scoped_ptr<net::ProxyService> proxy_service(net::ProxyService::CreateNull()); |
+ net::HttpTransactionFactory* factory = NULL; |
+ if (use_cache) |
+ factory = new net::HttpCache(proxy_service.get(), 0); |
+ else |
+ factory = new net::HttpNetworkLayer(proxy_service.get()); |
+ |
+ { |
+ StatsCounterTimer driver_time("FetchClient.total_time"); |
+ StatsScope<StatsCounterTimer> scope(driver_time); |
+ |
+ Client** clients = new Client*[client_limit]; |
+ for (int i = 0; i < client_limit; i++) |
+ clients[i] = new Client(factory, url); |
+ |
+ MessageLoop::current()->Run(); |
+ } |
+ |
+ // Print Statistics here. |
+ int num_clients = table.GetCounterValue("c:FetchClient.requests"); |
+ int test_time = table.GetCounterValue("t:FetchClient.total_time"); |
+ int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read"); |
+ |
+ printf("\n"); |
+ printf("Clients : %d\n", num_clients); |
+ printf("Time : %dms\n", test_time); |
+ printf("Bytes Read : %d\n", bytes_read); |
+ if (test_time > 0) { |
+ const char *units = "bps"; |
+ double bps = static_cast<float>(bytes_read * 8) / |
+ (static_cast<float>(test_time) / 1000.0); |
+ |
+ if (bps > (1024*1024)) { |
+ bps /= (1024*1024); |
+ units = "Mbps"; |
+ } else if (bps > 1024) { |
+ bps /= 1024; |
+ units = "Kbps"; |
+ } |
+ printf("Bandwidth : %.2f%s\n", bps, units); |
+ } |
+ |
+ if (parsed_command_line.HasSwitch(L"stats")) { |
+ // Dump the stats table. |
+ printf("<stats>\n"); |
+ int counter_max = table.GetMaxCounters(); |
+ for (int index=0; index < counter_max; index++) { |
+ std::string name(table.GetRowName(index)); |
+ if (name.length() > 0) { |
+ int value = table.GetRowValue(index); |
+ printf("%s:\t%d\n", name.c_str(), value); |
+ |
+ } |
+ } |
+ printf("</stats>\n"); |
+ } |
+ return 0; |
+} |