-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add functionality so Starcoder can send back arbitrary PMTs, not just blobs #78
Conversation
server/starcoder.go
Outdated
BlockId: blockName, | ||
Payload: bytes, | ||
}); err != nil { | ||
Pmt: message, |
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.
It looks like this code is duplicated above. Could this be made more DRY?
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.
Someone who knows C++ better than I do should also review this.
gr-starcoder/lib/pmt_to_proto.h
Outdated
|
||
void convert_pmt_to_proto(const pmt::pmt_t &pmt_msg, | ||
starcoder::BlockMessage *proto_msg); | ||
void convert_proto_uniform_vector(const pmt::pmt_t &pmt_msg, |
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.
It seems like this function is only used by convert_pmt_to_proto
and does not need to be exposes in a header file.
gr-starcoder/lib/pmt_to_proto.h
Outdated
#include <pmt/pmt.h> | ||
#include "starcoder.pb.h" | ||
|
||
void convert_pmt_to_proto(const pmt::pmt_t &pmt_msg, |
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.
Feel free to pass BlockMessage
back as a return value. I believe the compiler is smart enough to avoid copying an object when returning it (and actually this behavior is required by the language specification.)
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.
This is what I did first. The problem is the C++ generated protobuf has no way to set embedded message fields other than through getting a pointer to the embedded message field with the mutable_xxx()
method and directly modifying that pointer (there is no set_xxx()
method). See https://stackoverflow.com/questions/43268845/do-i-need-to-delete-objects-passed-to-google-protocol-buffer-protobuf. For the recursion to work, not sure if there's another way than having the function take a pointer.
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.
It seems you can call Swap()
on a mutable message. I haven't verified this API on my side and leave the decision up to you.
https://developers.google.com/protocol-buffers/docs/reference/cpp-generated#message
AMessageType parentMessage;
...
AMessageType submessage = convert_pmt_to_proto(...);
parentMessage.get_mutable_field()->Swap(&submessage);
....
return parentMessage;
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.
I guess this would work. Is there a specific reason to prefer returning the BlockMessage
?
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.
This is more or less a matter of personal preference so I left it up to you. But do you think it is more straightforward to return a value via a pointer argument than to use a return value? You wouldn't do it if you are programming in another language.
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.
Just for reference, found these about the protobuf move semantics. Not sure if copy when reallocating affects us
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.
FYI. No explicit move is needed in this case. Its optimization for returning a local variable from a function.
https://gist.github.com/kenichi-fukushima/197238e0cd23b82666a27abfa5fbd540
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.
@kenichi-fukushima Converted this to your suggested function signature. It does seem more intuitive to use.
gr-starcoder/lib/pmt_to_proto.cc
Outdated
const std::vector<std::complex<float>> vector_elements = | ||
pmt::c32vector_elements(pmt_msg); | ||
std::transform(vector_elements.begin(), vector_elements.end(), | ||
c32_vector->mutable_value()->begin(), |
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.
Don't you need to use a back inserter? Is it guaranteed that c32_vector
has enough buffer to store all transformed elements?
https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.repeated_field
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.
Okay, I modified it. Could you check if I did it correctly? Sorry, I don't fully understand STL containers yet...
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.
STL algorithms write to output iterators. And a vector's iterator is just the address of underlying memory buffer. So outputting to an iterator is no more than writing to a memory buffer. It won't change the container size, it won't reallocate the memory buffer if there is enough room.
gr-starcoder/lib/pmt_to_proto.cc
Outdated
const std::vector<std::complex<double>> vector_elements = | ||
pmt::c64vector_elements(pmt_msg); | ||
std::transform(vector_elements.begin(), vector_elements.end(), | ||
c64_vector->mutable_value()->begin(), |
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.
same as above
gr-starcoder/lib/pmt_to_proto.cc
Outdated
u_vector->set_size(starcoder::IntSize::Size8); | ||
const std::vector<uint8_t> vector_elements = | ||
pmt::u8vector_elements(pmt_msg); | ||
*u_vector->mutable_value() = { vector_elements.begin(), |
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.
My C++ knowledge hasn't been update for C++11 and I really don't know how initializer expressions work... Can you explain how this assignment works? My reasoning is the right hand side calls RepeatedPtrField::RepeatedPtrField(Iter begin, const Iter & end)
and then the whole content is copied for the another time, into the left hand side, which is redundant. You used transform
and an inserter below. Why this piece of code follows a different pattern?
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.
I changed it to use std::copy
. Wdyt?
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.
Looks good 👍
Adds functionality so Starcoder can send back arbitrary PMTs, not just data bytes. Instead of sending a serialized PMT, we convert it to the appropriate serialized Protobuf format and send it up the string queue.
We also introduce the Blob PMT. On the GNURadio side, this is equivalent to a uint8_vector, but since our protobuf maps the uint8_vector to a repeated uint32 field, it introduces a lot of overhead and necessitates weird conversion code when working with it from the gRPC side (e.g. converting
[]uint32
to[]byte
in Go).