:>>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
<[EMAIL PROTECTED]>
To Unsubscribe: send mail to [EMAIL PROTECTED]
with "unsubscribe freebsd-hackers" in the body of the message