Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 22 Dec 1999 16:09:55 -0800 (PST)
From:      Matthew Dillon <dillon@apollo.backplane.com>
To:        Jason Nordwick <nordwick@xcf.berkeley.edu>
Cc:        Jonathan Lemon <jlemon@americantv.com>, cmsedore@maxwell.syr.edu, hackers@FreeBSD.ORG
Subject:   Re: Practical limit for number of TCP connections? 
Message-ID:  <199912230009.QAA11643@apollo.backplane.com>
References:   <19991222234853.5770.qmail@scam.xcf.berkeley.edu>

next in thread | previous in thread | raw e-mail | index | archive | help
:>>it worked basically the same way on the kernel end.
:>
:>Yes, it is better.  Select uses the same backend as poll(), but those
:>"bit flag manipulations" that you are talking about consume a measurable
:>amount of CPU time when you start throwing thousands of descriptors at it.
:>--
:>Jonathan
:>
:
:I cannot believe that this is true.  It would seem, to me, that it is highly
:dependant on the density of the interest bit vector of select().  If it is
:very dense, then select is more appropriate.  Obviously, if you are only
:interested in fd# 5 and fd# 1000, then, yes, there is unecessary scanning.
:However is you are interested in 90% of the descriptors from 5 to 1000, then
:all the scanning is necessary.  (you can also, obviously, look through 32
:descriptors at a time).
:
:Also, doesn't the kernel need to copy the argument arrays into kernel space.
:A struct pollfd is 8 bytes per interested descriptor, whereas, select() only
:needs 1 bit per interested descriptor.  If I am interested in 1000 descriptors
:(assuming in a row), that is 8000 bytes to copyin, versus 125 bytes.
:
:Can somebody who knows better explain, please?
:
:-jason

    It's a real problem, actually.  I'll give you an example:  Generally 
    speaking every time you do a select() call with a thousand descriptors,
    the kernel must test and setup its wait on a thousand descriptors even
    if only one (or none) has pending data.

    The moment any single descriptor has data the entire select returns,
    you wind up processing the one descriptor, then reentering the select.

    The problem is that, typically, only one descriptor will have new data at
    a time (since, typically, the data coming in via your network is 
    serialized because you only have one network interface), which means that
    for light to medium loads you end up with O(N^2) of overhead (scanning 
    1000 descriptors each time one of them gets a hit).  Even though select()
    is fast and efficient by itself, the N-squaredness of the actual select
    activity results in significant (noticeable) overhead.

    Fortunately the problem is much reduced in heavy-load situations, since 
    more descriptors are likely to have data ready on them by the time your
    program gets around to calling select() again after processing the previous
    bunch.  Even so, select() is not ideal because it tends to plateu the
    cpu useage beyond a certain point - an ill-use of your available cpu.

    The typical solution to this problem is to design your program to be
    multi-fork/select - that is, you take the 1000 descriptors and you dole 
    them out to, say, 30 processes.  Each process select()s on only 33 
    descriptors, greatly reducing the order overhead of the algorithm.

    There is a second problem that programmers must be sure to avoid, and
    that is having multiple processes select()ing on the *same* descriptor
    (for example, a listen socket for accept).  Most select() implementations
    wind up waking up all the processes for every new connection (and, in
    fact, it could be argued that this is correct since you do not know what 
    any given process will do with the results from the select()).  One has
    the same problem when using multiple processes to select() on a single
    UDP socket for data.

					-Matt
					Matthew Dillon 
					<dillon@backplane.com>



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199912230009.QAA11643>