$include_dir="/home/hyper-archives/boost/include"; include("$include_dir/msg-header.inc") ?>
Subject: Re: [boost] Boost.Fiber review January 6-15
From: Niall Douglas (s_sourceforge_at_[hidden])
Date: 2014-01-10 11:36:57
On 7 Jan 2014 at 23:07, Oliver Kowalke wrote:
> my focus was to address the one-thread-per-client pattern used for C10K.
> the pattern makes code much more readable/reduces the complexity but
> doesn't scale. if you create too many threads on your system your
> overall performance will be shrink because at a certain number of threads,
> the overhead of the kernel scheduler starts to swamp the available cores. 
If you replace "doesn't scale" with "doesn't scale linearly" then I 
agree. The linearity is important.
> > I appreciate and understand this. However, I must then ask this: is
> > your library ready to enter Boost if you have not done any
> > performance testing or tuning?
> 
> is performance testing and tuning a precondition for a lib to be accepted?
No. I do think the question ought to be asked though, even if the 
answer is no. It helps people decide the relative merit of a new 
library.
> I did some tuning (for instance spinlock implementation) but it is not
> finished.
Even my own spinlock based on Intel TSX is unfinished - I had no TSX 
hardware to test it on, and had to rely on the Intel simulator which 
is dog slow.
I mentioned this in another reply, but I really think you ought to at 
least measure performance and supply some results in the docs. You 
don't need to performance tune, but it sure is handy to know some 
idea of performance.
> - io_service::post() pushes a callable to io_service's internal queue
> (executed by io_service::run() and related functions)
> - fibers::asio::spawn() creates a new fiber and adds it to the
> fiber-scheduler
>   (specialized to use asio's io_service hence asios's asyn-result feature)
> - yield is an instance of boost::fibers::asio::yield_context which
> represents the fiber
>   running this code; it is used by asio's async result feature
> - yield[ec] is put to an async-operation in order suspending the current
> fiber and pass an
>   error (if happend during execution of async-op) back to the calling code,
>   for instance EOF if socket was closed
Ok, let me try rewriting this description into my own words.
To supply fibers to an io_service, one creates N fibers each of which 
call io_service::run() as if they were threads. If there is no work 
available, the fiber executing the run() gives up context to the next 
fiber. If some fiber doing some work does an io_service::post(), that 
selects some fiber currently paused waiting inside run() for new 
work, and next context switch that fiber will be activated to do 
work.
This part I think I understand okay. The hard part for me is how 
yield() fits in. I get that one can call yield ordinarily like in 
Python
def foo:
  a=0
  while 1:
    a=a+1
    yield a
... and every time you call foo() you get back an increasing number.
Where I am finding things harder is what yield means to ASIO which 
takes a callback function of specification void (*callable)(const 
boost::system::error_code& error, size_t bytes_transferred) so fiber 
yield must supply a prototype matching that specification. You said 
above this:
> - yield is an instance of boost::fibers::asio::yield_context which
> represents the fiber running this code; it is used by asio's async result
> feature 
>
> - yield[ec] is put to an async-operation in order suspending the current
> fiber and pass an error (if happend during execution of async-op) back to
> the calling code, for instance EOF if socket was closed 
So I figure that yield will store somewhere a new bit of context, do 
a std::bind() encapsulating that context and hand off the functor to 
ASIO. ASIO then schedules the async i/o. When that completes, ASIO 
will do an io_service::post() with the bound functor, and so one of 
the fibers currently executing run() will get woken up and will 
invoke the bound functor.
So far so good. But here is where I fall down: the fibre receives in 
an error state and bytes transferred, and obviously transmits that 
back to the fiber which called ASIO async_read() by switching back to 
the original context. I would understand just fine if yield() 
suspended the calling fiber, but it surely cannot because yield() 
will get executed before ASIO async_read() does as it's a parameter 
to async_read(). So I therefore must be missing something very 
important, and this is why I am confused. Is it possible that yield() 
takes a *copy* of the context like setjmp()?
It's this kind of stuff which documentation is for, and why at least 
one person i.e. me needs hand holding through mentally groking how 
the ASIO support in Fiber works. Sorry for being a bit stupid.
Niall
-- Currently unemployed and looking for work. Work Portfolio: http://careers.stackoverflow.com/nialldouglas/