From d1f446e5e91df5b8384d564f3e3e716d575a38e3 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Mon, 16 Dec 2024 17:02:30 -0800 Subject: [PATCH 01/14] Add UUID generator based on two MT19937 pseudo-random number generators seeded by true randomness. --- benchmarks/uuid_generator.cpp | 32 ++++++++++++++++++++++++++++++++ catkit_core/CMakeLists.txt | 1 + catkit_core/UuidGenerator.cpp | 21 +++++++++++++++++++++ catkit_core/UuidGenerator.h | 17 +++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 benchmarks/uuid_generator.cpp create mode 100644 catkit_core/UuidGenerator.cpp create mode 100644 catkit_core/UuidGenerator.h diff --git a/benchmarks/uuid_generator.cpp b/benchmarks/uuid_generator.cpp new file mode 100644 index 00000000..bb2879cf --- /dev/null +++ b/benchmarks/uuid_generator.cpp @@ -0,0 +1,32 @@ +#include "UuidGenerator.h" +#include "Timing.h" + +#include + +int main() +{ + const size_t N = 100000000; + + UuidGenerator generator; + + char uuid[16]; + + std::cout << std::hex; + + auto start = GetTimeStamp(); + + for (size_t i = 0; i < N; ++i) + { + generator.GenerateUuid(uuid); + } + + auto end = GetTimeStamp(); + + std::cout << std::dec; + + std::cout << "Time: " << (end - start) / 1e9 << " sec" << std::endl; + std::cout << "Throughput: " << N / ((end - start) / 1e9) << " ops/s" << std::endl; + std::cout << "Time per operation: " << (end - start) / N << " ns" << std::endl; + + return 0; +} diff --git a/catkit_core/CMakeLists.txt b/catkit_core/CMakeLists.txt index 6258d432..360db308 100644 --- a/catkit_core/CMakeLists.txt +++ b/catkit_core/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(catkit_core STATIC Util.cpp PoolAllocator.cpp FreeListAllocator.cpp + UuidGenerator.cpp proto/core.pb.cc proto/logging.pb.cc proto/testbed.pb.cc diff --git a/catkit_core/UuidGenerator.cpp b/catkit_core/UuidGenerator.cpp new file mode 100644 index 00000000..ea68bcaf --- /dev/null +++ b/catkit_core/UuidGenerator.cpp @@ -0,0 +1,21 @@ +#include "UuidGenerator.h" + +UuidGenerator::UuidGenerator() +{ + std::random_device random_device; + + for (size_t i = 0; i < 2; ++i) + { + std::seed_seq seed{random_device(), random_device()}; + m_Engines[i].seed(seed); + } +} + +void UuidGenerator::GenerateUuid(char *uuid) +{ + for (size_t i = 0; i < 2; ++i) + { + std::uint64_t value = m_Engines[i](); + *reinterpret_cast(uuid + i * 8) = value; + } +} diff --git a/catkit_core/UuidGenerator.h b/catkit_core/UuidGenerator.h new file mode 100644 index 00000000..244b828d --- /dev/null +++ b/catkit_core/UuidGenerator.h @@ -0,0 +1,17 @@ +#ifndef UUID_GENERATOR_H +#define UUID_GENERATOR_H + +#include + +class UuidGenerator +{ +public: + UuidGenerator(); + + void GenerateUuid(char *uuid); + +private: + std::mt19937_64 m_Engines[2]; +}; + +#endif // UUID_GENERATOR_H From 7019b868a9eed314b35aa9812b3b72858ffb20d8 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Mon, 16 Dec 2024 17:08:43 -0800 Subject: [PATCH 02/14] Add interface for Cuda shared memory. --- catkit_core/CudaSharedMemory.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 catkit_core/CudaSharedMemory.h diff --git a/catkit_core/CudaSharedMemory.h b/catkit_core/CudaSharedMemory.h new file mode 100644 index 00000000..98899e2d --- /dev/null +++ b/catkit_core/CudaSharedMemory.h @@ -0,0 +1,28 @@ +#ifndef CUDA_SHARED_MEMORY_H +#define CUDA_SHARED_MEMORY_H + +#include + +#ifdef HAVE_CUDA +#include +typedef cudaIpcMemHandle_t CudaIpcHandle; +#else +// CUDA cudaIpcMemHandle_t is a struct of 64 bytes. +typedef char CudaIpcHandle[64]; +#endif + +class CudaSharedMemory +{ +private: + CudaSharedMemory(const CudaIpcHandle &ipc_handle, void *device_pointer=nullptr); + +public: + ~CudaSharedMemory(); + + static std::shared_ptr Create(size_t num_bytes_in_buffer); + static std::shared_ptr Open(const CudaIpcHandle &ipc_handle); + + void *GetAddress(); +}; + +#endif // CUDA_SHARED_MEMORY_H From 7e532d77e99a277cbf13c008ddaec272e002dda5 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Mon, 16 Dec 2024 17:09:20 -0800 Subject: [PATCH 03/14] Add rough layout for message broker. --- catkit_core/CMakeLists.txt | 1 + catkit_core/MessageBroker.cpp | 2 + catkit_core/MessageBroker.h | 136 ++++++++++++++++++++++++++++++++++ 3 files changed, 139 insertions(+) create mode 100644 catkit_core/MessageBroker.cpp create mode 100644 catkit_core/MessageBroker.h diff --git a/catkit_core/CMakeLists.txt b/catkit_core/CMakeLists.txt index 360db308..7afde58a 100644 --- a/catkit_core/CMakeLists.txt +++ b/catkit_core/CMakeLists.txt @@ -35,6 +35,7 @@ add_library(catkit_core STATIC Util.cpp PoolAllocator.cpp FreeListAllocator.cpp + MessageBroker.cpp UuidGenerator.cpp proto/core.pb.cc proto/logging.pb.cc diff --git a/catkit_core/MessageBroker.cpp b/catkit_core/MessageBroker.cpp new file mode 100644 index 00000000..2983c90e --- /dev/null +++ b/catkit_core/MessageBroker.cpp @@ -0,0 +1,2 @@ +#include "MessageBroker.h" + diff --git a/catkit_core/MessageBroker.h b/catkit_core/MessageBroker.h new file mode 100644 index 00000000..b96c563f --- /dev/null +++ b/catkit_core/MessageBroker.h @@ -0,0 +1,136 @@ +#ifndef MESSAGE_BROKER_H +#define MESSAGE_BROKER_H + +#include "HashMap.h" +#include "Synchronization.h" +#include "FreeListAllocator.h" +#include "PoolAllocator.h" +#include "SharedMemory.h" +#include "CudaSharedMemory.h" +#include "UuidGenerator.h" + +const char * const MESSAGE_BROKER_VERSION = "0.1"; + +const size_t VERSION_SIZE = 8; +const size_t TOPIC_HASH_MAP_SIZE = 16384; +const size_t TOPIC_MAX_KEY_SIZE = 128; +const size_t TOPIC_MAX_NUM_MESSAGES = 15; +const size_t HOST_NAME_SIZE = 64; +const size_t METADATA_MAX_STRLEN = 15; +const size_t UUID_SIZE = 16; +const size_t MAX_NUM_DIMENSIONS = 4; +const size_t MAX_NUM_METADATA_ENTRIES = 16; +const size_t MAX_SHARED_MEMORY_ID_SIZE = 64; +const size_t MAX_NUM_GPUS = 8; + +struct MetadataEntry +{ +// Avoid post-padding of this anonymous union. +#pragma pack(push,1) + union + { + std::uint64_t integer; + double floating_point; + char string[METADATA_MAX_STRLEN]; + }; +#pragma pack(pop) + + std::uint8_t metadata_id; +}; + +struct ArrayInfo +{ + char data_type; + char byte_order; + std::uint8_t num_dimensions; + std::uint32_t shape[MAX_NUM_DIMENSIONS]; + std::uint32_t strides[MAX_NUM_DIMENSIONS]; +}; + +struct PayloadInfo +{ + std::int8_t device_id; + std::uint64_t offset_in_buffer; + std::uint64_t total_size; + + ArrayInfo array_info; +}; + +struct MessageHeader +{ + char topic[TOPIC_MAX_KEY_SIZE]; + + char payload_id[UUID_SIZE]; + std::uint64_t frame_id; + + char trace_id[UUID_SIZE]; + + char producer_hostname[HOST_NAME_SIZE]; + std::uint32_t producer_pid; + std::uint64_t producer_timestamp; + + PayloadInfo payload_info; + + MetadataEntry metadata_entries[MAX_NUM_METADATA_ENTRIES]; + + std::uint16_t partial_frame_id; + std::uint64_t start_byte; + std::uint64_t end_byte; +}; + +struct TopicHeader +{ + std::atomic_uint64_t latest_frame_id; + std::uint64_t message_offsets[TOPIC_MAX_NUM_MESSAGES]; + char message_ids[UUID_SIZE][TOPIC_MAX_NUM_MESSAGES]; + + SynchronizationSharedData synchronization; +}; + +struct MessageBrokerHeader +{ + char version[VERSION_SIZE]; + char creator_hostname[HOST_NAME_SIZE]; + std::uint64_t time_of_last_activity; + + char buffer_shared_memory_id[MAX_SHARED_MEMORY_ID_SIZE]; + CudaIpcHandle cuda_ipc_handles[MAX_NUM_GPUS]; +}; + +struct Message +{ + MessageHeader *header; + void *payload; +}; + +class MessageBroker +{ +public: + MessageBroker(void *metadata_buffer); + + void Initialize(); + + void *ReservePayload(size_t payload_size, int8_t device_id = -1); + + void Publish(const std::string &topic, const Message &message); + void PublishPartial(const std::string &topic, const Message &message); + + Message GetNextMessage(const std::string &topic, double timeout_in_seconds); + Message GetMessage(const std::string &topic, size_t frame_id); + +private: + MessageBrokerHeader &m_Header; + + HashMap m_TopicHeaders; + PoolAllocator m_MessageHeaderAllocator; + + FreeListAllocator m_CpuPayloadAllocator; + std::shared_ptr m_CpuPayloadMemory; + + FreeListAllocator m_GpuPayloadAllocator[MAX_NUM_GPUS]; + std::shared_ptr m_GpuPayloadMemory[MAX_NUM_GPUS]; + + UuidGenerator m_UuidGenerator; +}; + +#endif // MESSAGE_BROKER_H From 09effc9c494c8e5942f69f905665c0d876e0b361 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Mon, 16 Dec 2024 17:09:33 -0800 Subject: [PATCH 04/14] Add benchmark for UUID generator. --- benchmarks/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/benchmarks/CMakeLists.txt b/benchmarks/CMakeLists.txt index a76ebf1e..b9c54288 100644 --- a/benchmarks/CMakeLists.txt +++ b/benchmarks/CMakeLists.txt @@ -39,6 +39,11 @@ add_executable(hash_map hash_map.cpp) target_include_directories(hash_map PUBLIC ../catkit_core) target_link_libraries(hash_map PUBLIC catkit_core) +# Uuid generator benchmark +add_executable(uuid_generator uuid_generator.cpp) +target_include_directories(uuid_generator PUBLIC ../catkit_core) +target_link_libraries(uuid_generator PUBLIC catkit_core) + # Add install files install(TARGETS datastream_latency DESTINATION bin) install(TARGETS datastream_submit DESTINATION bin) @@ -46,3 +51,4 @@ install(TARGETS timestamp DESTINATION bin) install(TARGETS free_list_allocator DESTINATION bin) install(TARGETS pool_allocator DESTINATION bin) install(TARGETS hash_map DESTINATION bin) +install(TARGETS uuid_generator DESTINATION bin) From f6723b9e0397e93eae53b97c898329f706f14e53 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Tue, 17 Dec 2024 21:41:01 -0800 Subject: [PATCH 05/14] Use a typename for UUIDs. --- catkit_core/UuidGenerator.cpp | 2 +- catkit_core/UuidGenerator.h | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/catkit_core/UuidGenerator.cpp b/catkit_core/UuidGenerator.cpp index ea68bcaf..80328a02 100644 --- a/catkit_core/UuidGenerator.cpp +++ b/catkit_core/UuidGenerator.cpp @@ -11,7 +11,7 @@ UuidGenerator::UuidGenerator() } } -void UuidGenerator::GenerateUuid(char *uuid) +void UuidGenerator::Generate(Uuid &uuid) { for (size_t i = 0; i < 2; ++i) { diff --git a/catkit_core/UuidGenerator.h b/catkit_core/UuidGenerator.h index 244b828d..87523421 100644 --- a/catkit_core/UuidGenerator.h +++ b/catkit_core/UuidGenerator.h @@ -3,12 +3,14 @@ #include +using Uuid = char[16]; + class UuidGenerator { public: UuidGenerator(); - void GenerateUuid(char *uuid); + void Generate(Uuid &uuid); private: std::mt19937_64 m_Engines[2]; From 86c9b1e140626f52a9ea858c99a0b2f80d9aadab Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Wed, 18 Dec 2024 14:00:20 -0800 Subject: [PATCH 06/14] Flesh out interface more. --- catkit_core/MessageBroker.h | 111 +++++++++++++++++++++++++++--------- 1 file changed, 84 insertions(+), 27 deletions(-) diff --git a/catkit_core/MessageBroker.h b/catkit_core/MessageBroker.h index b96c563f..f8ce8adf 100644 --- a/catkit_core/MessageBroker.h +++ b/catkit_core/MessageBroker.h @@ -9,6 +9,8 @@ #include "CudaSharedMemory.h" #include "UuidGenerator.h" +#include + const char * const MESSAGE_BROKER_VERSION = "0.1"; const size_t VERSION_SIZE = 8; @@ -16,26 +18,17 @@ const size_t TOPIC_HASH_MAP_SIZE = 16384; const size_t TOPIC_MAX_KEY_SIZE = 128; const size_t TOPIC_MAX_NUM_MESSAGES = 15; const size_t HOST_NAME_SIZE = 64; -const size_t METADATA_MAX_STRLEN = 15; -const size_t UUID_SIZE = 16; +const size_t METADATA_MAX_STRLEN = 16; const size_t MAX_NUM_DIMENSIONS = 4; const size_t MAX_NUM_METADATA_ENTRIES = 16; const size_t MAX_SHARED_MEMORY_ID_SIZE = 64; const size_t MAX_NUM_GPUS = 8; -struct MetadataEntry +union MetadataEntry { -// Avoid post-padding of this anonymous union. -#pragma pack(push,1) - union - { - std::uint64_t integer; - double floating_point; - char string[METADATA_MAX_STRLEN]; - }; -#pragma pack(pop) - - std::uint8_t metadata_id; + std::uint64_t integer; + double floating_point; + char string[METADATA_MAX_STRLEN]; }; struct ArrayInfo @@ -60,10 +53,10 @@ struct MessageHeader { char topic[TOPIC_MAX_KEY_SIZE]; - char payload_id[UUID_SIZE]; + Uuid payload_id; std::uint64_t frame_id; - char trace_id[UUID_SIZE]; + Uuid trace_id; char producer_hostname[HOST_NAME_SIZE]; std::uint32_t producer_pid; @@ -80,11 +73,20 @@ struct MessageHeader struct TopicHeader { - std::atomic_uint64_t latest_frame_id; + std::atomic_uint64_t next_frame_id; std::uint64_t message_offsets[TOPIC_MAX_NUM_MESSAGES]; - char message_ids[UUID_SIZE][TOPIC_MAX_NUM_MESSAGES]; SynchronizationSharedData synchronization; + + char metadata_keys[METADATA_MAX_STRLEN][MAX_NUM_METADATA_ENTRIES]; + + TopicHeader() = default; + TopicHeader(const TopicHeader &header); + + TopicHeader &operator=(const TopicHeader &header); + +private: + void CopyFrom(const TopicHeader &header); }; struct MessageBrokerHeader @@ -97,33 +99,88 @@ struct MessageBrokerHeader CudaIpcHandle cuda_ipc_handles[MAX_NUM_GPUS]; }; -struct Message +class Message { - MessageHeader *header; - void *payload; + friend class MessageBroker; + +public: + Message(); + + bool PublishPartial(std::uint64_t start_byte, std::uint64_t end_byte, bool is_final); + bool Publish(); + + const char *GetTopic() const; + + const Uuid &GetPayloadId() const; + const std::uint64_t GetFrameId() const; + + const Uuid &GetTraceId() const; + + const char *GetProducerHostnname() const; + const std::uint32_t GetProducerPid() const; + const std::uint64_t GetProducerTimestamp() const; + + const PayloadInfo &GetPayloadInfo() const; + + const ArrayInfo &GetArrayInfo() const; + void SetArrayInfo(const ArrayInfo &array_info); + + void *GetPayload() const; + size_t GetPayloadSize() const; + + const MetadataEntry &GetMetadataEntry(std::uint8_t metadata_id) const; + void SetMetadataEntry(std::uint8_t metadata_id, std::uint64_t value); + void SetMetadataEntry(std::uint8_t metadata_id, double value); + void SetMetadataEntry(std::uint8_t metadata_id, const char *value); + + const std::uint16_t GetPartialFrameId() const; + + const std::uint64_t GetStartByte() const; + void SetStartByte(const std::uint64_t &start_byte); + + const std::uint64_t GetEndByte() const; + void SetEndByte(const std::uint64_t &end_byte); + +private: + MessageHeader *m_Header; + void *m_Payload; + + bool m_HasBeenPublished; + + std::shared_ptr m_MessageBroker; }; class MessageBroker { -public: - MessageBroker(void *metadata_buffer); +private: + MessageBroker(); // TODO: Add parameters. - void Initialize(); +public: + std::unique_ptr Create(); // TODO: Add parameters. + std::unique_ptr Open(void *metadata_buffer); - void *ReservePayload(size_t payload_size, int8_t device_id = -1); + Message PrepareMessage(const std::string &topic, Uuid trace_id, size_t payload_size, int8_t device_id = -1); + Message PrepareMessage(const std::string &topic, size_t payload_size, int8_t device_id = -1); - void Publish(const std::string &topic, const Message &message); - void PublishPartial(const std::string &topic, const Message &message); + bool Publish(const Message &message); + bool PublishPartial(const Message &message, bool is_final); Message GetNextMessage(const std::string &topic, double timeout_in_seconds); Message GetMessage(const std::string &topic, size_t frame_id); private: + uint64_t AllocatePayload(size_t payload_size, int8_t device_id); + bool PublishMessage(const Message &message); + + FreeListAllocator *GetAllocator(int8_t device_id); + MessageBrokerHeader &m_Header; HashMap m_TopicHeaders; PoolAllocator m_MessageHeaderAllocator; + MessageHeader *m_MessageHeaders; + FreeListAllocator m_CpuPayloadAllocator; std::shared_ptr m_CpuPayloadMemory; From 0cf607e41c2c7f7c95a518a1c1c67bf18831fef5 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Thu, 19 Dec 2024 20:14:19 -0800 Subject: [PATCH 07/14] Only use a single PublishMessage() method. --- catkit_core/MessageBroker.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/catkit_core/MessageBroker.h b/catkit_core/MessageBroker.h index f8ce8adf..5b3a8e11 100644 --- a/catkit_core/MessageBroker.h +++ b/catkit_core/MessageBroker.h @@ -24,6 +24,8 @@ const size_t MAX_NUM_METADATA_ENTRIES = 16; const size_t MAX_SHARED_MEMORY_ID_SIZE = 64; const size_t MAX_NUM_GPUS = 8; +const std::uint64_t INVALID_FRAME_ID = 0xFFFFFFFFFFFFFFFF; + union MetadataEntry { std::uint64_t integer; @@ -103,11 +105,11 @@ class Message { friend class MessageBroker; -public: +private: Message(); - bool PublishPartial(std::uint64_t start_byte, std::uint64_t end_byte, bool is_final); - bool Publish(); +public: + ~Message(); const char *GetTopic() const; @@ -150,8 +152,10 @@ class Message std::shared_ptr m_MessageBroker; }; -class MessageBroker +class MessageBroker : std::enable_shared_from_this { + friend class Message; + private: MessageBroker(); // TODO: Add parameters. @@ -159,20 +163,17 @@ class MessageBroker std::unique_ptr Create(); // TODO: Add parameters. std::unique_ptr Open(void *metadata_buffer); - Message PrepareMessage(const std::string &topic, Uuid trace_id, size_t payload_size, int8_t device_id = -1); Message PrepareMessage(const std::string &topic, size_t payload_size, int8_t device_id = -1); + Message PrepareMessage(const std::string &topic, Uuid trace_id, size_t payload_size, int8_t device_id = -1); - bool Publish(const Message &message); - bool PublishPartial(const Message &message, bool is_final); + void PublishMessage(Message &message, bool is_final = true); Message GetNextMessage(const std::string &topic, double timeout_in_seconds); Message GetMessage(const std::string &topic, size_t frame_id); private: - uint64_t AllocatePayload(size_t payload_size, int8_t device_id); - bool PublishMessage(const Message &message); - FreeListAllocator *GetAllocator(int8_t device_id); + Synchronization *GetSynchronization(const std::string &topic); MessageBrokerHeader &m_Header; From 28d5f4b9b177028e8c2c2fbc4fd8bac7ed2e0723 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Thu, 19 Dec 2024 20:15:15 -0800 Subject: [PATCH 08/14] Topic header copy constructor and copy assignment operator. --- catkit_core/MessageBroker.cpp | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/catkit_core/MessageBroker.cpp b/catkit_core/MessageBroker.cpp index 2983c90e..d3ee1776 100644 --- a/catkit_core/MessageBroker.cpp +++ b/catkit_core/MessageBroker.cpp @@ -1,2 +1,28 @@ #include "MessageBroker.h" +#include "Util.h" +#include "Timing.h" +#include "HostName.h" + +#include + +TopicHeader::TopicHeader(const TopicHeader &header) +{ + CopyFrom(header); +} + +TopicHeader &TopicHeader::operator=(const TopicHeader &header) +{ + CopyFrom(header); + + return *this; +} + +void TopicHeader::CopyFrom(const TopicHeader &header) +{ + next_frame_id.store(header.next_frame_id.load(std::memory_order_relaxed), std::memory_order_relaxed); + synchronization = header.synchronization; + + std::copy(header.message_offsets, header.message_offsets + TOPIC_MAX_NUM_MESSAGES, message_offsets); + std::copy((char *)header.metadata_keys, (char *)header.metadata_keys + sizeof(metadata_keys), (char *)metadata_keys); +} From 2ad25ff4b4cc6db523703c0b878eb1be4716cd2a Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Thu, 19 Dec 2024 20:15:53 -0800 Subject: [PATCH 09/14] Initial implementation of Prepare() and Publish() functions. --- catkit_core/MessageBroker.cpp | 152 ++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/catkit_core/MessageBroker.cpp b/catkit_core/MessageBroker.cpp index d3ee1776..1fc6df6d 100644 --- a/catkit_core/MessageBroker.cpp +++ b/catkit_core/MessageBroker.cpp @@ -26,3 +26,155 @@ void TopicHeader::CopyFrom(const TopicHeader &header) std::copy(header.message_offsets, header.message_offsets + TOPIC_MAX_NUM_MESSAGES, message_offsets); std::copy((char *)header.metadata_keys, (char *)header.metadata_keys + sizeof(metadata_keys), (char *)metadata_keys); } + +Message MessageBroker::PrepareMessage(const std::string &topic, size_t payload_size, int8_t device_id) +{ + Uuid trace_id; + m_UuidGenerator.Generate(trace_id); + + return PrepareMessage(topic, trace_id, payload_size, device_id); +} + +Message MessageBroker::PrepareMessage(const std::string &topic, Uuid trace_id, size_t payload_size, int8_t device_id) +{ + Message message; + + message.m_HasBeenPublished = false; + message.m_MessageBroker = shared_from_this(); + + // Allocate a payload. + auto allocator = GetAllocator(device_id); + + if (allocator == nullptr) + { + throw std::runtime_error("Invalid device ID."); + } + + auto block_handle = allocator->Allocate(payload_size); + + if (block_handle == FreeListAllocator::INVALID_HANDLE) + { + throw std::runtime_error("Could not allocate payload."); + } + + auto offset = allocator->GetOffset(block_handle); + + if (device_id < 0) + { + message.m_Payload = m_CpuPayloadMemory->GetAddress() + offset; + } + else + { + message.m_Payload = m_GpuPayloadMemory[device_id]->GetAddress() + offset; + } + + // Allocate a message header. + auto message_header_handle = m_MessageHeaderAllocator.Allocate(); + + if (message_header_handle == PoolAllocator::INVALID_HANDLE) + { + throw std::runtime_error("Could not allocate message header."); + } + + // Access the message header. + message.m_Header = &m_MessageHeaders[message_header_handle]; + auto header = message.m_Header; + + // Set the payload information. + header->payload_info.device_id = device_id; + header->payload_info.total_size = payload_size; + header->payload_info.offset_in_buffer = offset; + m_UuidGenerator.Generate(header->payload_id); + + // Set the topic. + std::strncpy(header->topic, topic.c_str(), sizeof(header->topic)); + + // Set the trace ID. + std::strncpy(header->trace_id, trace_id, sizeof(header->trace_id)); + + // Set the producer information. + std::strncpy(header->producer_hostname, GetHostName().c_str(), sizeof(header->producer_hostname)); + header->producer_pid = GetProcessId(); + + header->partial_frame_id = 0; + header->start_byte = 0; + header->end_byte = payload_size; + + // Set default values. + header->frame_id = INVALID_FRAME_ID; + header->producer_timestamp = 0; + + return message; +} + +void MessageBroker::PublishMessage(Message &message, bool is_final) +{ + if (message.m_HasBeenPublished) + { + return; + } + + auto topic_header = m_TopicHeaders.Find(message.m_Header->topic); + + if (message.m_Header->partial_frame_id == INVALID_FRAME_ID) + { + // First partial frame. Assign a new frame ID. + message.m_Header->frame_id = topic_header->next_frame_id.fetch_add(1, std::memory_order_relaxed); + message.m_Header->partial_frame_id = 0; + } + else + { + // Not the first partial frame. Use the same frame ID and increment the partial frame ID. + message.m_Header->partial_frame_id++; + } + + // Get timestamp. + message.m_Header->producer_timestamp = GetTimeStamp(); + + // Go to synchronization structures and signal them. + + + if (!is_final) + { + // Copy the message header since it's gone after publishing. + auto message_header_handle = m_MessageHeaderAllocator.Allocate(); + + if (message_header_handle == PoolAllocator::INVALID_HANDLE) + { + throw std::runtime_error("Could not allocate message header."); + } + + auto new_message_header = &m_MessageHeaders[message_header_handle]; + *new_message_header = *message.m_Header; + message.m_Header = new_message_header; + } + + message.m_HasBeenPublished = is_final; +} + +FreeListAllocator *MessageBroker::GetAllocator(int8_t device_id) +{ + if (device_id < -1 || device_id >= MAX_NUM_GPUS) + { + return nullptr; + } + + if (device_id == -1) + { + return &m_CpuPayloadAllocator; + } + + return &m_GpuPayloadAllocator[device_id]; +} + +Synchronization *MessageBroker::GetSynchronization(const std::string &topic) +{ + auto topic_header = m_TopicHeaders.Find(topic); + + if (topic_header == nullptr) + { + return nullptr; + } + + // TODO: look up the synchronization structure (not the shared data). +} From e8f6086345fcfeea0eaaf2add898c9b279364998 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Fri, 20 Dec 2024 11:17:52 -0800 Subject: [PATCH 10/14] Declare class for pointer access. --- catkit_core/MessageBroker.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/catkit_core/MessageBroker.h b/catkit_core/MessageBroker.h index 5b3a8e11..25fdf79c 100644 --- a/catkit_core/MessageBroker.h +++ b/catkit_core/MessageBroker.h @@ -101,6 +101,8 @@ struct MessageBrokerHeader CudaIpcHandle cuda_ipc_handles[MAX_NUM_GPUS]; }; +class MessageBroker; + class Message { friend class MessageBroker; From d175952da44855cc283e3a2081d404bf4ce9a159 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Sun, 22 Dec 2024 12:21:16 -0800 Subject: [PATCH 11/14] Trigger synchronization for each (parent) topic. --- catkit_core/MessageBroker.cpp | 41 ++++++++++++++++++++++++++--------- catkit_core/MessageBroker.h | 11 ++++++---- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/catkit_core/MessageBroker.cpp b/catkit_core/MessageBroker.cpp index 1fc6df6d..89245a03 100644 --- a/catkit_core/MessageBroker.cpp +++ b/catkit_core/MessageBroker.cpp @@ -61,11 +61,11 @@ Message MessageBroker::PrepareMessage(const std::string &topic, Uuid trace_id, s if (device_id < 0) { - message.m_Payload = m_CpuPayloadMemory->GetAddress() + offset; + message.m_Payload = m_CpuPayloadMemory->GetAddress(offset); } else { - message.m_Payload = m_GpuPayloadMemory[device_id]->GetAddress() + offset; + message.m_Payload = m_GpuPayloadMemory[device_id]->GetAddress(offset); } // Allocate a message header. @@ -114,9 +114,10 @@ void MessageBroker::PublishMessage(Message &message, bool is_final) return; } - auto topic_header = m_TopicHeaders.Find(message.m_Header->topic); + auto topic = std::string_view(message.m_Header->topic); + auto topic_header = m_TopicHeaders.Find(topic); - if (message.m_Header->partial_frame_id == INVALID_FRAME_ID) + if (message.m_Header->frame_id == INVALID_FRAME_ID) { // First partial frame. Assign a new frame ID. message.m_Header->frame_id = topic_header->next_frame_id.fetch_add(1, std::memory_order_relaxed); @@ -128,11 +129,25 @@ void MessageBroker::PublishMessage(Message &message, bool is_final) message.m_Header->partial_frame_id++; } - // Get timestamp. + // Set the timestamp. message.m_Header->producer_timestamp = GetTimeStamp(); + // TODO: put message offsets. + // Go to synchronization structures and signal them. + // This includes parent topics. + for (std::size_t i = 0; i <= topic.size(); ++i) + { + std::size_t size = topic.size() - i; + + if (i == 0 || topic[size] == '/') + { + auto synchronization = GetSynchronization(topic.substr(0, size)); + if (synchronization) + synchronization->Signal(); + } + } if (!is_final) { @@ -152,7 +167,7 @@ void MessageBroker::PublishMessage(Message &message, bool is_final) message.m_HasBeenPublished = is_final; } -FreeListAllocator *MessageBroker::GetAllocator(int8_t device_id) +std::shared_ptr MessageBroker::GetAllocator(int8_t device_id) { if (device_id < -1 || device_id >= MAX_NUM_GPUS) { @@ -161,13 +176,13 @@ FreeListAllocator *MessageBroker::GetAllocator(int8_t device_id) if (device_id == -1) { - return &m_CpuPayloadAllocator; + return m_CpuPayloadAllocator; } - return &m_GpuPayloadAllocator[device_id]; + return m_GpuPayloadAllocator[device_id]; } -Synchronization *MessageBroker::GetSynchronization(const std::string &topic) +std::shared_ptr MessageBroker::GetSynchronization(std::string_view topic) { auto topic_header = m_TopicHeaders.Find(topic); @@ -176,5 +191,11 @@ Synchronization *MessageBroker::GetSynchronization(const std::string &topic) return nullptr; } - // TODO: look up the synchronization structure (not the shared data). + // Look up the synchronization structure (not the shared data). + if (m_Synchronizations.find(topic) == m_Synchronizations.end()) + { + m_Synchronizations[topic] = std::make_shared(topic_header->synchronization); + } + + return m_Synchronizations[topic]; } diff --git a/catkit_core/MessageBroker.h b/catkit_core/MessageBroker.h index 25fdf79c..c547c9b8 100644 --- a/catkit_core/MessageBroker.h +++ b/catkit_core/MessageBroker.h @@ -10,6 +10,7 @@ #include "UuidGenerator.h" #include +#include const char * const MESSAGE_BROKER_VERSION = "0.1"; @@ -174,8 +175,8 @@ class MessageBroker : std::enable_shared_from_this Message GetMessage(const std::string &topic, size_t frame_id); private: - FreeListAllocator *GetAllocator(int8_t device_id); - Synchronization *GetSynchronization(const std::string &topic); + std::shared_ptr GetAllocator(int8_t device_id); + std::shared_ptr GetSynchronization(std::string_view topic); MessageBrokerHeader &m_Header; @@ -184,13 +185,15 @@ class MessageBroker : std::enable_shared_from_this MessageHeader *m_MessageHeaders; - FreeListAllocator m_CpuPayloadAllocator; + std::shared_ptr m_CpuPayloadAllocator; std::shared_ptr m_CpuPayloadMemory; - FreeListAllocator m_GpuPayloadAllocator[MAX_NUM_GPUS]; + std::shared_ptr m_GpuPayloadAllocator[MAX_NUM_GPUS]; std::shared_ptr m_GpuPayloadMemory[MAX_NUM_GPUS]; UuidGenerator m_UuidGenerator; + + std::map> m_Synchronizations; }; #endif // MESSAGE_BROKER_H From cb496f8c80ee10a21de46156100c4e2bbc5fb286 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Sun, 22 Dec 2024 12:21:40 -0800 Subject: [PATCH 12/14] Fix due to API change. --- benchmarks/uuid_generator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmarks/uuid_generator.cpp b/benchmarks/uuid_generator.cpp index bb2879cf..8db6341a 100644 --- a/benchmarks/uuid_generator.cpp +++ b/benchmarks/uuid_generator.cpp @@ -17,7 +17,7 @@ int main() for (size_t i = 0; i < N; ++i) { - generator.GenerateUuid(uuid); + generator.Generate(uuid); } auto end = GetTimeStamp(); From af420b2b27d90dbee470dfa932f12ae4142abd1a Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Sun, 22 Dec 2024 12:22:03 -0800 Subject: [PATCH 13/14] Unify memory block API. --- catkit_core/CudaSharedMemory.h | 6 ++++-- catkit_core/Memory.h | 16 ++++++++++++++++ catkit_core/SharedMemory.cpp | 4 ++-- catkit_core/SharedMemory.h | 6 ++++-- 4 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 catkit_core/Memory.h diff --git a/catkit_core/CudaSharedMemory.h b/catkit_core/CudaSharedMemory.h index 98899e2d..a5e433f5 100644 --- a/catkit_core/CudaSharedMemory.h +++ b/catkit_core/CudaSharedMemory.h @@ -1,6 +1,8 @@ #ifndef CUDA_SHARED_MEMORY_H #define CUDA_SHARED_MEMORY_H +#include "Memory.h" + #include #ifdef HAVE_CUDA @@ -11,7 +13,7 @@ typedef cudaIpcMemHandle_t CudaIpcHandle; typedef char CudaIpcHandle[64]; #endif -class CudaSharedMemory +class CudaSharedMemory : public Memory { private: CudaSharedMemory(const CudaIpcHandle &ipc_handle, void *device_pointer=nullptr); @@ -22,7 +24,7 @@ class CudaSharedMemory static std::shared_ptr Create(size_t num_bytes_in_buffer); static std::shared_ptr Open(const CudaIpcHandle &ipc_handle); - void *GetAddress(); + void *GetAddress(std::size_t offset = 0) override; }; #endif // CUDA_SHARED_MEMORY_H diff --git a/catkit_core/Memory.h b/catkit_core/Memory.h new file mode 100644 index 00000000..9f20e9ed --- /dev/null +++ b/catkit_core/Memory.h @@ -0,0 +1,16 @@ +#ifndef MEMORY_H +#define MEMORY_H + +#include + +class Memory +{ +public: + virtual ~Memory() + { + } + + virtual void *GetAddress(std::size_t offset = 0) = 0; +}; + +#endif // MEMORY_H diff --git a/catkit_core/SharedMemory.cpp b/catkit_core/SharedMemory.cpp index a469b9c4..c8b8d356 100644 --- a/catkit_core/SharedMemory.cpp +++ b/catkit_core/SharedMemory.cpp @@ -82,7 +82,7 @@ SharedMemory::SharedMemory(const std::string &id, FileObject file, bool is_owner throw std::runtime_error("Something went wrong while mapping shared memory file."); } -void *SharedMemory::GetAddress() +void *SharedMemory::GetAddress(std::size_t offset) { - return m_Buffer; + return static_cast(m_Buffer) + offset; } diff --git a/catkit_core/SharedMemory.h b/catkit_core/SharedMemory.h index aa6764bd..ca78b51c 100644 --- a/catkit_core/SharedMemory.h +++ b/catkit_core/SharedMemory.h @@ -1,6 +1,8 @@ #ifndef SHARED_MEMORY_H #define SHARED_MEMORY_H +#include "Memory.h" + #include #include @@ -21,7 +23,7 @@ typedef int FileObject; #endif -class SharedMemory +class SharedMemory : public Memory { private: SharedMemory(const std::string &id, FileObject file, bool is_owner); @@ -32,7 +34,7 @@ class SharedMemory static std::shared_ptr Create(const std::string &id, size_t num_bytes_in_buffer); static std::shared_ptr Open(const std::string &id); - void *GetAddress(); + void *GetAddress(std::size_t offset = 0) override; private: std::string m_Id; From 45704c2678ba5d29dc48c228db4c33dddf0c7517 Mon Sep 17 00:00:00 2001 From: Emiel Por Date: Sun, 22 Dec 2024 12:22:17 -0800 Subject: [PATCH 14/14] Add local memory for testing purposes. --- catkit_core/CMakeLists.txt | 1 + catkit_core/LocalMemory.cpp | 16 ++++++++++++++++ catkit_core/LocalMemory.h | 18 ++++++++++++++++++ 3 files changed, 35 insertions(+) create mode 100644 catkit_core/LocalMemory.cpp create mode 100644 catkit_core/LocalMemory.h diff --git a/catkit_core/CMakeLists.txt b/catkit_core/CMakeLists.txt index 7afde58a..2264c90d 100644 --- a/catkit_core/CMakeLists.txt +++ b/catkit_core/CMakeLists.txt @@ -37,6 +37,7 @@ add_library(catkit_core STATIC FreeListAllocator.cpp MessageBroker.cpp UuidGenerator.cpp + LocalMemory.cpp proto/core.pb.cc proto/logging.pb.cc proto/testbed.pb.cc diff --git a/catkit_core/LocalMemory.cpp b/catkit_core/LocalMemory.cpp new file mode 100644 index 00000000..57120fc0 --- /dev/null +++ b/catkit_core/LocalMemory.cpp @@ -0,0 +1,16 @@ +#include "LocalMemory.h" + +LocalMemory::LocalMemory(std::size_t num_bytes) + : m_Memory(new char[num_bytes]) +{ +} + +LocalMemory::~LocalMemory() +{ + delete[] m_Memory; +} + +void *LocalMemory::GetAddress(std::size_t offset) +{ + return m_Memory + offset; +} diff --git a/catkit_core/LocalMemory.h b/catkit_core/LocalMemory.h new file mode 100644 index 00000000..d237b9db --- /dev/null +++ b/catkit_core/LocalMemory.h @@ -0,0 +1,18 @@ +#ifndef LOCAL_MEMORY_H +#define LOCAL_MEMORY_H + +#include "Memory.h" + +class LocalMemory : public Memory +{ +public: + LocalMemory(std::size_t num_bytes); + virtual ~LocalMemory(); + + virtual void *GetAddress(std::size_t offset = 0); + +private: + char *m_Memory; +}; + +#endif // LOCAL_MEMORY_H