1 // Copyright (c) 2012 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.
5 #include "build/build_config.h"
7 #include "base/at_exit.h"
9 #include "base/bind_helpers.h"
10 #include "base/command_line.h"
11 #include "base/lazy_instance.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/stats_counters.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/string_util.h"
16 #include "net/base/completion_callback.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/request_priority.h"
20 #include "net/cert/cert_verifier.h"
21 #include "net/dns/host_resolver.h"
22 #include "net/http/http_auth_handler_factory.h"
23 #include "net/http/http_cache.h"
24 #include "net/http/http_network_layer.h"
25 #include "net/http/http_network_session.h"
26 #include "net/http/http_request_info.h"
27 #include "net/http/http_server_properties_impl.h"
28 #include "net/http/http_transaction.h"
29 #include "net/http/transport_security_state.h"
30 #include "net/proxy/proxy_service.h"
31 #include "net/ssl/ssl_config_service_defaults.h"
33 void usage(const char* program_name
) {
34 printf("usage: %s --url=<url> [--n=<clients>] [--stats] [--use_cache]\n",
45 void ClientStarted() { clients_
++; }
46 void ClientStopped() {
48 base::MessageLoop::current()->Quit();
56 static base::LazyInstance
<Driver
> g_driver
= LAZY_INSTANCE_INITIALIZER
;
61 Client(net::HttpTransactionFactory
* factory
, const std::string
& url
) :
63 buffer_(new net::IOBuffer(kBufferSize
)) {
64 int rv
= factory
->CreateTransaction(
65 net::DEFAULT_PRIORITY
, &transaction_
, NULL
);
66 DCHECK_EQ(net::OK
, rv
);
68 g_driver
.Get().ClientStarted();
69 request_info_
.url
= url_
;
70 request_info_
.method
= "GET";
71 int state
= transaction_
->Start(
73 base::Bind(&Client::OnConnectComplete
, base::Unretained(this)),
75 DCHECK(state
== net::ERR_IO_PENDING
);
79 void OnConnectComplete(int result
) {
81 int state
= transaction_
->Read(
82 buffer_
.get(), kBufferSize
,
83 base::Bind(&Client::OnReadComplete
, base::Unretained(this)));
84 if (state
== net::ERR_IO_PENDING
)
85 return; // IO has started.
88 OnReadComplete(state
);
91 void OnReadComplete(int result
) {
93 OnRequestComplete(result
);
97 // Deal with received data here.
98 base::StatsCounter
bytes_read("FetchClient.bytes_read");
99 bytes_read
.Add(result
);
101 // Issue a read for more data.
102 int state
= transaction_
->Read(
103 buffer_
.get(), kBufferSize
,
104 base::Bind(&Client::OnReadComplete
, base::Unretained(this)));
105 if (state
== net::ERR_IO_PENDING
)
106 return; // IO has started.
109 OnReadComplete(state
);
112 void OnRequestComplete(int result
) {
113 base::StatsCounter
requests("FetchClient.requests");
114 requests
.Increment();
115 g_driver
.Get().ClientStopped();
119 static const int kBufferSize
= (16 * 1024);
121 net::HttpRequestInfo request_info_
;
122 scoped_ptr
<net::HttpTransaction
> transaction_
;
123 scoped_refptr
<net::IOBuffer
> buffer_
;
126 int main(int argc
, char** argv
) {
127 base::AtExitManager exit
;
128 base::StatsTable
table("fetchclient", 50, 1000);
129 table
.set_current(&table
);
131 CommandLine::Init(argc
, argv
);
132 const CommandLine
& parsed_command_line
= *CommandLine::ForCurrentProcess();
133 std::string url
= parsed_command_line
.GetSwitchValueASCII("url");
136 int client_limit
= 1;
137 if (parsed_command_line
.HasSwitch("n")) {
138 base::StringToInt(parsed_command_line
.GetSwitchValueASCII("n"),
141 bool use_cache
= parsed_command_line
.HasSwitch("use-cache");
144 base::MessageLoop
loop(base::MessageLoop::TYPE_IO
);
146 scoped_ptr
<net::HostResolver
> host_resolver(
147 net::HostResolver::CreateDefaultResolver(NULL
));
148 scoped_ptr
<net::CertVerifier
> cert_verifier(
149 net::CertVerifier::CreateDefault());
150 scoped_ptr
<net::TransportSecurityState
> transport_security_state(
151 new net::TransportSecurityState
);
152 scoped_ptr
<net::ProxyService
> proxy_service(
153 net::ProxyService::CreateDirect());
154 scoped_refptr
<net::SSLConfigService
> ssl_config_service(
155 new net::SSLConfigServiceDefaults
);
156 net::HttpTransactionFactory
* factory
= NULL
;
157 scoped_ptr
<net::HttpAuthHandlerFactory
> http_auth_handler_factory(
158 net::HttpAuthHandlerFactory::CreateDefault(host_resolver
.get()));
159 net::HttpServerPropertiesImpl http_server_properties
;
161 net::HttpNetworkSession::Params session_params
;
162 session_params
.host_resolver
= host_resolver
.get();
163 session_params
.cert_verifier
= cert_verifier
.get();
164 session_params
.transport_security_state
= transport_security_state
.get();
165 session_params
.proxy_service
= proxy_service
.get();
166 session_params
.http_auth_handler_factory
= http_auth_handler_factory
.get();
167 session_params
.http_server_properties
= http_server_properties
.GetWeakPtr();
168 session_params
.ssl_config_service
= ssl_config_service
.get();
170 scoped_refptr
<net::HttpNetworkSession
> network_session(
171 new net::HttpNetworkSession(session_params
));
173 factory
= new net::HttpCache(network_session
.get(),
174 net::HttpCache::DefaultBackend::InMemory(0));
176 factory
= new net::HttpNetworkLayer(network_session
.get());
180 base::StatsCounterTimer
driver_time("FetchClient.total_time");
181 base::StatsScope
<base::StatsCounterTimer
> scope(driver_time
);
183 Client
** clients
= new Client
*[client_limit
];
184 for (int i
= 0; i
< client_limit
; i
++)
185 clients
[i
] = new Client(factory
, url
);
187 base::MessageLoop::current()->Run();
190 // Print Statistics here.
191 int num_clients
= table
.GetCounterValue("c:FetchClient.requests");
192 int test_time
= table
.GetCounterValue("t:FetchClient.total_time");
193 int bytes_read
= table
.GetCounterValue("c:FetchClient.bytes_read");
196 printf("Clients : %d\n", num_clients
);
197 printf("Time : %dms\n", test_time
);
198 printf("Bytes Read : %d\n", bytes_read
);
200 const char *units
= "bps";
201 double bps
= static_cast<float>(bytes_read
* 8) /
202 (static_cast<float>(test_time
) / 1000.0);
204 if (bps
> (1024*1024)) {
207 } else if (bps
> 1024) {
211 printf("Bandwidth : %.2f%s\n", bps
, units
);
214 if (parsed_command_line
.HasSwitch("stats")) {
215 // Dump the stats table.
217 int counter_max
= table
.GetMaxCounters();
218 for (int index
= 0; index
< counter_max
; index
++) {
219 std::string
name(table
.GetRowName(index
));
220 if (name
.length() > 0) {
221 int value
= table
.GetRowValue(index
);
222 printf("%s:\t%d\n", name
.c_str(), value
);
225 printf("</stats>\n");