14710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# -*- coding: utf-8 -*- 24710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# This file should be kept compatible with both Python 2.6 and Python >= 3.0. 34710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 44710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom __future__ import division 54710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom __future__ import print_function 64710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 74710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm""" 84710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmccbench, a Python concurrency benchmark. 94710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm""" 104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport time 124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport os 134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport sys 144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport functools 154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport itertools 164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport threading 174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport subprocess 184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport socket 194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfrom optparse import OptionParser, SUPPRESS_HELP 204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmimport platform 214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# Compatibility 234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtry: 244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm xrange 254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmexcept NameError: 264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm xrange = range 274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmtry: 294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm map = itertools.imap 304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmexcept AttributeError: 314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pass 324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmTHROUGHPUT_DURATION = 2.0 354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmLATENCY_PING_INTERVAL = 0.1 374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmLATENCY_DURATION = 2.0 384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmBANDWIDTH_PACKET_SIZE = 1024 404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmBANDWIDTH_DURATION = 2.0 414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef task_pidigits(): 444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """Pi calculation (Python)""" 454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _map = map 464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _count = itertools.count 474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _islice = itertools.islice 484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def calc_ndigits(n): 504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # From http://shootout.alioth.debian.org/ 514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def gen_x(): 524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return _map(lambda k: (k, 4*k + 2, 0, 2*k + 1), _count(1)) 534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def compose(a, b): 554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm aq, ar, as_, at = a 564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm bq, br, bs, bt = b 574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return (aq * bq, 584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm aq * br + ar * bt, 594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm as_ * bq + at * bs, 604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm as_ * br + at * bt) 614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def extract(z, j): 634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm q, r, s, t = z 644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return (q*j + r) // (s*j + t) 654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def pi_digits(): 674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm z = (1, 0, 0, 1) 684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm x = gen_x() 694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while 1: 704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm y = extract(z, 3) 714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while y != extract(z, 4): 724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm z = compose(z, next(x)) 734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm y = extract(z, 3) 744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm z = compose((10, -10*y, 0, 1), z) 754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm yield y 764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return list(_islice(pi_digits(), n)) 784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return calc_ndigits, (50, ) 804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef task_regex(): 824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """regular expression (C)""" 834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # XXX this task gives horrendous latency results. 844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import re 854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Taken from the `inspect` module 864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm pat = re.compile(r'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)', re.MULTILINE) 874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with open(__file__, "r") as f: 884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm arg = f.read(2000) 894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def findall(s): 914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t = time.time() 924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return pat.findall(s) 944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm finally: 954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print(time.time() - t) 964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return pat.findall, (arg, ) 974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef task_sort(): 994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """list sorting (C)""" 1004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def list_sort(l): 1014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm l = l[::-1] 1024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm l.sort() 1034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return list_sort, (list(range(1000)), ) 1054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef task_compress_zlib(): 1074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """zlib compression (C)""" 1084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import zlib 1094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with open(__file__, "rb") as f: 1104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm arg = f.read(5000) * 3 1114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def compress(s): 1134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm zlib.decompress(zlib.compress(s, 5)) 1144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return compress, (arg, ) 1154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef task_compress_bz2(): 1174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """bz2 compression (C)""" 1184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import bz2 1194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with open(__file__, "rb") as f: 1204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm arg = f.read(3000) * 2 1214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def compress(s): 1234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm bz2.compress(s) 1244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return compress, (arg, ) 1254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef task_hashing(): 1274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm """SHA1 hashing (C)""" 1284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm import hashlib 1294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with open(__file__, "rb") as f: 1304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm arg = f.read(5000) * 30 1314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def compute(s): 1334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm hashlib.sha1(s).digest() 1344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return compute, (arg, ) 1354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmthroughput_tasks = [task_pidigits, task_regex] 1384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmfor mod in 'bz2', 'hashlib': 1394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 1404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm globals()[mod] = __import__(mod) 1414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm except ImportError: 1424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm globals()[mod] = None 1434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# For whatever reasons, zlib gives irregular results, so we prefer bz2 or 1454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# hashlib if available. 1464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm# (NOTE: hashlib releases the GIL from 2.7 and 3.1 onwards) 1474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif bz2 is not None: 1484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm throughput_tasks.append(task_compress_bz2) 1494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmelif hashlib is not None: 1504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm throughput_tasks.append(task_hashing) 1514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmelse: 1524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm throughput_tasks.append(task_compress_zlib) 1534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmlatency_tasks = throughput_tasks 1554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmbandwidth_tasks = [task_pidigits] 1564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmclass TimedLoop: 1594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __init__(self, func, args): 1604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.func = func 1614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm self.args = args 1624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def __call__(self, start_time, min_duration, end_event, do_yield=False): 1644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm step = 20 1654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm niters = 0 1664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm duration = 0.0 1674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _time = time.time 1684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep = time.sleep 1694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _func = self.func 1704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _args = self.args 1714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t1 = start_time 1724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while True: 1734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for i in range(step): 1744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _func(*_args) 1754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t2 = _time() 1764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # If another thread terminated, the current measurement is invalid 1774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # => return the previous one. 1784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if end_event: 1794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return niters, duration 1804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm niters += step 1814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm duration = t2 - start_time 1824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if duration >= min_duration: 1834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event.append(None) 1844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return niters, duration 1854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if t2 - t1 < 0.01: 1864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Minimize interference of measurement on overall runtime 1874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm step = step * 3 // 2 1884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm elif do_yield: 1894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # OS scheduling of Python threads is sometimes so bad that we 1904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # have to force thread switching ourselves, otherwise we get 1914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # completely useless results. 1924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep(0.0001) 1934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t1 = t2 1944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_throughput_test(func, args, nthreads): 1974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm assert nthreads >= 1 1984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 1994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Warm up 2004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func(*args) 2014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = [] 2034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm loop = TimedLoop(func, args) 2044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event = [] 2054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if nthreads == 1: 2074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Pure single-threaded performance, without any switching or 2084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # synchronization overhead. 2094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_time = time.time() 2104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results.append(loop(start_time, THROUGHPUT_DURATION, 2114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event, do_yield=False)) 2124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return results 2134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm started = False 2154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond = threading.Condition() 2164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond = threading.Condition() 2174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready = [] 2184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def run(): 2204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with ready_cond: 2214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready.append(None) 2224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond.notify() 2234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with start_cond: 2244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while not started: 2254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond.wait() 2264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results.append(loop(start_time, THROUGHPUT_DURATION, 2274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event, do_yield=True)) 2284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm threads = [] 2304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for i in range(nthreads): 2314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm threads.append(threading.Thread(target=run)) 2324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in threads: 2334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.setDaemon(True) 2344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.start() 2354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # We don't want measurements to include thread startup overhead, 2364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # so we arrange for timing to start after all threads are ready. 2374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with ready_cond: 2384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while len(ready) < nthreads: 2394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond.wait() 2404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with start_cond: 2414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_time = time.time() 2424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm started = True 2434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond.notify(nthreads) 2444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in threads: 2454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.join() 2464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return results 2484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_throughput_tests(max_threads): 2504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for task in throughput_tasks: 2514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print(task.__doc__) 2524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 2534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func, args = task() 2544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nthreads = 1 2554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm baseline_speed = None 2564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while nthreads <= max_threads: 2574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = run_throughput_test(func, args, nthreads) 2584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Taking the max duration rather than average gives pessimistic 2594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # results rather than optimistic. 2604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm speed = sum(r[0] for r in results) / max(r[1] for r in results) 2614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("threads=%d: %d" % (nthreads, speed), end="") 2624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if baseline_speed is None: 2634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print(" iterations/s.") 2644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm baseline_speed = speed 2654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 2664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print(" ( %d %%)" % (speed / baseline_speed * 100)) 2674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nthreads += 1 2684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 2694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmLAT_END = "END" 2724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _sendto(sock, s, addr): 2744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock.sendto(s.encode('ascii'), addr) 2754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef _recv(sock, n): 2774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return sock.recv(n).decode('ascii') 2784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef latency_client(addr, nb_pings, interval): 2804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 2814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _time = time.time 2824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep = time.sleep 2834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _ping(): 2844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sendto(sock, "%r\n" % _time(), addr) 2854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # The first ping signals the parent process that we are ready. 2864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _ping() 2874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # We give the parent a bit of time to notice. 2884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep(1.0) 2894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for i in range(nb_pings): 2904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep(interval) 2914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _ping() 2924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sendto(sock, LAT_END + "\n", addr) 2934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 2944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_latency_client(**kwargs): 2954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cmd_line = [sys.executable, '-E', os.path.abspath(__file__)] 2964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cmd_line.extend(['--latclient', repr(kwargs)]) 2974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return subprocess.Popen(cmd_line) #, stdin=subprocess.PIPE, 2984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm #stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 2994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_latency_test(func, args, nthreads): 3014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Create a listening socket to receive the pings. We use UDP which should 3024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # be painlessly cross-platform. 3034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 3044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock.bind(("127.0.0.1", 0)) 3054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm addr = sock.getsockname() 3064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm interval = LATENCY_PING_INTERVAL 3084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm duration = LATENCY_DURATION 3094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nb_pings = int(duration / interval) 3104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = [] 3124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm threads = [] 3134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event = [] 3144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond = threading.Condition() 3154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm started = False 3164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if nthreads > 0: 3174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Warm up 3184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func(*args) 3194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = [] 3214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm loop = TimedLoop(func, args) 3224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready = [] 3234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond = threading.Condition() 3244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def run(): 3264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with ready_cond: 3274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready.append(None) 3284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond.notify() 3294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with start_cond: 3304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while not started: 3314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond.wait() 3324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm loop(start_time, duration * 1.5, end_event, do_yield=False) 3334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for i in range(nthreads): 3354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm threads.append(threading.Thread(target=run)) 3364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in threads: 3374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.setDaemon(True) 3384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.start() 3394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Wait for threads to be ready 3404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with ready_cond: 3414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while len(ready) < nthreads: 3424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond.wait() 3434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Run the client and wait for the first ping(s) to arrive before 3454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # unblocking the background threads. 3464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm chunks = [] 3474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm process = run_latency_client(addr=sock.getsockname(), 3484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nb_pings=nb_pings, interval=interval) 3494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm s = _recv(sock, 4096) 3504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _time = time.time 3514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with start_cond: 3534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_time = _time() 3544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm started = True 3554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond.notify(nthreads) 3564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while LAT_END not in s: 3584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm s = _recv(sock, 4096) 3594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t = _time() 3604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm chunks.append((t, s)) 3614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Tell the background threads to stop. 3634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event.append(None) 3644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in threads: 3654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.join() 3664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm process.wait() 3674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for recv_time, chunk in chunks: 3694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # NOTE: it is assumed that a line sent by a client wasn't received 3704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # in two chunks because the lines are very small. 3714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for line in chunk.splitlines(): 3724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm line = line.strip() 3734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if line and line != LAT_END: 3744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm send_time = eval(line) 3754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm assert isinstance(send_time, float) 3764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results.append((send_time, recv_time)) 3774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return results 3794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 3804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_latency_tests(max_threads): 3814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for task in latency_tasks: 3824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("Background CPU task:", task.__doc__) 3834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 3844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func, args = task() 3854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nthreads = 0 3864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while nthreads <= max_threads: 3874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = run_latency_test(func, args, nthreads) 3884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm n = len(results) 3894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # We print out milliseconds 3904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm lats = [1000 * (t2 - t1) for (t1, t2) in results] 3914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm #print(list(map(int, lats))) 3924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm avg = sum(lats) / n 3934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm dev = (sum((x - avg) ** 2 for x in lats) / n) ** 0.5 3944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("CPU threads=%d: %d ms. (std dev: %d ms.)" % (nthreads, avg, dev), end="") 3954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 3964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm #print(" [... from %d samples]" % n) 3974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nthreads += 1 3984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 3994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmBW_END = "END" 4024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef bandwidth_client(addr, packet_size, duration): 4044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 4054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock.bind(("127.0.0.1", 0)) 4064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm local_addr = sock.getsockname() 4074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _time = time.time 4084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep = time.sleep 4094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def _send_chunk(msg): 4104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sendto(sock, ("%r#%s\n" % (local_addr, msg)).rjust(packet_size), addr) 4114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # We give the parent some time to be ready. 4124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sleep(1.0) 4134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm try: 4144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_time = _time() 4154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_time = start_time + duration * 2.0 4164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i = 0 4174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while _time() < end_time: 4184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _send_chunk(str(i)) 4194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm s = _recv(sock, packet_size) 4204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm assert len(s) == packet_size 4214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm i += 1 4224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _send_chunk(BW_END) 4234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm finally: 4244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock.close() 4254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_bandwidth_client(**kwargs): 4274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cmd_line = [sys.executable, '-E', os.path.abspath(__file__)] 4284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cmd_line.extend(['--bwclient', repr(kwargs)]) 4294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return subprocess.Popen(cmd_line) #, stdin=subprocess.PIPE, 4304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm #stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 4314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_bandwidth_test(func, args, nthreads): 4334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Create a listening socket to receive the packets. We use UDP which should 4344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # be painlessly cross-platform. 4354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 4364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sock.bind(("127.0.0.1", 0)) 4374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm addr = sock.getsockname() 4384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm duration = BANDWIDTH_DURATION 4404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm packet_size = BANDWIDTH_PACKET_SIZE 4414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = [] 4434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm threads = [] 4444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event = [] 4454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond = threading.Condition() 4464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm started = False 4474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if nthreads > 0: 4484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Warm up 4494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func(*args) 4504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = [] 4524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm loop = TimedLoop(func, args) 4534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready = [] 4544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond = threading.Condition() 4554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm def run(): 4574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with ready_cond: 4584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready.append(None) 4594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond.notify() 4604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with start_cond: 4614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while not started: 4624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond.wait() 4634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm loop(start_time, duration * 1.5, end_event, do_yield=False) 4644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for i in range(nthreads): 4664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm threads.append(threading.Thread(target=run)) 4674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in threads: 4684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.setDaemon(True) 4694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.start() 4704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Wait for threads to be ready 4714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with ready_cond: 4724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while len(ready) < nthreads: 4734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm ready_cond.wait() 4744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Run the client and wait for the first packet to arrive before 4764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # unblocking the background threads. 4774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm process = run_bandwidth_client(addr=addr, 4784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm packet_size=packet_size, 4794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm duration=duration) 4804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _time = time.time 4814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # This will also wait for the parent to be ready 4824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm s = _recv(sock, packet_size) 4834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm remote_addr = eval(s.partition('#')[0]) 4844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm with start_cond: 4864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_time = _time() 4874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm started = True 4884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm start_cond.notify(nthreads) 4894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 4904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm n = 0 4914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm first_time = None 4924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while not end_event and BW_END not in s: 4934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm _sendto(sock, s, remote_addr) 4944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm s = _recv(sock, packet_size) 4954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if first_time is None: 4964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm first_time = _time() 4974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm n += 1 4984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_time = _time() 4994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm end_event.append(None) 5014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for t in threads: 5024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm t.join() 5034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm process.kill() 5044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return (n - 1) / (end_time - first_time) 5064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef run_bandwidth_tests(max_threads): 5084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm for task in bandwidth_tasks: 5094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("Background CPU task:", task.__doc__) 5104710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 5114710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm func, args = task() 5124710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nthreads = 0 5134710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm baseline_speed = None 5144710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm while nthreads <= max_threads: 5154710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm results = run_bandwidth_test(func, args, nthreads) 5164710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm speed = results 5174710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm #speed = len(results) * 1.0 / results[-1][0] 5184710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("CPU threads=%d: %.1f" % (nthreads, speed), end="") 5194710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if baseline_speed is None: 5204710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print(" packets/s.") 5214710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm baseline_speed = speed 5224710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm else: 5234710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print(" ( %d %%)" % (speed / baseline_speed * 100)) 5244710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm nthreads += 1 5254710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 5264710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5274710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5284710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmdef main(): 5294710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm usage = "usage: %prog [-h|--help] [options]" 5304710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser = OptionParser(usage=usage) 5314710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("-t", "--throughput", 5324710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store_true", dest="throughput", default=False, 5334710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help="run throughput tests") 5344710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("-l", "--latency", 5354710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store_true", dest="latency", default=False, 5364710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help="run latency tests") 5374710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("-b", "--bandwidth", 5384710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store_true", dest="bandwidth", default=False, 5394710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help="run I/O bandwidth tests") 5404710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("-i", "--interval", 5414710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store", type="int", dest="check_interval", default=None, 5424710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help="sys.setcheckinterval() value") 5434710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("-I", "--switch-interval", 5444710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store", type="float", dest="switch_interval", default=None, 5454710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help="sys.setswitchinterval() value") 5464710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("-n", "--num-threads", 5474710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store", type="int", dest="nthreads", default=4, 5484710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help="max number of threads in tests") 5494710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5504710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Hidden option to run the pinging and bandwidth clients 5514710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("", "--latclient", 5524710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store", dest="latclient", default=None, 5534710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help=SUPPRESS_HELP) 5544710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.add_option("", "--bwclient", 5554710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm action="store", dest="bwclient", default=None, 5564710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm help=SUPPRESS_HELP) 5574710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5584710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm options, args = parser.parse_args() 5594710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if args: 5604710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm parser.error("unexpected arguments") 5614710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5624710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.latclient: 5634710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm kwargs = eval(options.latclient) 5644710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm latency_client(**kwargs) 5654710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 5664710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5674710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.bwclient: 5684710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm kwargs = eval(options.bwclient) 5694710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm bandwidth_client(**kwargs) 5704710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm return 5714710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5724710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if not options.throughput and not options.latency and not options.bandwidth: 5734710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm options.throughput = options.latency = options.bandwidth = True 5744710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.check_interval: 5754710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sys.setcheckinterval(options.check_interval) 5764710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.switch_interval: 5774710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm sys.setswitchinterval(options.switch_interval) 5784710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5794710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("== %s %s (%s) ==" % ( 5804710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm platform.python_implementation(), 5814710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm platform.python_version(), 5824710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm platform.python_build()[0], 5834710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm )) 5844710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm # Processor identification often has repeated spaces 5854710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cpu = ' '.join(platform.processor().split()) 5864710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("== %s %s on '%s' ==" % ( 5874710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm platform.machine(), 5884710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm platform.system(), 5894710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm cpu, 5904710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm )) 5914710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 5924710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5934710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.throughput: 5944710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("--- Throughput ---") 5954710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 5964710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm run_throughput_tests(options.nthreads) 5974710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 5984710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.latency: 5994710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("--- Latency ---") 6004710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 6014710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm run_latency_tests(options.nthreads) 6024710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 6034710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm if options.bandwidth: 6044710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print("--- I/O bandwidth ---") 6054710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm print() 6064710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm run_bandwidth_tests(options.nthreads) 6074710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm 6084710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylmif __name__ == "__main__": 6094710c53dcad1ebf3755f3efb9e80ac24bd72a9b2darylm main() 610