]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Tools/ccbench/ccbench.py
1 # -*- coding: utf-8 -*-
2 # This file should be kept compatible with both Python 2.6 and Python >= 3.0.
4 from __future__
import division
5 from __future__
import print_function
8 ccbench, a Python concurrency benchmark.
19 from optparse
import OptionParser
, SUPPRESS_HELP
30 except AttributeError:
34 THROUGHPUT_DURATION
= 2.0
36 LATENCY_PING_INTERVAL
= 0.1
37 LATENCY_DURATION
= 2.0
39 BANDWIDTH_PACKET_SIZE
= 1024
40 BANDWIDTH_DURATION
= 2.0
44 """Pi calculation (Python)"""
46 _count
= itertools
.count
47 _islice
= itertools
.islice
50 # From http://shootout.alioth.debian.org/
52 return _map(lambda k
: (k
, 4*k
+ 2, 0, 2*k
+ 1), _count(1))
64 return (q
*j
+ r
) // (s
*j
+ t
)
71 while y
!= extract(z
, 4):
72 z
= compose(z
, next(x
))
74 z
= compose((10, -10*y
, 0, 1), z
)
77 return list(_islice(pi_digits(), n
))
79 return calc_ndigits
, (50, )
82 """regular expression (C)"""
83 # XXX this task gives horrendous latency results.
85 # Taken from the `inspect` module
86 pat
= re
.compile(r
'^(\s*def\s)|(.*(?<!\w)lambda(:|\s))|^(\s*@)', re
.MULTILINE
)
87 with
open(__file__
, "r") as f
:
95 print(time
.time() - t
)
96 return pat
.findall
, (arg
, )
99 """list sorting (C)"""
104 return list_sort
, (list(range(1000)), )
106 def task_compress_zlib():
107 """zlib compression (C)"""
109 with
open(__file__
, "rb") as f
:
110 arg
= f
.read(5000) * 3
113 zlib
.decompress(zlib
.compress(s
, 5))
114 return compress
, (arg
, )
116 def task_compress_bz2():
117 """bz2 compression (C)"""
119 with
open(__file__
, "rb") as f
:
120 arg
= f
.read(3000) * 2
124 return compress
, (arg
, )
127 """SHA1 hashing (C)"""
129 with
open(__file__
, "rb") as f
:
130 arg
= f
.read(5000) * 30
133 hashlib
.sha1(s
).digest()
134 return compute
, (arg
, )
137 throughput_tasks
= [task_pidigits
, task_regex
]
138 for mod
in 'bz2', 'hashlib':
140 globals()[mod
] = __import__(mod
)
142 globals()[mod
] = None
144 # For whatever reasons, zlib gives irregular results, so we prefer bz2 or
145 # hashlib if available.
146 # (NOTE: hashlib releases the GIL from 2.7 and 3.1 onwards)
148 throughput_tasks
.append(task_compress_bz2
)
149 elif hashlib
is not None:
150 throughput_tasks
.append(task_hashing
)
152 throughput_tasks
.append(task_compress_zlib
)
154 latency_tasks
= throughput_tasks
155 bandwidth_tasks
= [task_pidigits
]
159 def __init__(self
, func
, args
):
163 def __call__(self
, start_time
, min_duration
, end_event
, do_yield
=False):
173 for i
in range(step
):
176 # If another thread terminated, the current measurement is invalid
177 # => return the previous one.
179 return niters
, duration
181 duration
= t2
- start_time
182 if duration
>= min_duration
:
183 end_event
.append(None)
184 return niters
, duration
186 # Minimize interference of measurement on overall runtime
189 # OS scheduling of Python threads is sometimes so bad that we
190 # have to force thread switching ourselves, otherwise we get
191 # completely useless results.
196 def run_throughput_test(func
, args
, nthreads
):
203 loop
= TimedLoop(func
, args
)
207 # Pure single-threaded performance, without any switching or
208 # synchronization overhead.
209 start_time
= time
.time()
210 results
.append(loop(start_time
, THROUGHPUT_DURATION
,
211 end_event
, do_yield
=False))
215 ready_cond
= threading
.Condition()
216 start_cond
= threading
.Condition()
226 results
.append(loop(start_time
, THROUGHPUT_DURATION
,
227 end_event
, do_yield
=True))
230 for i
in range(nthreads
):
231 threads
.append(threading
.Thread(target
=run
))
235 # We don't want measurements to include thread startup overhead,
236 # so we arrange for timing to start after all threads are ready.
238 while len(ready
) < nthreads
:
241 start_time
= time
.time()
243 start_cond
.notify(nthreads
)
249 def run_throughput_tests(max_threads
):
250 for task
in throughput_tasks
:
255 baseline_speed
= None
256 while nthreads
<= max_threads
:
257 results
= run_throughput_test(func
, args
, nthreads
)
258 # Taking the max duration rather than average gives pessimistic
259 # results rather than optimistic.
260 speed
= sum(r
[0] for r
in results
) / max(r
[1] for r
in results
)
261 print("threads=%d: %d" % (nthreads
, speed
), end
="")
262 if baseline_speed
is None:
263 print(" iterations/s.")
264 baseline_speed
= speed
266 print(" ( %d %%)" % (speed
/ baseline_speed
* 100))
273 def _sendto(sock
, s
, addr
):
274 sock
.sendto(s
.encode('ascii'), addr
)
277 return sock
.recv(n
).decode('ascii')
279 def latency_client(addr
, nb_pings
, interval
):
280 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
284 _sendto(sock
, "%r\n" % _time(), addr
)
285 # The first ping signals the parent process that we are ready.
287 # We give the parent a bit of time to notice.
289 for i
in range(nb_pings
):
292 _sendto(sock
, LAT_END
+ "\n", addr
)
294 def run_latency_client(**kwargs
):
295 cmd_line
= [sys
.executable
, '-E', os
.path
.abspath(__file__
)]
296 cmd_line
.extend(['--latclient', repr(kwargs
)])
297 return subprocess
.Popen(cmd_line
) #, stdin=subprocess.PIPE,
298 #stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
300 def run_latency_test(func
, args
, nthreads
):
301 # Create a listening socket to receive the pings. We use UDP which should
302 # be painlessly cross-platform.
303 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
304 sock
.bind(("127.0.0.1", 0))
305 addr
= sock
.getsockname()
307 interval
= LATENCY_PING_INTERVAL
308 duration
= LATENCY_DURATION
309 nb_pings
= int(duration
/ interval
)
314 start_cond
= threading
.Condition()
321 loop
= TimedLoop(func
, args
)
323 ready_cond
= threading
.Condition()
332 loop(start_time
, duration
* 1.5, end_event
, do_yield
=False)
334 for i
in range(nthreads
):
335 threads
.append(threading
.Thread(target
=run
))
339 # Wait for threads to be ready
341 while len(ready
) < nthreads
:
344 # Run the client and wait for the first ping(s) to arrive before
345 # unblocking the background threads.
347 process
= run_latency_client(addr
=sock
.getsockname(),
348 nb_pings
=nb_pings
, interval
=interval
)
349 s
= _recv(sock
, 4096)
355 start_cond
.notify(nthreads
)
357 while LAT_END
not in s
:
358 s
= _recv(sock
, 4096)
360 chunks
.append((t
, s
))
362 # Tell the background threads to stop.
363 end_event
.append(None)
368 for recv_time
, chunk
in chunks
:
369 # NOTE: it is assumed that a line sent by a client wasn't received
370 # in two chunks because the lines are very small.
371 for line
in chunk
.splitlines():
373 if line
and line
!= LAT_END
:
374 send_time
= eval(line
)
375 assert isinstance(send_time
, float)
376 results
.append((send_time
, recv_time
))
380 def run_latency_tests(max_threads
):
381 for task
in latency_tasks
:
382 print("Background CPU task:", task
.__doc
__)
386 while nthreads
<= max_threads
:
387 results
= run_latency_test(func
, args
, nthreads
)
389 # We print out milliseconds
390 lats
= [1000 * (t2
- t1
) for (t1
, t2
) in results
]
391 #print(list(map(int, lats)))
393 dev
= (sum((x
- avg
) ** 2 for x
in lats
) / n
) ** 0.5
394 print("CPU threads=%d: %d ms. (std dev: %d ms.)" % (nthreads
, avg
, dev
), end
="")
396 #print(" [... from %d samples]" % n)
403 def bandwidth_client(addr
, packet_size
, duration
):
404 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
405 sock
.bind(("127.0.0.1", 0))
406 local_addr
= sock
.getsockname()
409 def _send_chunk(msg
):
410 _sendto(sock
, ("%r#%s\n" % (local_addr
, msg
)).rjust(packet_size
), addr
)
411 # We give the parent some time to be ready.
415 end_time
= start_time
+ duration
* 2.0
417 while _time() < end_time
:
419 s
= _recv(sock
, packet_size
)
420 assert len(s
) == packet_size
426 def run_bandwidth_client(**kwargs
):
427 cmd_line
= [sys
.executable
, '-E', os
.path
.abspath(__file__
)]
428 cmd_line
.extend(['--bwclient', repr(kwargs
)])
429 return subprocess
.Popen(cmd_line
) #, stdin=subprocess.PIPE,
430 #stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
432 def run_bandwidth_test(func
, args
, nthreads
):
433 # Create a listening socket to receive the packets. We use UDP which should
434 # be painlessly cross-platform.
435 sock
= socket
.socket(socket
.AF_INET
, socket
.SOCK_DGRAM
)
436 sock
.bind(("127.0.0.1", 0))
437 addr
= sock
.getsockname()
439 duration
= BANDWIDTH_DURATION
440 packet_size
= BANDWIDTH_PACKET_SIZE
445 start_cond
= threading
.Condition()
452 loop
= TimedLoop(func
, args
)
454 ready_cond
= threading
.Condition()
463 loop(start_time
, duration
* 1.5, end_event
, do_yield
=False)
465 for i
in range(nthreads
):
466 threads
.append(threading
.Thread(target
=run
))
470 # Wait for threads to be ready
472 while len(ready
) < nthreads
:
475 # Run the client and wait for the first packet to arrive before
476 # unblocking the background threads.
477 process
= run_bandwidth_client(addr
=addr
,
478 packet_size
=packet_size
,
481 # This will also wait for the parent to be ready
482 s
= _recv(sock
, packet_size
)
483 remote_addr
= eval(s
.partition('#')[0])
488 start_cond
.notify(nthreads
)
492 while not end_event
and BW_END
not in s
:
493 _sendto(sock
, s
, remote_addr
)
494 s
= _recv(sock
, packet_size
)
495 if first_time
is None:
500 end_event
.append(None)
505 return (n
- 1) / (end_time
- first_time
)
507 def run_bandwidth_tests(max_threads
):
508 for task
in bandwidth_tasks
:
509 print("Background CPU task:", task
.__doc
__)
513 baseline_speed
= None
514 while nthreads
<= max_threads
:
515 results
= run_bandwidth_test(func
, args
, nthreads
)
517 #speed = len(results) * 1.0 / results[-1][0]
518 print("CPU threads=%d: %.1f" % (nthreads
, speed
), end
="")
519 if baseline_speed
is None:
521 baseline_speed
= speed
523 print(" ( %d %%)" % (speed
/ baseline_speed
* 100))
529 usage
= "usage: %prog [-h|--help] [options]"
530 parser
= OptionParser(usage
=usage
)
531 parser
.add_option("-t", "--throughput",
532 action
="store_true", dest
="throughput", default
=False,
533 help="run throughput tests")
534 parser
.add_option("-l", "--latency",
535 action
="store_true", dest
="latency", default
=False,
536 help="run latency tests")
537 parser
.add_option("-b", "--bandwidth",
538 action
="store_true", dest
="bandwidth", default
=False,
539 help="run I/O bandwidth tests")
540 parser
.add_option("-i", "--interval",
541 action
="store", type="int", dest
="check_interval", default
=None,
542 help="sys.setcheckinterval() value")
543 parser
.add_option("-I", "--switch-interval",
544 action
="store", type="float", dest
="switch_interval", default
=None,
545 help="sys.setswitchinterval() value")
546 parser
.add_option("-n", "--num-threads",
547 action
="store", type="int", dest
="nthreads", default
=4,
548 help="max number of threads in tests")
550 # Hidden option to run the pinging and bandwidth clients
551 parser
.add_option("", "--latclient",
552 action
="store", dest
="latclient", default
=None,
554 parser
.add_option("", "--bwclient",
555 action
="store", dest
="bwclient", default
=None,
558 options
, args
= parser
.parse_args()
560 parser
.error("unexpected arguments")
562 if options
.latclient
:
563 kwargs
= eval(options
.latclient
)
564 latency_client(**kwargs
)
568 kwargs
= eval(options
.bwclient
)
569 bandwidth_client(**kwargs
)
572 if not options
.throughput
and not options
.latency
and not options
.bandwidth
:
573 options
.throughput
= options
.latency
= options
.bandwidth
= True
574 if options
.check_interval
:
575 sys
.setcheckinterval(options
.check_interval
)
576 if options
.switch_interval
:
577 sys
.setswitchinterval(options
.switch_interval
)
579 print("== %s %s (%s) ==" % (
580 platform
.python_implementation(),
581 platform
.python_version(),
582 platform
.python_build()[0],
584 # Processor identification often has repeated spaces
585 cpu
= ' '.join(platform
.processor().split())
586 print("== %s %s on '%s' ==" % (
593 if options
.throughput
:
594 print("--- Throughput ---")
596 run_throughput_tests(options
.nthreads
)
599 print("--- Latency ---")
601 run_latency_tests(options
.nthreads
)
603 if options
.bandwidth
:
604 print("--- I/O bandwidth ---")
606 run_bandwidth_tests(options
.nthreads
)
608 if __name__
== "__main__":