[Ns-developers] [ns3] socket API
Tom Henderson
tomh at tomh.org
Tue Apr 15 10:10:09 PDT 2008
Mathieu,
I had a few questions about the efficiency points, inline below. They relate also to George's post yesterday.
>-----Original Message-----
>From: Mathieu Lacage [mailto:mathieu.lacage at sophia.inria.fr]
>Sent: Monday, April 14, 2008 01:37 PM
>To: 'ns-developers'
>Subject: [Ns-developers] [ns3] socket API
>
>hi,
>
>Trying to implement a synchronous socket API on top of the ns3 API
>turned out to be pretty useful, if only it showed some issues with the
>underlying async API. Tom and I talked about some of these issues on
>friday and I spent a while pondering over them and others so, here is a
>summary of the parts of the socket API which are missing to implement a
>full posix API on top. Some of the key issues I tried to address:
>
> - ability to implement a fully-conformant posix API on top
>
> - should make it possible to implement efficient versions of these
>APIs. i.e., implementations which do not copy packet data from the
>application to the socket layer.
>
> - allow the posix socket API to be extended with a version of
>functions which take Ptr<Packet>, to allow _really_ efficient
>synchronous applications which do not copy data from application to
>socket.
If I understand correctly, the efficiency goal here is to try to avoid buffer copies at the various APIs.
In the send direction, whether Send (Ptr<Packet>) or Send (const uint8_t* buf) is used does not matter; one copy into the packet buffer is performed in either case, and a fake buffer is supported similarly in either case.
In the receive direction, if you want to support recv/recvfrom semantics, the choices are Recv (..., Ptr<Packet>, ...) or Recv (..., uint8_t* buf, ...).
In the case of fake data, there is no efficiency difference because zero bytes are copied. In the case of real data, the use of the buf version requires a copy from Packet to buf. If you use the Recv (Ptr<Packet>) version, you can avoid this copy if you use Packet::PeekData(). Is this what you mean by _really_ efficient synchronous applications? Otherwise, it doesn't seem like the two variants differ in efficiency, for the common case.
There are also cases in which the Recv does not align with the Packet boundaries as Packets were delivered to the receive socket. For instance, in TCP, you may have a read that spans multiple packet (and packet Buffers). The application may also read less than what is available. In these cases, do you end up losing the _really_ efficient operation of the Ptr<Packet> version, when your read spans underlying Buffers?
In the case of a large read, wouldn't you have to create a new Packet that concatenated the underlying Buffers (and hence required a copy into this new Buffer)? If not, how would that work?
In the case of the small read, you may have multiple Packet objects pointing at the same Buffer, with differing offsets (m_start, m_end), so unless the read spans Buffers, then it seems like you can also avoid copies here.
So, in summary, it seems to me that the real issue is that in the receive direction, you may be able to get by in many (but not all) cases by effectively passing a pointer (to const) to the underlying Buffer up to the application, since the smart pointer semantics of Packet make this a safe operation. But if you use the "const uint8_t* buf" variant of recv, you always must copy into buf, from a memory management perspective. Is this an accurate summary?
- Tom
More information about the Ns-developers
mailing list