QKD R10 V9.9999.8 performance tweaks

Recent changes in the QKD R10 V9.9999.8 omit unnecessary memory copies.
Added by Oliver Maurhart over 1 year ago

The last commit into the QKD R10 V9.9999.8 (ad90a8cc) - currently develop branch - introduces a huge transition into a more fine grain control over memory operations. Before working on key data and message data had the drawback, that the develop was not aware when and how held by the key and message objects has been copied. Indeed, any I/O operation involved at least a single memory copy. This has changed.

The current QKD R10 v9.9999.8 does no memory copy anymore when it is not requested. It does this via:

  • qkd::key::key is now a smart pointer to a qkd::key::key_instance. Keys are now created on the heap.
  • qkd::module::message is now a smart pointer to a qkd::module::message_instance. Peer-to-peer messages are now created on the heap.
  • Any key received from the previous module in a pipeline is not copied as long the developer does not call the data() method.
  • To enforce a const (non-copy) access to a message or key's data the additional const_data() method has been introduced.
  • The streaming operators for qkd::utility::buffer have been dropped and the push() and pop() methods have been renamed to write() and read(). Utilizing the stream operators on qkd::utility::buffer could cause easily memory copies. They have been removed without substitution.
  • Modules now declare themselves to be key modifying or not. A lot of helper modules do not modify the key content. Therefore it is an error to access the key content in a way which could cause key modifications. This is a safety net for the developers to not accidentally provoke unwanted key data memory copy operations.

Hence, these changes do break the API. V9.9999.8 is NOT source compatible to V9.9999.7 any more. As the "Changes" read:

Changes from 9.9999.7 to 9.9999.8

* qkd::key::key and qkd::module::message are now smart pointer to instance objects


    We turned qkd::key::key and qkd::module::message into smart pointers.

    That is:

        qkd::key::key           ---> std::shared_ptr<qkd::key::key_instance>
        qkd::module::message    ---> std::shared_ptr<qkd::module::message>

    Rationale: by operating all keys and messages on the heap we try to minimize
               memcpy operations in sending and receiving keys and messages from
               paired modules.

    Yes, this breaks old implementations. However, the benefit for a more faster
    system which deeply controls each and every memcpy of key and message material
    outweights this drawback. Sorry.

    You now have to ability to fine grain memcpy on key or message data content.
    Whenever you make a call to a possible data manipulation method the containing
    data in the key and message will be detached (memcpy!) if it is not uniquely

    That is: the containing memory area of the key and the message does have an
    internal reference count. Whenever a pointer to this data is requested which
    could lead to a write access the memory is copied whenever the reference count
    is bigger than 1.

    Example:        cKey = qkd::key::key();
                    cKey->data()[0] = 42;       // <-- memcpy here!

    To avoid this automatic memcpy we've added the 


    method in the qkd::key::key and qkd::module::message classes.

    The above example then renders:

    Example:        cKey = qkd::key::key();
                    char const * p = (char *)cKey->const_data();
                    if (p[0] == 42) {

    With this, we avoid memcpy opertions when they are not needed and speed up
    the qkd key post processing.

Sorry, but we think the effort is worthwhile.