fetch_client.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "build/build_config.h" 6 7#include "base/at_exit.h" 8#include "base/command_line.h" 9#include "base/message_loop.h" 10#include "base/singleton.h" 11#include "base/stats_counters.h" 12#include "base/string_util.h" 13#include "net/base/completion_callback.h" 14#include "net/base/host_resolver.h" 15#include "net/base/io_buffer.h" 16#include "net/base/net_errors.h" 17#include "net/base/ssl_config_service.h" 18#include "net/http/http_auth_handler_factory.h" 19#include "net/http/http_cache.h" 20#include "net/http/http_network_layer.h" 21#include "net/http/http_request_info.h" 22#include "net/http/http_transaction.h" 23#include "net/proxy/proxy_service.h" 24#include "net/socket/client_socket_factory.h" 25 26void usage(const char* program_name) { 27 printf("usage: %s --url=<url> [--n=<clients>] [--stats] [--use_cache]\n", 28 program_name); 29 exit(1); 30} 31 32// Test Driver 33class Driver { 34 public: 35 Driver() 36 : clients_(0) {} 37 38 void ClientStarted() { clients_++; } 39 void ClientStopped() { 40 if (!--clients_) { 41 MessageLoop::current()->Quit(); 42 } 43 } 44 45 private: 46 int clients_; 47}; 48 49// A network client 50class Client { 51 public: 52 Client(net::HttpTransactionFactory* factory, const std::string& url) : 53 url_(url), 54 buffer_(new net::IOBuffer(kBufferSize)), 55 ALLOW_THIS_IN_INITIALIZER_LIST( 56 connect_callback_(this, &Client::OnConnectComplete)), 57 ALLOW_THIS_IN_INITIALIZER_LIST( 58 read_callback_(this, &Client::OnReadComplete)) { 59 int rv = factory->CreateTransaction(&transaction_); 60 DCHECK_EQ(net::OK, rv); 61 buffer_->AddRef(); 62 driver_->ClientStarted(); 63 request_info_.url = url_; 64 request_info_.method = "GET"; 65 int state = transaction_->Start( 66 &request_info_, &connect_callback_, net::BoundNetLog()); 67 DCHECK(state == net::ERR_IO_PENDING); 68 }; 69 70 private: 71 void OnConnectComplete(int result) { 72 // Do work here. 73 int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); 74 if (state == net::ERR_IO_PENDING) 75 return; // IO has started. 76 if (state < 0) 77 return; // ERROR! 78 OnReadComplete(state); 79 } 80 81 void OnReadComplete(int result) { 82 if (result == 0) { 83 OnRequestComplete(result); 84 return; 85 } 86 87 // Deal with received data here. 88 static StatsCounter bytes_read("FetchClient.bytes_read"); 89 bytes_read.Add(result); 90 91 // Issue a read for more data. 92 int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_); 93 if (state == net::ERR_IO_PENDING) 94 return; // IO has started. 95 if (state < 0) 96 return; // ERROR! 97 OnReadComplete(state); 98 } 99 100 void OnRequestComplete(int result) { 101 static StatsCounter requests("FetchClient.requests"); 102 requests.Increment(); 103 driver_->ClientStopped(); 104 printf("."); 105 } 106 107 static const int kBufferSize = (16 * 1024); 108 GURL url_; 109 net::HttpRequestInfo request_info_; 110 scoped_ptr<net::HttpTransaction> transaction_; 111 scoped_refptr<net::IOBuffer> buffer_; 112 net::CompletionCallbackImpl<Client> connect_callback_; 113 net::CompletionCallbackImpl<Client> read_callback_; 114 Singleton<Driver> driver_; 115}; 116 117int main(int argc, char**argv) { 118 base::AtExitManager exit; 119 StatsTable table("fetchclient", 50, 1000); 120 table.set_current(&table); 121 122 CommandLine::Init(argc, argv); 123 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); 124 std::string url = parsed_command_line.GetSwitchValueASCII("url"); 125 if (!url.length()) 126 usage(argv[0]); 127 int client_limit = 1; 128 if (parsed_command_line.HasSwitch("n")) 129 StringToInt(parsed_command_line.GetSwitchValueASCII("n"), &client_limit); 130 bool use_cache = parsed_command_line.HasSwitch("use-cache"); 131 132 // Do work here. 133 MessageLoop loop(MessageLoop::TYPE_IO); 134 135 scoped_refptr<net::HostResolver> host_resolver( 136 net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism)); 137 138 scoped_refptr<net::ProxyService> proxy_service( 139 net::ProxyService::CreateNull()); 140 scoped_refptr<net::SSLConfigService> ssl_config_service( 141 net::SSLConfigService::CreateSystemSSLConfigService()); 142 net::HttpTransactionFactory* factory = NULL; 143 scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory( 144 net::HttpAuthHandlerFactory::CreateDefault()); 145 if (use_cache) { 146 factory = new net::HttpCache(host_resolver, proxy_service, 147 ssl_config_service, http_auth_handler_factory.get(), NULL, NULL, 148 net::HttpCache::DefaultBackend::InMemory(0)); 149 } else { 150 factory = new net::HttpNetworkLayer( 151 net::ClientSocketFactory::GetDefaultFactory(), host_resolver, 152 proxy_service, ssl_config_service, http_auth_handler_factory.get(), 153 NULL, NULL); 154 } 155 156 { 157 StatsCounterTimer driver_time("FetchClient.total_time"); 158 StatsScope<StatsCounterTimer> scope(driver_time); 159 160 Client** clients = new Client*[client_limit]; 161 for (int i = 0; i < client_limit; i++) 162 clients[i] = new Client(factory, url); 163 164 MessageLoop::current()->Run(); 165 } 166 167 // Print Statistics here. 168 int num_clients = table.GetCounterValue("c:FetchClient.requests"); 169 int test_time = table.GetCounterValue("t:FetchClient.total_time"); 170 int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read"); 171 172 printf("\n"); 173 printf("Clients : %d\n", num_clients); 174 printf("Time : %dms\n", test_time); 175 printf("Bytes Read : %d\n", bytes_read); 176 if (test_time > 0) { 177 const char *units = "bps"; 178 double bps = static_cast<float>(bytes_read * 8) / 179 (static_cast<float>(test_time) / 1000.0); 180 181 if (bps > (1024*1024)) { 182 bps /= (1024*1024); 183 units = "Mbps"; 184 } else if (bps > 1024) { 185 bps /= 1024; 186 units = "Kbps"; 187 } 188 printf("Bandwidth : %.2f%s\n", bps, units); 189 } 190 191 if (parsed_command_line.HasSwitch("stats")) { 192 // Dump the stats table. 193 printf("<stats>\n"); 194 int counter_max = table.GetMaxCounters(); 195 for (int index=0; index < counter_max; index++) { 196 std::string name(table.GetRowName(index)); 197 if (name.length() > 0) { 198 int value = table.GetRowValue(index); 199 printf("%s:\t%d\n", name.c_str(), value); 200 } 201 } 202 printf("</stats>\n"); 203 } 204 return 0; 205} 206