import optparse import os import select import socket import sys import time parser = optparse.OptionParser() parser.add_option("-r", dest='nb_ready', type=int, help="Number of ready FDs") parser.add_option("-m", dest='nb_max', type=int, help="Total number of FDs/highest FD") parser.add_option("-s", dest='sparse', default=False, action='store_true', help="Use sparse FDs allocation") parser.add_option("-t", dest='fd_type', default='socket', help="FD type ('socket', 'pipe', 'tty'") options, args = parser.parse_args() nb_ready = options.nb_ready nb_max = options.nb_max sparse = options.sparse fd_type = options.fd_type # prepare FDs and events events = [] if fd_type == 'socket': r, w = socket.socketpair() rd = os.dup(r.fileno()) wr = os.dup(w.fileno()) r.close() w.close() elif fd_type == 'tty': rd = os.dup(sys.stdin.fileno()) wr = os.dup(sys.stdout.fileno()) else: rd, wr = os.pipe() if sparse: # in sparse mode, only allocate ready FDs in the upper range print("Trying with {} FDs starting at {}, type {}".format(nb_ready, nb_max, fd_type)) for i in range(nb_max - nb_ready, nb_max): os.dup2(wr, i) events.append((i, select.SELECT_OUT)) else: # allocate ready and non ready FDs monotonically print("Trying with {} ready FDs out of {}, type {}".format(nb_ready, nb_max, fd_type)) for i in range(nb_max - nb_ready): events.append((os.dup(rd), select.SELECT_IN)) for i in range(nb_ready): events.append((os.dup(wr), select.SELECT_OUT)) os.close(rd) os.close(wr) # benchmark each implementation for selector in (select.EpollSelector, select.PollSelector, select.SelectSelector): print(selector) with selector() as s: # register events for fd, mask in events: s.register(fd, mask) t = time.perf_counter() for i in range(1024): ready = s.select() print(time.perf_counter() - t) for fd, mask in events: os.close(fd)