
Christopher Kohlhoff wrote:
Hi Rene,
In my first reply to your review I outlined a proposal for custom memory allocation. I have now implemented enough of it to re-run your test program (updated program and results attached).
OK.
--- Rene Rivera <grafik.list@redshift-software.com> wrote:
I ran the same 100,000*1K*6*2*3 tests with both debug and release compiled code. As can be seen from the attached output in the best case, of release code, there is a 5.6% "overhead" from the async to sync cases.
Machine specs: 1.7GHz Pentium M, 512MB RAM, Windows XP SP2. Compiler: VC8 Express.
First, without custom memory allocation a typical run of the program made approximately 340000 calls to new. With my custom memory allocation there were just 80.
Much better :-)
In the release build async calls were marginally slower, but the difference was less than 1%.
For the debug code the difference is a more dramatic 25.2%.
Even though a debug build is not really relevant for performance
Of course... I was being as complete as possible.
In my continue reading and use of the code I concluded that the basic design flaw is that the underlying *socket_service classes are not available as a public interface.
I don't understand how not exposing the implementation details is a design flaw.
You might consider it an implementation detail. But depending on the context it might not be considered a detail. At minimum, in this case, I would expect to be able to choose which implementation to use. And in some situations I might want to make that choice at runtime, not just compile time. For example some would consider the std::deque<T> container behind an std::stack<T> to be an implementation detail. But I might want to use a circular_deque<T> instead, for those cases where I want to make certain memory guarantees. After all it's how we draw the abstraction line that we worry so much about in Boost. In this case I think you've drawn the line too far up preventing some alternate uses of your library.
Another restriction that this causes is that the various OS handling models are not available as individual handling types. Hence, for example on Linux, it is not possible to choose at runtime whether one should use epoll, kqueue, or select.
The stated intention is to use the most scalable event demultiplexer offered by a platform.
Sure, but scalability is a contextual measure. In my use case the scalability is not measured in how many connections are handled at once since my connections are all virtual and is only limited by bandwidth and protocol limits.
Furthermore, runtime polymorphism is likely to limit the opportunity for optimisation. E.g. the custom allocation strategy I have implemented works because the user handler types have not been erased.
I didn't realize I implied runtime polymorphism. I was only thinking of the simple ability to create different kinds of clients/servers based the OS signaling method. It's not possible right now since one can't instantiate in a type safe manner different datagram_socket_service variants. for example.
I'd be interested to know whether you, or others, find this custom memory allocation interface satisfactory.
It's OK. It solves the allocation problem, but not the reuse problems. -- -- Grafik - Don't Assume Anything -- Redshift Software, Inc. - http://redshift-software.com -- rrivera/acm.org - grafik/redshift-software.com -- 102708583/icq - grafikrobot/aim - Grafik/jabber.org