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