PEP 433: add test scripts; performances results on Linux 3.6

This commit is contained in:
Victor Stinner 2013-01-27 13:35:21 +01:00
parent d5f14bd374
commit 74a6f4b364
3 changed files with 88 additions and 4 deletions

View File

@ -143,9 +143,8 @@ the kernel ignores ``O_CLOEXEC`` or ``SOCK_CLOEXEC`` flag, a call to
.. note::
OpenBSD older 5.2 does not close the file descriptor with
close-on-exec flag set if ``fork()`` is used before ``exec()``, but
it works correctly if ``exec()`` is called without ``fork()``.
XXX recheck this OpenBSD bug using a C program. XXX
it works correctly if ``exec()`` is called without ``fork()``. Try
`openbsd_bug.py <http://hg.python.org/peps/file/tip/pep-0433/openbsd_bug.py>`_.
Scope
@ -446,7 +445,15 @@ calls depends on the method used to set the flag:
* ``fcntl(fd, F_SETFD, flags)``: two addition system calls per file
descriptor, one to get old flags and one to set new flags
XXX Benchmark the overhead for these 4 methods. XXX
On Linux, setting the close-on-flag has a low overhead on performances.
Results of
`bench_cloexec.py <http://hg.python.org/peps/file/tip/pep-0433/bench_cloexec.py>`_
on Linux 3.6:
* close-on-flag not set: 7.8 us
* ``O_CLOEXEC``: 1% slower (7.9 us)
* ``ioctl()``: 3% slower (8.0 us)
* ``fcntl()``: 3% slower (8.0 us)
Implementation

45
pep-0433/bench_cloexec.py Normal file
View File

@ -0,0 +1,45 @@
"""
Linux 3.6, O_CLOEXEC:
open(cloexec=False) + close(): 7.76 us per call
open(cloexec=True) + close(): 7.87 us per call
=> 1% slower
Linux 3.6, ioctl(FIOCLEX):
open(cloexec=False) + close(): 7.77 us per call
open(cloexec=True) + close(): 8.02 us per call
=> 3% slower
Linux 3.6, fnctl(F_GETFD) + fnctl(F_SETFD):
open(cloexec=False) + close(): 7.77 us per call
open(cloexec=True) + close(): 8.01 us per call
=> 3% slower
"""
import os, time
name = __file__
LOOPS = 10**5
RUNS = 5
for cloexec in (False, True):
best = None
for run in range(RUNS):
print("cloexec", cloexec, "run", run)
time.sleep(1)
start = time.perf_counter()
for loops in range(LOOPS):
fd = os.open(name, os.O_RDONLY, cloexec=cloexec)
os.close(fd)
dt = time.perf_counter() - start
if best is not None:
best = min(best, dt)
else:
best = dt
seconds = best / LOOPS
print("open(cloexec=%s) + close(): %.2f us per call" % (cloexec, seconds * 1e6))

32
pep-0433/openbsd_bug.py Normal file
View File

@ -0,0 +1,32 @@
# Script testing an OpenBSD bug
#
# The script fails with "OS BUG!!!" with OpenBSD older than 5.2.
# It works on any version using USE_FORK = False.
USE_FORK = True
import fcntl, os, sys
fd = os.open("/etc/passwd", os.O_RDONLY)
flags = fcntl.fcntl(fd, fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(fd, fcntl.F_SETFD, flags)
code = """
import os, sys
fd = int(sys.argv[1])
try:
os.fstat(fd)
except OSError:
print("fd %s closed by exec (FD_CLOEXEC works)" % fd)
else:
print("fd %s not closed by exec: FD_CLOEXEC doesn't work, OS BUG!!!" % fd)
"""
args = [sys.executable, '-c', code, str(fd)]
if USE_FORK:
pid = os.fork()
if pid:
os.waitpid(pid, 0)
sys.exit(0)
os.execv(args[0], args)