Files
dmlc--dgl/include/dgl/zerocopy_serializer.h
2026-07-13 13:35:51 +08:00

192 lines
6.1 KiB
C++

/**
* Copyright (c) 2020 by Contributors
* @file rpc/shared_mem_serializer.h
* @brief headers for serializer.
*/
#ifndef DGL_ZEROCOPY_SERIALIZER_H_
#define DGL_ZEROCOPY_SERIALIZER_H_
#include <dgl/runtime/ndarray.h>
#include <dmlc/io.h>
#include <dmlc/memory_io.h>
#include <dmlc/serializer.h>
#include <deque>
#include <memory>
#include <queue>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "dmlc/logging.h"
namespace dgl {
/**
*
* StreamWithBuffer is backed up by dmlc::MemoryFixedSizeStream or
* dmlc::MemoryStringStream. This class supports serializing and deserializing
* NDArrays stored in shared memory. If the stream is created for
* sending/recving data through network, the data pointer of the NDArray will be
* transmitted directly without and copy. Otherwise, the stream is for
* sending/recving data to another process on the same machine, so if an NDArray
* is stored in shared memory, it will just record the shared memory name
* instead of the actual data buffer.
*
* For example:
*
* std::string blob;
* // Send to local
* StreamWithBuffer strm(&blob, false);
* // Send to remote
* StreamWithBuffer strm(&blob, true);
* // Receive from local
* StreamWithBuffer strm(&blob, false);
* // Receive from remote
* std::vector<void*> ptr_list
* StreamWithBuffer strm(&blob, ptr_list);
*/
class StreamWithBuffer : public dmlc::SeekStream {
public:
// Buffer type. Storing NDArray to maintain the reference counting to ensure
// the liveness of data pointer
struct Buffer {
dgl::runtime::NDArray tensor = dgl::runtime::NDArray();
void* data = nullptr;
int64_t size = 0;
Buffer(const dgl::runtime::NDArray& tensor, void* data, int64_t data_size)
: tensor(tensor), data(data), size(data_size) {}
explicit Buffer(void* data) : data(data) {}
};
/**
* @brief This constructor is for writing scenario or reading from local
* machine
* @param strm The backup stream to write/load from
* @param send_to_remote Whether this stream will be deserialized at remote
* machine or the local machine. If true, will record the data pointer into
* buffer list.
*/
StreamWithBuffer(std::unique_ptr<dmlc::SeekStream> strm, bool send_to_remote)
: strm_(std::move(strm)),
buffer_list_(),
send_to_remote_(send_to_remote) {}
/**
* @brief This constructor is for reading from remote
* @param strm The stream to write/load from zerocopy write/load
* @param data_ptr_list list of pointer to reconstruct NDArray
*
* For example:
* std::string blob;
* std::vector<void*> data_ptr_list;
* // Read from remote sended pointer list
* StreamWithBuffer buf_strm(&blob, data_ptr_list)
*/
StreamWithBuffer(
std::unique_ptr<dmlc::SeekStream> strm,
const std::vector<void*>& data_ptr_list)
: strm_(std::move(strm)), send_to_remote_(true) {
for (void* data : data_ptr_list) {
buffer_list_.emplace_back(data);
}
}
/**
* @brief Construct stream backed up by string
* @param blob The string to write/load from zerocopy write/load
* @param send_to_remote Whether this stream will be deserialized at remote
* machine or the local machine. If true, will record the data pointer into
* buffer list.
*/
StreamWithBuffer(std::string* blob, bool send_to_remote)
: strm_(new dmlc::MemoryStringStream(blob)),
send_to_remote_(send_to_remote) {}
/**
* @brief Construct stream backed up by string
* @param p_buffer buffer pointer
* @param size buffer size
* @param send_to_remote Whether this stream will be deserialized at remote
* machine or the local machine. If true, will record the data pointer into
* buffer list.
*/
StreamWithBuffer(char* p_buffer, size_t size, bool send_to_remote)
: strm_(new dmlc::MemoryFixedSizeStream(p_buffer, size)),
send_to_remote_(send_to_remote) {}
/**
* @brief Construct stream backed up by string, and reconstruct NDArray
* from data_ptr_list
* @param blob The string to write/load from zerocopy write/load
* @param data_ptr_list pointer list for NDArrays to deconstruct from
*/
StreamWithBuffer(std::string* blob, const std::vector<void*>& data_ptr_list)
: strm_(new dmlc::MemoryStringStream(blob)), send_to_remote_(true) {
for (void* data : data_ptr_list) {
buffer_list_.emplace_back(data);
}
}
/**
* @brief Construct stream backed up by string, and reconstruct NDArray
* from data_ptr_list
* @param p_buffer buffer pointer
* @param size buffer size
* @param data_ptr_list pointer list for NDArrays to deconstruct from
*/
StreamWithBuffer(
char* p_buffer, size_t size, const std::vector<void*>& data_ptr_list)
: strm_(new dmlc::MemoryFixedSizeStream(p_buffer, size)),
send_to_remote_(true) {
for (void* data : data_ptr_list) {
buffer_list_.emplace_back(data);
}
}
// delegate methods to strm_
virtual size_t Read(void* ptr, size_t size) { return strm_->Read(ptr, size); }
virtual void Write(const void* ptr, size_t size) { strm_->Write(ptr, size); }
virtual void Seek(size_t pos) { strm_->Seek(pos); }
virtual size_t Tell(void) { return strm_->Tell(); }
using dmlc::Stream::Read;
using dmlc::Stream::Write;
/**
* @brief push NDArray into stream
* If send_to_remote=true, the NDArray will be saved to the buffer list
* If send_to_remote=false, the NDArray will be saved to the backedup string
*/
void PushNDArray(const runtime::NDArray& tensor);
/**
* @brief pop NDArray from stream
* If send_to_remote=true, the NDArray will be reconstructed from buffer list
* If send_to_remote=false, the NDArray will be reconstructed from shared
* memory
*/
dgl::runtime::NDArray PopNDArray();
/**
* @brief Get whether this stream is for remote usage
*/
bool send_to_remote() { return send_to_remote_; }
/**
* @brief Get underlying buffer list
*/
const std::deque<Buffer>& buffer_list() const { return buffer_list_; }
private:
std::unique_ptr<dmlc::SeekStream> strm_;
std::deque<Buffer> buffer_list_;
bool send_to_remote_;
}; // namespace dgl
} // namespace dgl
#endif // DGL_ZEROCOPY_SERIALIZER_H_