-
Notifications
You must be signed in to change notification settings - Fork 85
Add simple zero copy support #83
base: master
Are you sure you want to change the base?
Conversation
Signed-off-by: Ondrej Kupka <[email protected]>
Zero-copy is pretty cool, nice to see you're having fun with it! I've got my hopes up :-) |
Oh yeah, a lot of fun :-) |
Tried the benchmarks from zmq_test.go, but cloned them and used ZeroCopySend instead of Send, for fun:
The differences are often very small, so I am not sure how much proving that is, but for large messages even this simply implementation shows some improvements I guess. Also the TCP tests are there more or less for fun, because I think that the TCP stack must have much more overhead that what we save with ZC on small messages... |
SendZeroCopy can be now places into the general zmq sources since the detection of libzmq version is happening at compile time. Signed-off-by: Ondrej Kupka <[email protected]>
Added a test for SendZeroCopy and also a few benchmarks to compare it with the regular Send function. The code of those benchmarks is probably not optimal yet, there is some code that was simply copy-pasted. Signed-off-by: Ondrej Kupka <[email protected]>
Signed-off-by: Ondrej Kupka <[email protected]>
Brb, it's completely broken now, I am too eager to send commits I guess... |
It looked like the implementation was in place, but it was completely forgotten to actually link the message buffer from Go to make sure it is not GC'd. This patch should fix this issue, []byte is finally correctly inserted into a map that is keeping it reachable from Go. Signed-off-by: Ondrej Kupka <[email protected]>
You're right, I got 3.2.3 mixed up with 3.3: http://api.zeromq.org/3-3:zmq-socket-monitor where this pointer issue is fixed. What do you think of sticking with the zeromq convention that the caller is responsible for providing the callback e.g. so that other resources associated with a message can be freed? It might be simpler than synchronizing access to a shared map since a near-empty callback can block GC on a slice. Nice work on the benchmarking btw. |
Good idea, I will try that. The only issue I am constantly fighting with is what is possible to do in CGO. Like very often passing callbacks between Go and C is not possible, many things are not possible. But I will do my best using casting and other regular brute methods ;-) |
Sorry, I am a bit out of time right now, will continue on this ASAP. I was just thinking... If we want to copy that |
In the previous patch the references to the frames sent using zero copy were kept internally by the library to make sure they are not GC'd. This patch drops this part and makes it the user's responsibility to take care of this. Signed-off-by: Ondrej Kupka <[email protected]>
Signed-off-by: Ondrej Kupka <[email protected]>
Hmm, I would need to rebase this so that Travis passes. Is that possible with GitHub or not? I can tell you that everything passed with Go 1.1 on my computer ;-) |
Signed-off-by: Ondrej Kupka <[email protected]>
Ah, cool, it rebases automatically. Travis passes now :-) |
Signed-off-by: Ondrej Kupka <[email protected]>
if (zmq_msg_init_data(&msg, data, dlen, gozmq_zc_free_fn, hint) == -1) | ||
return -1; | ||
|
||
#if ZMQ_VERSION_MAJOR == 3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API documentation for ZeroMQ 4.0 shows no incompatible change between 3 and 4 for this case. With #93 possibly coming in soon, would you consider allowing 4 here?
I just noticed this will only compile in Go 1.1 and up. That's not a problem for me, but maybe we can separate the 1.1-specific code into another file with build tag "go1.1". At least the use of ZCFrameBuffer in zmq_test.go, but maybe the ZCFrameBuffer type itself? |
Sounds reasonable to me. |
Hi, I am rather busy these days, but I will try to take a look. |
The simplest thing I managed to come up with is to simply remember the data still being used in a map in the Go part so that it's not GC'd. In the callback it's then enough to just delete the record in the map and we are done. Unfortunately there is some synchronization needed, creating a possible bottleneck, but who knows, maybe not. And it's locking in the callback, so I don't know what scenario would really break this down. It should be fine and enough.
As an improvement it could be possible to simply pass the key as the integer, i.e. don't malloc space for the integer and pass the pointer, but simply cast the integer to pointer and pass that one...
I also don't like the global state in the Go module, I will think about it a bit more, if it is possible to get rid of that. I don't think that you can possibly manage to fill the map with ID's even if you use several contexts, but it's just ugly...
Btw tests and other stuff left out for now, we should first get this into a usable state and then take care of the rest I think.
In fact I haven't even tried to run it, just to compile it :P
Signed-off-by: Ondrej Kupka [email protected]