PEP 433: add test scripts; performances results on Linux 3.6
This commit is contained in:
parent
d5f14bd374
commit
74a6f4b364
15
pep-0433.txt
15
pep-0433.txt
|
@ -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
|
||||
|
|
|
@ -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))
|
|
@ -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)
|
Loading…
Reference in New Issue