OLD | NEW |
1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import common, fnmatch, logging, os, re, string, threading, time | 5 import common, fnmatch, logging, os, re, string, threading, time |
6 | 6 |
7 from autotest_lib.server import autotest, hosts, subcommand | 7 from autotest_lib.server import autotest, hosts, subcommand |
8 from autotest_lib.server import site_bsd_router | 8 from autotest_lib.server import site_bsd_router |
9 from autotest_lib.server import site_linux_router | 9 from autotest_lib.server import site_linux_router |
10 from autotest_lib.server import site_host_attributes | 10 from autotest_lib.server import site_host_attributes |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
61 by adding a new class and auto-selecting it in __init__. | 61 by adding a new class and auto-selecting it in __init__. |
62 | 62 |
63 The WiFiTest class could be generalized to handle clients other than | 63 The WiFiTest class could be generalized to handle clients other than |
64 ChromeOS; this would useful for systems that use Network Manager or | 64 ChromeOS; this would useful for systems that use Network Manager or |
65 wpa_supplicant directly. | 65 wpa_supplicant directly. |
66 """ | 66 """ |
67 | 67 |
68 def __init__(self, name, steps, config): | 68 def __init__(self, name, steps, config): |
69 self.name = name | 69 self.name = name |
70 self.steps = steps | 70 self.steps = steps |
71 self.keyvals = {} | 71 self.perf_keyvals = {} |
72 | 72 |
73 router = config['router'] | 73 router = config['router'] |
74 self.router = hosts.create_host(router['addr']) | 74 self.router = hosts.create_host(router['addr']) |
75 # NB: truncate SSID to 32 characters | 75 # NB: truncate SSID to 32 characters |
76 self.defssid = self.__get_defssid(router['addr'])[0:32] | 76 self.defssid = self.__get_defssid(router['addr'])[0:32] |
77 | 77 |
78 defaults = config.get('defaults', {}) | 78 defaults = config.get('defaults', {}) |
79 self.deftimeout = defaults.get('timeout', 30) | 79 self.deftimeout = defaults.get('timeout', 30) |
80 self.defpingcount = defaults.get('pingcount', 10) | 80 self.defpingcount = defaults.get('pingcount', 10) |
81 self.defwaittime = str(defaults.get('netperf_wait_time', 3)) | 81 self.defwaittime = str(defaults.get('netperf_wait_time', 3)) |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 self.server = None; | 125 self.server = None; |
126 # NB: wifi address must be set if not reachable from control | 126 # NB: wifi address must be set if not reachable from control |
127 self.server_wifi_ip = server['wifi_addr'] | 127 self.server_wifi_ip = server['wifi_addr'] |
128 | 128 |
129 # potential bg thread for ping untilstop | 129 # potential bg thread for ping untilstop |
130 self.ping_thread = None | 130 self.ping_thread = None |
131 | 131 |
132 # potential bg thread for client network monitoring | 132 # potential bg thread for client network monitoring |
133 self.client_netdump_thread = None | 133 self.client_netdump_thread = None |
134 self.__client_discover_commands(client) | 134 self.__client_discover_commands(client) |
135 self.netperf_iter = 0 | |
136 self.firewall_rules = [] | 135 self.firewall_rules = [] |
137 | 136 |
| 137 # Find all repeated steps and create iterators for them |
| 138 self.iterated_steps = {} |
| 139 step_names = [step[0] for step in steps] |
| 140 for step_name in list(set(step_names)): |
| 141 if step_names.count(step_name) > 1: |
| 142 self.iterated_steps[step_name] = 0 |
138 | 143 |
139 def cleanup(self, params): | 144 def cleanup(self, params): |
140 """ Cleanup state: disconnect client and destroy ap """ | 145 """ Cleanup state: disconnect client and destroy ap """ |
141 self.disconnect({}) | 146 self.disconnect({}) |
142 self.wifi.destroy({}) | 147 self.wifi.destroy({}) |
143 self.client_netdump_stop({}) | 148 self.client_netdump_stop({}) |
144 self.firewall_cleanup({}) | 149 self.firewall_cleanup({}) |
145 | 150 |
146 | 151 |
147 def __client_discover_commands(self, client): | 152 def __client_discover_commands(self, client): |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 in this class or the ancillary router class and invoked with | 186 in this class or the ancillary router class and invoked with |
182 the supplied parameter dictionary. | 187 the supplied parameter dictionary. |
183 """ | 188 """ |
184 for s in self.steps: | 189 for s in self.steps: |
185 method = s[0] | 190 method = s[0] |
186 if len(s) > 1: | 191 if len(s) > 1: |
187 params = s[1] | 192 params = s[1] |
188 else: | 193 else: |
189 params = {} | 194 params = {} |
190 | 195 |
| 196 # What should perf data be prefixed with? |
| 197 if 'perf_prefix' in params: |
| 198 self.prefix = '%s_%s' % (method, params.pop('perf_prefix')) |
| 199 elif method in self.iterated_steps: |
| 200 self.prefix = '%s_%d' % (method, self.iterated_steps[method]) |
| 201 self.iterated_steps[method] += 1 |
| 202 else: |
| 203 self.prefix = method |
| 204 |
191 logging.info("%s: step '%s' params %s", self.name, method, params) | 205 logging.info("%s: step '%s' params %s", self.name, method, params) |
192 | 206 |
193 func = getattr(self, method, None) | 207 func = getattr(self, method, None) |
194 if func is None: | 208 if func is None: |
195 func = getattr(self.wifi, method, None) | 209 func = getattr(self.wifi, method, None) |
196 if func is not None: | 210 if func is not None: |
197 try: | 211 try: |
198 func(params) | 212 func(params) |
199 except Exception, e: | 213 except Exception, e: |
200 logging.error("%s: Step '%s' failed: %s; abort test", | 214 logging.error("%s: Step '%s' failed: %s; abort test", |
201 self.name, method, str(e)) | 215 self.name, method, str(e)) |
202 self.cleanup(params) | 216 self.cleanup(params) |
203 raise e | 217 raise e |
204 break | 218 break |
205 else: | 219 else: |
206 logging.error("%s: Step '%s' unknown; abort test", | 220 logging.error("%s: Step '%s' unknown; abort test", |
207 self.name, method) | 221 self.name, method) |
208 self.cleanup(params) | 222 self.cleanup(params) |
209 break | 223 break |
210 | 224 |
211 # Other cleanup steps might be optional, but this is mandatory | 225 # Other cleanup steps might be optional, but this is mandatory |
212 self.client_netdump_stop({}) | 226 self.client_netdump_stop({}) |
213 | 227 |
214 | 228 |
215 def write_keyvals(self, job): | 229 def write_keyvals(self, job): |
216 job.write_perf_keyval(self.keyvals) | 230 job.write_perf_keyval(self.perf_keyvals) |
217 | 231 |
| 232 def write_perf(self, data): |
| 233 for key, value in data.iteritems(): |
| 234 self.perf_keyvals['%s_%s' % (self.prefix, key)] = value |
218 | 235 |
219 def __get_ipaddr(self, host, ifnet): | 236 def __get_ipaddr(self, host, ifnet): |
220 # XXX gotta be a better way to do this | 237 # XXX gotta be a better way to do this |
221 result = host.run("%s %s" % (self.client_cmd_ifconfig, ifnet)) | 238 result = host.run("%s %s" % (self.client_cmd_ifconfig, ifnet)) |
222 m = re.search('inet addr:([^ ]*)', result.stdout) | 239 m = re.search('inet addr:([^ ]*)', result.stdout) |
223 if m is None: | 240 if m is None: |
224 raise error.TestFail("No inet address found") | 241 raise error.TestFail("No inet address found") |
225 return m.group(1) | 242 return m.group(1) |
226 | 243 |
227 | 244 |
(...skipping 15 matching lines...) Expand all Loading... |
243 result = self.client.run('python "%s" "%s" "%s" "%s" "%d" "%d"' % | 260 result = self.client.run('python "%s" "%s" "%s" "%s" "%d" "%d"' % |
244 (script_client_file, | 261 (script_client_file, |
245 params.get('ssid', self.wifi.get_ssid()), | 262 params.get('ssid', self.wifi.get_ssid()), |
246 params.get('security', ''), | 263 params.get('security', ''), |
247 params.get('psk', ''), | 264 params.get('psk', ''), |
248 params.get('assoc_timeout', self.deftimeout), | 265 params.get('assoc_timeout', self.deftimeout), |
249 params.get('config_timeout', self.deftimeout))).stdout.rstrip() | 266 params.get('config_timeout', self.deftimeout))).stdout.rstrip() |
250 | 267 |
251 result_times = re.match("OK ([0-9\.]*) ([0-9\.]*) .*", result) | 268 result_times = re.match("OK ([0-9\.]*) ([0-9\.]*) .*", result) |
252 | 269 |
253 self.keyvals['connect_config_s'] = result_times.group(1) | 270 self.write_perf({'config_s': result_times.group(1), |
254 self.keyvals['connect_assoc_s'] = result_times.group(2) | 271 'assoc_s': result_times.group(2)}) |
255 for k in ('multiple_attempts', 'clear_error', 'fast_fail'): | 272 for k in ('already_connected', 'clear_error', 'fast_fail', |
| 273 'get_prop', 'in_progress', 'lost_dbus', 'multiple_attempts'): |
256 if re.search(k, result) is not None: | 274 if re.search(k, result) is not None: |
257 self.keyvals[k] = 'true' | 275 self.write_perf({k:'true'}) |
258 | 276 |
259 print "%s: %s" % (self.name, result) | 277 print "%s: %s" % (self.name, result) |
260 | 278 |
261 # fetch IP address of wireless device | 279 # fetch IP address of wireless device |
262 self.client_wifi_ip = self.__get_ipaddr(self.client, self.client_wlanif) | 280 self.client_wifi_ip = self.__get_ipaddr(self.client, self.client_wlanif) |
263 logging.info("%s: client WiFi-IP is %s", self.name, self.client_wifi_ip) | 281 logging.info("%s: client WiFi-IP is %s", self.name, self.client_wifi_ip) |
264 # TODO(sleffler) not right for non-mac80211 devices | 282 # TODO(sleffler) not right for non-mac80211 devices |
265 # TODO(sleffler) verify debugfs is mounted @ /sys/kernel/debug | 283 # TODO(sleffler) verify debugfs is mounted @ /sys/kernel/debug |
266 self.client_debugfs_path = "/sys/kernel/debug/ieee80211/%s/netdev:%s" \ | 284 self.client_debugfs_path = "/sys/kernel/debug/ieee80211/%s/netdev:%s" \ |
267 % ("phy0", self.client_wlanif) | 285 % ("phy0", self.client_wlanif) |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
417 stats['max'] = m.group(4) | 435 stats['max'] = m.group(4) |
418 return stats | 436 return stats |
419 | 437 |
420 | 438 |
421 def __print_pingstats(self, label, stats): | 439 def __print_pingstats(self, label, stats): |
422 logging.info("%s: %s%s/%s, %s%% loss, rtt %s/%s/%s", | 440 logging.info("%s: %s%s/%s, %s%% loss, rtt %s/%s/%s", |
423 self.name, label, stats['xmit'], stats['recv'], stats['loss'], | 441 self.name, label, stats['xmit'], stats['recv'], stats['loss'], |
424 stats['min'], stats['avg'], stats['max']) | 442 stats['min'], stats['avg'], stats['max']) |
425 | 443 |
426 | 444 |
427 def __ping_prefix(self, params): | |
428 if 'name' in params: | |
429 return params['name'] | |
430 | |
431 args = [] | |
432 for k, v in params.items(): | |
433 if k != 'count': | |
434 args.append('%s_%s' % (k, v)) | |
435 return '/'.join(args) | |
436 | |
437 | |
438 def client_ping(self, params): | 445 def client_ping(self, params): |
439 """ Ping the server from the client """ | 446 """ Ping the server from the client """ |
440 ping_ip = params.get('ping_ip', self.server_wifi_ip) | 447 ping_ip = params.get('ping_ip', self.server_wifi_ip) |
441 count = params.get('count', self.defpingcount) | 448 count = params.get('count', self.defpingcount) |
442 # set timeout for 3s / ping packet | 449 # set timeout for 3s / ping packet |
443 result = self.client.run("ping %s %s" % \ | 450 result = self.client.run("ping %s %s" % \ |
444 (self.__ping_args(params), ping_ip), timeout=3*int(count)) | 451 (self.__ping_args(params), ping_ip), timeout=3*int(count)) |
445 | 452 |
446 stats = self.__get_pingstats(result.stdout) | 453 stats = self.__get_pingstats(result.stdout) |
447 prefix = 'client_ping_%s_' % self.__ping_prefix(params) | 454 self.write_perf(stats) |
448 for k,v in stats.iteritems(): | |
449 self.keyvals[prefix + k] = v | |
450 self.__print_pingstats("client_ping ", stats) | 455 self.__print_pingstats("client_ping ", stats) |
451 | 456 |
452 | 457 |
453 def client_ping_bg(self, params): | 458 def client_ping_bg(self, params): |
454 """ Ping the server from the client """ | 459 """ Ping the server from the client """ |
455 ping_ip = params.get('ping_ip', self.server_wifi_ip) | 460 ping_ip = params.get('ping_ip', self.server_wifi_ip) |
456 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) | 461 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) |
457 self.ping_thread = HelperThread(self.client, cmd) | 462 self.ping_thread = HelperThread(self.client, cmd) |
458 self.ping_thread.start() | 463 self.ping_thread.start() |
459 | 464 |
(...skipping 11 matching lines...) Expand all Loading... |
471 self.__unreachable("server_ping") | 476 self.__unreachable("server_ping") |
472 return | 477 return |
473 ping_ip = params.get('ping_ip', self.client_wifi_ip) | 478 ping_ip = params.get('ping_ip', self.client_wifi_ip) |
474 count = params.get('count', self.defpingcount) | 479 count = params.get('count', self.defpingcount) |
475 # set timeout for 3s / ping packet | 480 # set timeout for 3s / ping packet |
476 result = self.server.run("%s %s %s" % \ | 481 result = self.server.run("%s %s %s" % \ |
477 (self.server_ping_cmd, self.__ping_args(params), | 482 (self.server_ping_cmd, self.__ping_args(params), |
478 ping_ip), timeout=3*int(count)) | 483 ping_ip), timeout=3*int(count)) |
479 | 484 |
480 stats = self.__get_pingstats(result.stdout) | 485 stats = self.__get_pingstats(result.stdout) |
481 prefix = 'server_ping_' + self.__ping_prefix(params) | 486 self.write_perf(stats) |
482 for k,v in stats.iteritems(): | |
483 self.keyvals['server_ping_' + k] = v | |
484 self.__print_pingstats("server_ping ", stats) | 487 self.__print_pingstats("server_ping ", stats) |
485 | 488 |
486 | 489 |
487 def server_ping_bg(self, params): | 490 def server_ping_bg(self, params): |
488 """ Ping the client from the server """ | 491 """ Ping the client from the server """ |
489 if self.server is None: | 492 if self.server is None: |
490 self.__unreachable("server_ping_bg") | 493 self.__unreachable("server_ping_bg") |
491 return | 494 return |
492 ping_ip = params.get('ping_ip', self.client_wifi_ip) | 495 ping_ip = params.get('ping_ip', self.client_wifi_ip) |
493 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) | 496 cmd = "ping %s %s" % (self.__ping_args(params), ping_ip) |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 # Run netperf command and receive command results | 619 # Run netperf command and receive command results |
617 t0 = time.time() | 620 t0 = time.time() |
618 results = client['host'].run("%s %s" % (client['cmd'], netperf_args)) | 621 results = client['host'].run("%s %s" % (client['cmd'], netperf_args)) |
619 actual_time = time.time() - t0 | 622 actual_time = time.time() - t0 |
620 logging.info('actual_time: %f', actual_time) | 623 logging.info('actual_time: %f', actual_time) |
621 | 624 |
622 # Close up whatever firewall rules we created for netperf | 625 # Close up whatever firewall rules we created for netperf |
623 for rule in np_rules: | 626 for rule in np_rules: |
624 self.__firewall_close(rule) | 627 self.__firewall_close(rule) |
625 | 628 |
626 # Results are prefixed with the iteration or a caller-defined name | 629 self.write_perf({'test':test, 'mode':mode, 'actual_time':actual_time}) |
627 prefix = 'Netperf_%s_' % params.get('name', str(self.netperf_iter)) | |
628 self.netperf_iter += 1 | |
629 | |
630 self.keyvals[prefix + 'test'] = test | |
631 self.keyvals[prefix + 'mode'] = mode | |
632 self.keyvals[prefix + 'actual_time'] = actual_time | |
633 | 630 |
634 logging.info(results) | 631 logging.info(results) |
635 | 632 |
636 lines = results.stdout.splitlines() | 633 lines = results.stdout.splitlines() |
637 | 634 |
638 # Each test type has a different form of output | 635 # Each test type has a different form of output |
639 if test in ['TCP_STREAM', 'TCP_MAERTS', 'TCP_SENDFILE']: | 636 if test in ['TCP_STREAM', 'TCP_MAERTS', 'TCP_SENDFILE']: |
640 """Parses the following (works for both TCP_STREAM, TCP_MAERTS and | 637 """Parses the following (works for both TCP_STREAM, TCP_MAERTS and |
641 TCP_SENDFILE) and returns a singleton containing throughput. | 638 TCP_SENDFILE) and returns a singleton containing throughput. |
642 | 639 |
643 TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to \ | 640 TCP STREAM TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET to \ |
644 foo.bar.com (10.10.10.3) port 0 AF_INET | 641 foo.bar.com (10.10.10.3) port 0 AF_INET |
645 Recv Send Send | 642 Recv Send Send |
646 Socket Socket Message Elapsed | 643 Socket Socket Message Elapsed |
647 Size Size Size Time Throughput | 644 Size Size Size Time Throughput |
648 bytes bytes bytes secs. 10^6bits/sec | 645 bytes bytes bytes secs. 10^6bits/sec |
649 | 646 |
650 87380 16384 16384 2.00 941.28 | 647 87380 16384 16384 2.00 941.28 |
651 """ | 648 """ |
652 self.keyvals[prefix + 'Throughput'] = float(lines[6].split()[4]) | 649 self.write_perf({'Throughput':float(lines[6].split()[4])}) |
653 elif test == 'UDP_STREAM': | 650 elif test == 'UDP_STREAM': |
654 """Parses the following and returns a touple containing throughput | 651 """Parses the following and returns a touple containing throughput |
655 and the number of errors. | 652 and the number of errors. |
656 | 653 |
657 UDP UNIDIRECTIONAL SEND TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ | 654 UDP UNIDIRECTIONAL SEND TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ |
658 to foo.bar.com (10.10.10.3) port 0 AF_INET | 655 to foo.bar.com (10.10.10.3) port 0 AF_INET |
659 Socket Message Elapsed Messages | 656 Socket Message Elapsed Messages |
660 Size Size Time Okay Errors Throughput | 657 Size Size Time Okay Errors Throughput |
661 bytes bytes secs # # 10^6bits/sec | 658 bytes bytes secs # # 10^6bits/sec |
662 | 659 |
663 129024 65507 2.00 3673 0 961.87 | 660 129024 65507 2.00 3673 0 961.87 |
664 131072 2.00 3673 961.87 | 661 131072 2.00 3673 961.87 |
665 """ | 662 """ |
666 udp_tokens = lines[5].split() | 663 udp_tokens = lines[5].split() |
667 self.keyvals[prefix + 'Throughput'] = float(udp_tokens[5]) | 664 self.write_perf({'Throughput':float(udp_tokens[5]), |
668 self.keyvals[prefix + 'Errors'] = float(udp_tokens[4]) | 665 'Errors':float(udp_tokens[4])}) |
669 elif test in ['TCP_RR', 'TCP_CRR', 'UDP_RR']: | 666 elif test in ['TCP_RR', 'TCP_CRR', 'UDP_RR']: |
670 """Parses the following which works for both rr (TCP and UDP) | 667 """Parses the following which works for both rr (TCP and UDP) |
671 and crr tests and returns a singleton containing transfer rate. | 668 and crr tests and returns a singleton containing transfer rate. |
672 | 669 |
673 TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ | 670 TCP REQUEST/RESPONSE TEST from 0.0.0.0 (0.0.0.0) port 0 AF_INET \ |
674 to foo.bar.com (10.10.10.3) port 0 AF_INET | 671 to foo.bar.com (10.10.10.3) port 0 AF_INET |
675 Local /Remote | 672 Local /Remote |
676 Socket Size Request Resp. Elapsed Trans. | 673 Socket Size Request Resp. Elapsed Trans. |
677 Send Recv Size Size Time Rate | 674 Send Recv Size Size Time Rate |
678 bytes Bytes bytes bytes secs. per sec | 675 bytes Bytes bytes bytes secs. per sec |
679 | 676 |
680 16384 87380 1 1 2.00 14118.53 | 677 16384 87380 1 1 2.00 14118.53 |
681 16384 87380 | 678 16384 87380 |
682 """ | 679 """ |
683 self.kevals[prefix + 'Trasnfer_Rate'] = float(lines[6].split()[5]) | 680 self.write_perf({'Trasnfer_Rate':float(lines[6].split()[5])}) |
684 else: | 681 else: |
685 raise error.TestError('Unhandled test') | 682 raise error.TestError('Unhandled test') |
686 | 683 |
687 return True | 684 return True |
688 | 685 |
689 | 686 |
690 def client_netperf(self, params): | 687 def client_netperf(self, params): |
691 """ Run netperf on the client against the server """ | 688 """ Run netperf on the client against the server """ |
692 self.__run_netperf('client', params) | 689 self.__run_netperf('client', params) |
693 | 690 |
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 if server_addr is None and hasattr(client_attributes, 'server_addr'): | 802 if server_addr is None and hasattr(client_attributes, 'server_addr'): |
806 server_addr = client_attributes.server_addr | 803 server_addr = client_attributes.server_addr |
807 if server_addr is not None: | 804 if server_addr is not None: |
808 server['addr'] = server_addr; | 805 server['addr'] = server_addr; |
809 # TODO(sleffler) check for wifi_addr when no control address | 806 # TODO(sleffler) check for wifi_addr when no control address |
810 | 807 |
811 # tag jobs w/ the router's address on the control network | 808 # tag jobs w/ the router's address on the control network |
812 config['tagname'] = router['addr'] | 809 config['tagname'] = router['addr'] |
813 | 810 |
814 return config | 811 return config |
OLD | NEW |