1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved.
2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be
3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file.
4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "build/build_config.h"
6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/at_exit.h"
8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/command_line.h"
921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/message_loop.h"
11731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick#include "base/metrics/stats_counters.h"
123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/string_util.h"
1421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "net/base/cert_verifier.h"
15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/completion_callback.h"
16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/host_resolver.h"
17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/io_buffer.h"
18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/net_errors.h"
19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/base/ssl_config_service.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/http/http_auth_handler_factory.h"
21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_cache.h"
22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_network_layer.h"
2372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "net/http/http_network_session.h"
24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_request_info.h"
25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/http/http_transaction.h"
26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "net/proxy/proxy_service.h"
27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottvoid usage(const char* program_name) {
29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  printf("usage: %s --url=<url>  [--n=<clients>] [--stats] [--use_cache]\n",
30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott         program_name);
31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  exit(1);
32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Test Driver
35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass Driver {
36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Driver()
38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      : clients_(0) {}
39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void ClientStarted() { clients_++; }
41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void ClientStopped() {
42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (!--clients_) {
43c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      MessageLoop::current()->Quit();
44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int clients_;
49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
50c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
5121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<Driver> g_driver(base::LINKER_INITIALIZED);
5221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A network client
54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass Client {
55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public:
56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  Client(net::HttpTransactionFactory* factory, const std::string& url) :
57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      url_(url),
58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      buffer_(new net::IOBuffer(kBufferSize)),
59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ALLOW_THIS_IN_INITIALIZER_LIST(
60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          connect_callback_(this, &Client::OnConnectComplete)),
61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      ALLOW_THIS_IN_INITIALIZER_LIST(
62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott          read_callback_(this, &Client::OnReadComplete)) {
63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int rv = factory->CreateTransaction(&transaction_);
64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK_EQ(net::OK, rv);
65c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    buffer_->AddRef();
6621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    g_driver.Get().ClientStarted();
67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    request_info_.url = url_;
68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    request_info_.method = "GET";
69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int state = transaction_->Start(
70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        &request_info_, &connect_callback_, net::BoundNetLog());
71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    DCHECK(state == net::ERR_IO_PENDING);
72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  };
73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private:
75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void OnConnectComplete(int result) {
76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Do work here.
77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_);
78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (state == net::ERR_IO_PENDING)
79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;  // IO has started.
80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (state < 0)
81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;  // ERROR!
82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    OnReadComplete(state);
83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void OnReadComplete(int result) {
86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (result == 0) {
87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      OnRequestComplete(result);
88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;
89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Deal with received data here.
92ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::StatsCounter bytes_read("FetchClient.bytes_read");
93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    bytes_read.Add(result);
94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Issue a read for more data.
96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int state = transaction_->Read(buffer_.get(), kBufferSize, &read_callback_);
97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (state == net::ERR_IO_PENDING)
98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;  // IO has started.
99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (state < 0)
100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      return;  // ERROR!
101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    OnReadComplete(state);
102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  void OnRequestComplete(int result) {
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::StatsCounter requests("FetchClient.requests");
106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    requests.Increment();
10721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    g_driver.Get().ClientStopped();
108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    printf(".");
109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  static const int kBufferSize = (16 * 1024);
112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  GURL url_;
113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::HttpRequestInfo request_info_;
114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_ptr<net::HttpTransaction> transaction_;
115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<net::IOBuffer> buffer_;
116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::CompletionCallbackImpl<Client> connect_callback_;
117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::CompletionCallbackImpl<Client> read_callback_;
118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott};
119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottint main(int argc, char**argv) {
121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  base::AtExitManager exit;
122731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::StatsTable table("fetchclient", 50, 1000);
123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  table.set_current(&table);
124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  CommandLine::Init(argc, argv);
126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  std::string url = parsed_command_line.GetSwitchValueASCII("url");
128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (!url.length())
129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    usage(argv[0]);
130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int client_limit = 1;
1313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (parsed_command_line.HasSwitch("n")) {
1323345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    base::StringToInt(parsed_command_line.GetSwitchValueASCII("n"),
1333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                      &client_limit);
1343345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  bool use_cache = parsed_command_line.HasSwitch("use-cache");
136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Do work here.
138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  MessageLoop loop(MessageLoop::TYPE_IO);
139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
140731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  scoped_ptr<net::HostResolver> host_resolver(
1413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net::CreateSystemHostResolver(net::HostResolver::kDefaultParallelism,
142513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                    NULL, NULL));
143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
14421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_ptr<net::CertVerifier> cert_verifier(new net::CertVerifier);
145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<net::ProxyService> proxy_service(
1463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      net::ProxyService::CreateDirect());
147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  scoped_refptr<net::SSLConfigService> ssl_config_service(
148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      net::SSLConfigService::CreateSystemSSLConfigService());
149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  net::HttpTransactionFactory* factory = NULL;
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  scoped_ptr<net::HttpAuthHandlerFactory> http_auth_handler_factory(
151731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
15272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
15372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  net::HttpNetworkSession::Params session_params;
15472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  session_params.host_resolver = host_resolver.get();
15572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  session_params.cert_verifier = cert_verifier.get();
15672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  session_params.proxy_service = proxy_service;
15772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  session_params.http_auth_handler_factory = http_auth_handler_factory.get();
15872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  session_params.ssl_config_service = ssl_config_service;
15972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
16072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  scoped_refptr<net::HttpNetworkSession> network_session(
16172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      new net::HttpNetworkSession(session_params));
162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (use_cache) {
16372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    factory = new net::HttpCache(network_session,
16472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                 net::HttpCache::DefaultBackend::InMemory(0));
165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  } else {
16672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    factory = new net::HttpNetworkLayer(network_session);
167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  {
170731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::StatsCounterTimer driver_time("FetchClient.total_time");
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    base::StatsScope<base::StatsCounterTimer> scope(driver_time);
172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    Client** clients = new Client*[client_limit];
174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    for (int i = 0; i < client_limit; i++)
175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      clients[i] = new Client(factory, url);
176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    MessageLoop::current()->Run();
178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  // Print Statistics here.
181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int num_clients = table.GetCounterValue("c:FetchClient.requests");
182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int test_time = table.GetCounterValue("t:FetchClient.total_time");
183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  int bytes_read = table.GetCounterValue("c:FetchClient.bytes_read");
184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  printf("\n");
186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  printf("Clients     : %d\n", num_clients);
187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  printf("Time        : %dms\n", test_time);
188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  printf("Bytes Read  : %d\n", bytes_read);
189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (test_time > 0) {
190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    const char *units = "bps";
191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    double bps = static_cast<float>(bytes_read * 8) /
192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        (static_cast<float>(test_time) / 1000.0);
193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    if (bps > (1024*1024)) {
195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bps /= (1024*1024);
196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      units = "Mbps";
197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    } else if (bps > 1024) {
198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      bps /= 1024;
199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      units = "Kbps";
200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    printf("Bandwidth   : %.2f%s\n", bps, units);
202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott
204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  if (parsed_command_line.HasSwitch("stats")) {
205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    // Dump the stats table.
206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    printf("<stats>\n");
207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    int counter_max = table.GetMaxCounters();
20821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    for (int index = 0; index < counter_max; index++) {
209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      std::string name(table.GetRowName(index));
210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      if (name.length() > 0) {
211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        int value = table.GetRowValue(index);
212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott        printf("%s:\t%d\n", name.c_str(), value);
213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott      }
214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    }
215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott    printf("</stats>\n");
216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  }
217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott  return 0;
218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}
219