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.
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
26 If --use_wget is present, it will fetch the URLs using wget and ignores
27 the flags --address, --port, --quic_binary_dir, etc.
30 def Timestamp(datetm
=None):
31 """Get the timestamp in microseconds.
33 datetm: the date and time to be converted to timestamp.
34 If not set, use the current UTC time.
36 The timestamp in microseconds.
38 datetm
= datetm
or datetime
.datetime
.utcnow()
39 diff
= datetm
- datetime
.datetime
.utcfromtimestamp(0)
40 timestamp
= (diff
.days
* 86400 + diff
.seconds
) * 1000000 + diff
.microseconds
43 class PageloadExperiment
:
44 def __init__(self
, use_wget
, quic_binary_dir
, quic_server_address
,
46 """Initialize PageloadExperiment.
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.
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.'
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.
69 with
open(json_file
) as f
:
71 for page
in data
['pages']:
73 if 'resources' in page
:
74 resources
= page
['resources']
78 page_list
.append([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
)
88 def DownloadOnePage(self
, urls
):
89 """Download a page emulated by a list of urls.
92 urls: list of URLs to fetch.
94 A tuple (page download time, max packet number).
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
111 if not self
.use_wget
:
112 for line
in std_err
.splitlines():
113 if line
.find('Client: Got packet') >= 0:
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.
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
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
)
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
)
160 parser
= OptionParser()
161 parser
.add_option('--use_wget', dest
='use_wget', action
='store_true',
163 # Note that only debug version generates the log containing packets
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',
172 parser
.add_option('--port', dest
='quic_server_port',
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__':