Skip to content

Commit

Permalink
Core / ZeroCopy: Added Doxygen API documentation and 2 new c++ sample…
Browse files Browse the repository at this point in the history
…s demonstrating usage of low level zero copy API (#1145)

Co-authored-by: Florian Reimold <[email protected]>
  • Loading branch information
rex-schilasky and FlorianReimold authored Jul 31, 2023
1 parent 50699d8 commit 942f01d
Show file tree
Hide file tree
Showing 8 changed files with 435 additions and 31 deletions.
134 changes: 109 additions & 25 deletions ecal/core/include/ecal/ecal_payload_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,56 +29,140 @@

namespace eCAL
{
// base payload writer class to allow zero copy memory operations
//
// the `Write`and `Update` calls may operate on the target memory file directly (zero copy mode)
/**
* @brief Base payload writer class to allow zero copy memory operations.
*
* This class serves as the base class for payload writers, allowing zero-copy memory
* operations. The `Write` and `Update` calls may operate on the target memory file
* directly in zero-copy mode.
*/
class CPayloadWriter
{
public:
/**
* @brief Default constructor for CPayloadWriter.
*/
CPayloadWriter() = default;

/**
* @brief Virtual destructor for CPayloadWriter.
*/
virtual ~CPayloadWriter() = default;

CPayloadWriter(const CPayloadWriter &) = default;
CPayloadWriter(CPayloadWriter &&) = default;
/**
* @brief Copy constructor (deleted).
*/
CPayloadWriter(const CPayloadWriter&) = default;

/**
* @brief Move constructor (deleted).
*/
CPayloadWriter(CPayloadWriter&&) = default;

/**
* @brief Copy assignment operator (deleted).
*/
CPayloadWriter& operator=(const CPayloadWriter&) = default;

CPayloadWriter& operator=(const CPayloadWriter &) = default;
CPayloadWriter& operator=(CPayloadWriter &&) = default;
/**
* @brief Move assignment operator (deleted).
*/
CPayloadWriter& operator=(CPayloadWriter&&) = default;

// the provisioned memory is uninitialized ->
// perform a full write operation
/**
* @brief Perform a full write operation with uninitialized memory.
*
* This virtual function allows derived classes to perform a full write operation
* when the provisioned memory is uninitialized.
*
* @param buffer_ Pointer to the buffer containing the data to be written.
* @param size_ Size of the data to be written.
*
* @return True if the write operation is successful, false otherwise.
*/
virtual bool Write(void* buffer_, size_t size_) = 0;

// the provisioned memory is initialized and contains the data from the last write operation ->
// perform a partial write operation or just modify a few bytes here
//
// by default this operation will just call `Write`
/**
* @brief Perform a partial write operation or modify existing data.
*
* This virtual function allows derived classes to perform a partial write operation
* or modify existing data when the provisioned memory is already initialized and
* contains the data from the last write operation. By default, this operation will
* just call the `Write` function.
*
* @param buffer_ Pointer to the buffer containing the data to be written or modified.
* @param size_ Size of the data to be written or modified.
*
* @return True if the write/update operation is successful, false otherwise.
*/
virtual bool Update(void* buffer_, size_t size_) { return Write(buffer_, size_); };

// provide the size of the required memory (eCAL needs to allocate for you).
/**
* @brief Get the size of the required memory.
*
* This virtual function allows derived classes to provide the size of the memory
* that eCAL needs to allocate.
*
* @return The size of the required memory.
*/
virtual size_t GetSize() = 0;
};

// payload writer class that wraps classic (void*, size_t) interface
/**
* @brief Payload writer class that wraps a classic (void*, size_t) interface.
*
* This class is a payload writer that wraps a classic interface using `void*` and `size_t`
* arguments. It inherits from the base class CPayloadWriter, allowing zero-copy memory
* operations.
*/
class CBufferPayloadWriter : public CPayloadWriter
{
public:
/**
* @brief Constructor for CBufferPayloadWriter.
*
* @param buffer_ Pointer to the buffer containing the data to be written.
* @param size_ Size of the data to be written.
*/
CBufferPayloadWriter(const void* const buffer_, size_t size_) : m_buffer(buffer_), m_size(size_) {};

// make a dump memory copy
bool Write (void* buffer_, size_t size_) override {
if (buffer_ == nullptr) return false;
if (size_ < m_size) return false;
/**
* @brief Make a dump memory copy of the stored buffer.
*
* This function performs a dump memory copy of the stored buffer to the provided
* memory location (buffer_) with the specified size (size_). The size of the provided
* memory buffer should be equal to or greater than the stored buffer size to avoid
* memory corruption.
*
* @param buffer_ Pointer to the target buffer where the data will be copied.
* @param size_ Size of the target buffer.
*
* @return True if the copy operation is successful, false otherwise.
*/
bool Write(void* buffer_, size_t size_) override
{
if (buffer_ == nullptr) return false;
if (size_ < m_size) return false;
if (m_buffer == nullptr) return false;
if (m_size == 0) return false;
if (m_size == 0) return false;
memcpy(buffer_, m_buffer, m_size);
return true;
}

// size of the memory that needs to be copied
/**
* @brief Get the size of the memory that needs to be copied.
*
* This function returns the size of the memory buffer that needs to be copied during
* the write operation. It is used by the base class CPayloadWriter to allocate the
* required memory for eCAL.
*
* @return The size of the memory that needs to be copied.
*/
size_t GetSize() override { return m_size; };

private:
const void* m_buffer = nullptr;
size_t m_size = 0;
const void* m_buffer = nullptr; ///< Pointer to the buffer containing the data to be written.
size_t m_size = 0; ///< Size of the data to be written.
};
}

} // namespace eCAL
4 changes: 3 additions & 1 deletion samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,10 @@ add_subdirectory(cpp/orchestration/component2)
add_subdirectory(cpp/orchestration/orchestrator)

# pubsub
add_subdirectory(cpp/pubsub/binary/binary_rec_cb)
add_subdirectory(cpp/pubsub/binary/binary_rec)
add_subdirectory(cpp/pubsub/binary/binary_snd)
add_subdirectory(cpp/pubsub/binary/binary_zero_copy_rec)
add_subdirectory(cpp/pubsub/binary/binary_zero_copy_snd)
add_subdirectory(cpp/pubsub/binary/ping)
add_subdirectory(cpp/pubsub/binary/pong)
if(HAS_CAPNPROTO)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ cmake_minimum_required(VERSION 3.10)

set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)

project(binary_rec_cb)
project(binary_rec)

find_package(eCAL REQUIRED)

set(binary_rec_cb_src
src/binary_rec_cb.cpp
set(binary_rec_src
src/binary_rec.cpp
)

ecal_add_sample(${PROJECT_NAME} ${binary_rec_cb_src})
ecal_add_sample(${PROJECT_NAME} ${binary_rec_src})

target_link_libraries(${PROJECT_NAME} eCAL::core)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ void OnReceive(const char* /*topic_name_*/, const struct eCAL::SReceiveCallbackD
int main(int argc, char** argv)
{
// initialize eCAL API
eCAL::Initialize(argc, argv, "binary_rec_cb");
eCAL::Initialize(argc, argv, "binary_rec");

// subscriber for topic "blob"
eCAL::CSubscriber sub("blob");
Expand Down
38 changes: 38 additions & 0 deletions samples/cpp/pubsub/binary/binary_zero_copy_rec/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ========================= eCAL LICENSE =================================
#
# Copyright (C) 2016 - 2019 Continental Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ========================= eCAL LICENSE =================================

cmake_minimum_required(VERSION 3.10)

project(binary_zero_copy_rec)

# set project properties
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
set(binary_zero_copy_rec_src src/binary_zero_copy_rec.cpp)

# find packages
message("-- Checking for modules 'eCAL'")
find_package(eCAL REQUIRED)

# add and configure sample project
ecal_add_sample(${PROJECT_NAME} ${binary_zero_copy_rec_src})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14)
target_link_libraries(${PROJECT_NAME} eCAL::core)

# install and set properties
ecal_install_sample(${PROJECT_NAME})
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER samples/cpp/pubsub/binary)
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* ========================= eCAL LICENSE =================================
*
* Copyright (C) 2016 - 2019 Continental Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================= eCAL LICENSE =================================
*/

#include <ecal/ecal.h>

#include <iostream>
#include <chrono>
#include <sstream>
#include <thread>

// a simple struct to demonstrate
// zero copy modifications
struct alignas(4) SSimpleStruct
{
uint32_t version = 1;
uint16_t rows = 5;
uint16_t cols = 3;
uint32_t clock = 0;
uint8_t bytes[5 * 3] = { 0 };
};

// SSimpleStruct logging
std::ostream& operator<<(std::ostream& os, const SSimpleStruct& s)
{
os << "Version : " << s.version << std::endl;
os << "Rows : " << s.rows << std::endl;
os << "Cols : " << s.cols << std::endl;
os << "Clock : " << s.clock << std::endl;

os << "Bytes : " << std::endl;
for (int i = 0; i < s.rows; ++i) {
for (int j = 0; j < s.cols; ++j) {
os << static_cast<int>(s.bytes[i * s.cols + j]) << " ";
}
os << std::endl;
}
return os;
}

// subscriber callback function
void OnReceive(const char* /*topic_name_*/, const struct eCAL::SReceiveCallbackData* data_)
{
if (data_->size < 1) return;

std::cout << "------------------------------------" << std::endl;
std::cout << "Binary buffer header :" << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << " Size : " << data_->size << std::endl;
std::cout << " Id : " << data_->id << std::endl;
std::cout << " Time : " << data_->time << std::endl;
std::cout << " Clock : " << data_->clock << std::endl;
std::cout << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << "SSimpleStruct :" << std::endl;
std::cout << "------------------------------------" << std::endl;
std::cout << *static_cast<SSimpleStruct*>(data_->buf) << std::endl;
}

int main(int argc, char** argv)
{
const char* nodeName = "binary_zero_copy_rec";
const char* topicName = "simple_struct";

// initialize eCAL API
eCAL::Initialize(argc, argv, nodeName);

// create the subscriber
eCAL::CSubscriber sub(topicName);

// assign callback
sub.AddReceiveCallback(OnReceive);

// idle main loop
while (eCAL::Ok()) std::this_thread::sleep_for(std::chrono::milliseconds(500));

// finalize eCAL API
eCAL::Finalize();

return 0;
}
38 changes: 38 additions & 0 deletions samples/cpp/pubsub/binary/binary_zero_copy_snd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ========================= eCAL LICENSE =================================
#
# Copyright (C) 2016 - 2019 Continental Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# ========================= eCAL LICENSE =================================

cmake_minimum_required(VERSION 3.10)

project(binary_zero_copy_snd)

# set project properties
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
set(binary_zero_copy_snd_src src/binary_zero_copy_snd.cpp)

# find packages
message("-- Checking for modules 'eCAL'")
find_package(eCAL REQUIRED)

# add and configure sample project
ecal_add_sample(${PROJECT_NAME} ${binary_zero_copy_snd_src})
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_14)
target_link_libraries(${PROJECT_NAME} eCAL::core)

# install and set properties
ecal_install_sample(${PROJECT_NAME})
set_property(TARGET ${PROJECT_NAME} PROPERTY FOLDER samples/cpp/pubsub/binary)
Loading

0 comments on commit 942f01d

Please sign in to comment.