Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / net / tools / quic / benchmark / run_client.py
blob7df37ab7fa040169ce83fa537cbbc69e935ff454
1 #!/usr/bin/env python
3 # Copyright 2013 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file.
7 import csv
8 import datetime
9 import json
10 import os
11 import shlex
12 import subprocess
13 import sys
14 from optparse import OptionParser
16 """Start a client to fetch web pages either using wget or using quic_client.
17 If --use_wget is set, it uses wget.
18 Usage: This invocation
19 run_client.py --quic_binary_dir=../../../../out/Debug \
20 --address=127.0.0.1 --port=5000 --infile=test_urls.json \
21 --delay_file=delay.csv --packets_file=packets.csv
22 fetches pages listed in test_urls.json from a quic server running at
23 127.0.0.1 on port 5000 using quic binary ../../../../out/Debug/quic_client
24 and stores the delay in delay.csv and the max received packet number (for
25 QUIC) in packets.csv.
26 If --use_wget is present, it will fetch the URLs using wget and ignores
27 the flags --address, --port, --quic_binary_dir, etc.
28 """
30 def Timestamp(datetm=None):
31 """Get the timestamp in microseconds.
32 Args:
33 datetm: the date and time to be converted to timestamp.
34 If not set, use the current UTC time.
35 Returns:
36 The timestamp in microseconds.
37 """
38 datetm = datetm or datetime.datetime.utcnow()
39 diff = datetm - datetime.datetime.utcfromtimestamp(0)
40 timestamp = (diff.days * 86400 + diff.seconds) * 1000000 + diff.microseconds
41 return timestamp
43 class PageloadExperiment:
44 def __init__(self, use_wget, quic_binary_dir, quic_server_address,
45 quic_server_port):
46 """Initialize PageloadExperiment.
48 Args:
49 use_wget: Whether to use wget.
50 quic_binary_dir: Directory for quic_binary.
51 quic_server_address: IP address of quic server.
52 quic_server_port: Port of the quic server.
53 """
54 self.use_wget = use_wget
55 self.quic_binary_dir = quic_binary_dir
56 self.quic_server_address = quic_server_address
57 self.quic_server_port = quic_server_port
58 if not use_wget and not os.path.isfile(quic_binary_dir + '/quic_client'):
59 raise IOError('There is no quic_client in the given dir: %s.'
60 % quic_binary_dir)
62 @classmethod
63 def ReadPages(cls, json_file):
64 """Return the list of URLs from the json_file.
66 One entry of the list may contain a html link and multiple resources.
67 """
68 page_list = []
69 with open(json_file) as f:
70 data = json.load(f)
71 for page in data['pages']:
72 url = page['url']
73 if 'resources' in page:
74 resources = page['resources']
75 else:
76 resources = None
77 if not resources:
78 page_list.append([url])
79 else:
80 urls = [url]
81 # For url http://x.com/z/y.html, url_dir is http://x.com/z
82 url_dir = url.rsplit('/', 1)[0]
83 for resource in resources:
84 urls.append(url_dir + '/' + resource)
85 page_list.append(urls)
86 return page_list
88 def DownloadOnePage(self, urls):
89 """Download a page emulated by a list of urls.
91 Args:
92 urls: list of URLs to fetch.
93 Returns:
94 A tuple (page download time, max packet number).
95 """
96 if self.use_wget:
97 cmd = 'wget -O -'
98 else:
99 cmd = '%s/quic_client --port=%s --address=%s' % (
100 self.quic_binary_dir, self.quic_server_port, self.quic_server_address)
101 cmd_in_list = shlex.split(cmd)
102 cmd_in_list.extend(urls)
103 start_time = Timestamp()
104 ps_proc = subprocess.Popen(cmd_in_list,
105 stdout=subprocess.PIPE,
106 stderr=subprocess.PIPE)
107 _std_out, std_err = ps_proc.communicate()
108 end_time = Timestamp()
109 delta_time = end_time - start_time
110 max_packets = 0
111 if not self.use_wget:
112 for line in std_err.splitlines():
113 if line.find('Client: Got packet') >= 0:
114 elems = line.split()
115 packet_num = int(elems[4])
116 max_packets = max(max_packets, packet_num)
117 return delta_time, max_packets
119 def RunExperiment(self, infile, delay_file, packets_file=None, num_it=1):
120 """Run the pageload experiment.
122 Args:
123 infile: Input json file describing the page list.
124 delay_file: Output file storing delay in csv format.
125 packets_file: Output file storing max packet number in csv format.
126 num_it: Number of iterations to run in this experiment.
128 page_list = self.ReadPages(infile)
129 header = [urls[0].rsplit('/', 1)[1] for urls in page_list]
130 header0 = 'wget' if self.use_wget else 'quic'
131 header = [header0] + header
133 plt_list = []
134 packets_list = []
135 for i in range(num_it):
136 plt_one_row = [str(i)]
137 packets_one_row = [str(i)]
138 for urls in page_list:
139 time_micros, num_packets = self.DownloadOnePage(urls)
140 time_secs = time_micros / 1000000.0
141 plt_one_row.append('%6.3f' % time_secs)
142 packets_one_row.append('%5d' % num_packets)
143 plt_list.append(plt_one_row)
144 packets_list.append(packets_one_row)
146 with open(delay_file, 'w') as f:
147 csv_writer = csv.writer(f, delimiter=',')
148 csv_writer.writerow(header)
149 for one_row in plt_list:
150 csv_writer.writerow(one_row)
151 if packets_file:
152 with open(packets_file, 'w') as f:
153 csv_writer = csv.writer(f, delimiter=',')
154 csv_writer.writerow(header)
155 for one_row in packets_list:
156 csv_writer.writerow(one_row)
159 def main():
160 parser = OptionParser()
161 parser.add_option('--use_wget', dest='use_wget', action='store_true',
162 default=False)
163 # Note that only debug version generates the log containing packets
164 # information.
165 parser.add_option('--quic_binary_dir', dest='quic_binary_dir',
166 default='../../../../out/Debug')
167 # For whatever server address you specify, you need to run the
168 # quic_server on that machine and populate it with the cache containing
169 # the URLs requested in the --infile.
170 parser.add_option('--address', dest='quic_server_address',
171 default='127.0.0.1')
172 parser.add_option('--port', dest='quic_server_port',
173 default='5002')
174 parser.add_option('--delay_file', dest='delay_file', default='delay.csv')
175 parser.add_option('--packets_file', dest='packets_file',
176 default='packets.csv')
177 parser.add_option('--infile', dest='infile', default='test_urls.json')
178 (options, _) = parser.parse_args()
180 exp = PageloadExperiment(options.use_wget, options.quic_binary_dir,
181 options.quic_server_address,
182 options.quic_server_port)
183 exp.RunExperiment(options.infile, options.delay_file, options.packets_file)
185 if __name__ == '__main__':
186 sys.exit(main())