-
Notifications
You must be signed in to change notification settings - Fork 78
serialization performance improvements #361
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -432,6 +432,21 @@ class OMG_DDS_API cdr_stream { | |
*/ | ||
virtual bool finish_member(const entity_properties_t &props, member_id_set &member_ids, bool is_set = true); | ||
|
||
/** | ||
* @brief | ||
* Function declaration for finishing an existing member. | ||
* | ||
* This function is called by next_entity for each entity which is iterated over. | ||
* Depending on the implementation and mode header length fields may be completed. | ||
* This function can be overridden in cdr streaming implementations. | ||
* | ||
* @param[in] props Properties of the member to finish. | ||
* @param[in] is_set Whether the entity represented by prop is present, if it is an optional entity. | ||
* | ||
* @return Whether the operation was completed succesfully. | ||
*/ | ||
virtual bool finish_member_unchecked(const entity_properties_t &props, bool is_set = true); | ||
|
||
/** | ||
* @brief | ||
* Function declaration for retrieving the next entity to be operated on by the streamer. | ||
|
@@ -481,7 +496,20 @@ class OMG_DDS_API cdr_stream { | |
* | ||
* @return Whether the struct is complete and correct. | ||
*/ | ||
virtual bool finish_struct(const entity_properties_t &props, const member_id_set &member_ids); | ||
virtual bool finish_struct(const entity_properties_t &props, const member_id_set &member_ids) {return check_struct_completeness(props, member_ids);} | ||
|
||
/** | ||
* @brief | ||
* Function declaration for finishing a parameter list. | ||
* | ||
* This function is called by the generated functions for the entity, and will trigger the necessary actions on finishing the current struct. | ||
* I.E. finishing headers, writing length fields. | ||
* | ||
* @param[in] props The entity whose members might be represented by a parameter list. | ||
* | ||
* @return Whether the struct is complete and correct. | ||
*/ | ||
virtual bool finish_struct_unchecked(const entity_properties_t &props) {(void)props; return true;} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar reasoning to the I am cool with being wrong, mind 🙂 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yep, the explanation is included in the previous comment. |
||
|
||
/** | ||
* @brief | ||
|
@@ -941,6 +969,39 @@ bool max_string(S& str, const T& max_sz, size_t N) | |
return true; | ||
} | ||
|
||
/** | ||
* @brief | ||
* Sequence of base types read function. | ||
* | ||
* This is called when a resize + memcpy is way less efficient than an assign, | ||
* as this skips the default initialization of entities in the sequence. | ||
* | ||
* @param[in, out] str The stream being read from. | ||
* @param[in] toread The sequence being read into. | ||
* @param[in] N Number of base entities to read. | ||
* | ||
* @return Whether the operation was completed succesfully. | ||
*/ | ||
template<typename S, template<typename,typename> class V, typename T, typename A, std::enable_if_t<std::is_base_of<cdr_stream, S>::value && std::is_arithmetic<T>::value && !std::is_same<T,bool>::value, bool> = true > | ||
bool read(S& str, V<T,A> &toread, size_t N) | ||
{ | ||
if (str.position() == SIZE_MAX | ||
|| !str.align(sizeof(T), false) | ||
|| !str.bytes_available(sizeof(T)*N)) | ||
return false; | ||
|
||
auto ptr = reinterpret_cast<const T*>(str.get_cursor()); | ||
toread.assign(ptr, ptr+N); | ||
str.incr_position(N*sizeof(T)); | ||
|
||
if (str.swap_endianness()) { | ||
for (auto &e:toread) | ||
byte_swap(&e); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,7 +55,7 @@ bool xcdr_v1_stream::start_member(const entity_properties_t &prop, bool is_set) | |
return cdr_stream::start_member(prop, is_set); | ||
} | ||
|
||
bool xcdr_v1_stream::finish_member(const entity_properties_t &prop, member_id_set &member_ids, bool is_set) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I correct that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the functionality which was duplicated here is now absorbed into the base class's version of the function. |
||
bool xcdr_v1_stream::finish_member_unchecked(const entity_properties_t &prop, bool is_set) | ||
{ | ||
if (header_necessary(prop)) { | ||
switch (m_mode) { | ||
|
@@ -73,7 +73,7 @@ bool xcdr_v1_stream::finish_member(const entity_properties_t &prop, member_id_se | |
} | ||
|
||
pop_member_start(); | ||
return cdr_stream::finish_member(prop, member_ids, is_set); | ||
return cdr_stream::finish_member_unchecked(prop, is_set); | ||
} | ||
|
||
const entity_properties_t* xcdr_v1_stream::next_entity(const entity_properties_t *prop) | ||
|
@@ -288,7 +288,7 @@ bool xcdr_v1_stream::finish_write_header(const entity_properties_t &props) | |
return true; | ||
} | ||
|
||
bool xcdr_v1_stream::finish_struct(const entity_properties_t &props, const member_id_set &member_ids) | ||
bool xcdr_v1_stream::finish_struct_unchecked(const entity_properties_t &props) | ||
{ | ||
switch (m_mode) { | ||
case stream_mode::write: | ||
|
@@ -300,11 +300,8 @@ bool xcdr_v1_stream::finish_struct(const entity_properties_t &props, const membe | |
if (list_necessary(props)) | ||
return move_final_list_entry(); | ||
break; | ||
case stream_mode::read: | ||
return check_struct_completeness(props, member_ids); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I can't yet figure out how |
||
break; | ||
default: | ||
return false; | ||
break; | ||
} | ||
return true; | ||
} | ||
|
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.
So presumably the
_unchecked
refers to it not outputting a set of members that were completed successfully (themember_ids
) in the original one. I presume that for both functions the return value isfalse
iff some failure occurred, and that the nice bit of the non-unchecked
version is that you get more detailed information on what actually happened.Ok, that makes sense.
What I do wonder is if it would not make more sense to overload them? If the only difference is getting some additional information out, then it seems like that would more elegant and introduce less risk of head-scratching.
Would you agree?
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
_unchecked
versions of thefinish_member
andfinish_struct
functions do not check the member or struct for completeness (whether all members are present) when doing a streaming operation.These functions do the streaming steps when finishing a struct or a member, like reading/inserting headers etc.
The check for completeness is not necessary, unless reading a non-final extensibility struct, since there we have no control over the set of members present.
This check uses std::set as a container of the member ids that were read, and this was a significant performance drain, and therefore was split out for those datatype+streaming operation combinations that needed it.
Overloading is indeed an option, i will look in to this, this should also simplify the code generator.
Don't know why I overlooked this when writing this, probably went into this with a little too much C code attitude.