/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved. 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. */ #pragma once #if defined _WIN32 || defined __APPLE__ #else #define _LINUX #endif #include #include // NOLINT #include #include // NOLINT #include #include #include #include // NOLINT #include #include #include #include #include "paddle/fluid/framework/archive.h" #include "paddle/fluid/framework/blocking_queue.h" #include "paddle/fluid/framework/channel.h" #include "paddle/fluid/framework/data_feed.pb.h" #include "paddle/fluid/framework/fleet/fleet_wrapper.h" #include "paddle/fluid/framework/lod_tensor.h" #include "paddle/fluid/framework/reader.h" #include "paddle/fluid/framework/variable.h" #include "paddle/fluid/platform/timer.h" #include "paddle/fluid/string/string_helper.h" #include "paddle/phi/core/macros.h" #if defined(PADDLE_WITH_CUDA) #include "paddle/fluid/framework/fleet/heter_ps/gpu_graph_utils.h" #include "paddle/fluid/platform/cuda_device_guard.h" #include "paddle/fluid/platform/device/gpu/gpu_info.h" #include "paddle/phi/core/cuda_stream.h" #endif #include "paddle/phi/core/flags.h" PHI_DECLARE_int32(record_pool_max_size); PHI_DECLARE_int32(slotpool_thread_num); PHI_DECLARE_bool(enable_slotpool_wait_release); PHI_DECLARE_bool(enable_slotrecord_reset_shrink); namespace paddle { namespace framework { class DataFeedDesc; class Scope; class Variable; class NeighborSampleResult; class NodeQueryResult; template class HashTable; } // namespace framework } // namespace paddle namespace phi { class DenseTensor; } // namespace phi namespace paddle { namespace framework { // DataFeed is the base virtual class for all ohther DataFeeds. // It is used to read files and parse the data for subsequent trainer. // Example: // DataFeed* reader = // paddle::framework::DataFeedFactory::CreateDataFeed(data_feed_name); // reader->Init(data_feed_desc); // data_feed_desc is a protobuf object // reader->SetFileList(filelist); // const std::vector & use_slot_alias = // reader->GetUseSlotAlias(); // for (auto name: use_slot_alias){ // for binding memory // reader->AddFeedVar(scope->Var(name), name); // } // reader->Start(); // while (reader->Next()) { // // trainer do something // } template struct SlotValues { std::vector slot_values; std::vector slot_offsets; void add_values(const T* values, uint32_t num) { if (slot_offsets.empty()) { slot_offsets.push_back(0); } if (num > 0) { slot_values.insert(slot_values.end(), values, values + num); } slot_offsets.push_back(static_cast(slot_values.size())); } T* get_values(int idx, size_t* size) { uint32_t& offset = slot_offsets[idx]; (*size) = slot_offsets[idx + 1] - offset; return &slot_values[offset]; } void add_slot_feasigns(const std::vector>& slot_feasigns, uint32_t fea_num) { slot_values.reserve(fea_num); int slot_num = static_cast(slot_feasigns.size()); slot_offsets.resize(slot_num + 1); for (int i = 0; i < slot_num; ++i) { auto& slot_val = slot_feasigns[i]; slot_offsets[i] = static_cast(slot_values.size()); uint32_t num = static_cast(slot_val.size()); if (num > 0) { slot_values.insert(slot_values.end(), slot_val.begin(), slot_val.end()); } } slot_offsets[slot_num] = slot_values.size(); } void clear(bool shrink) { slot_offsets.clear(); slot_values.clear(); if (shrink) { slot_values.shrink_to_fit(); slot_offsets.shrink_to_fit(); } } }; union FeatureFeasign { uint64_t uint64_feasign_; float float_feasign_; }; struct FeatureItem { FeatureItem() {} FeatureItem(FeatureFeasign sign, uint16_t slot) { this->sign() = sign; this->slot() = slot; } FeatureFeasign& sign() { return *(reinterpret_cast(sign_buffer())); } const FeatureFeasign& sign() const { const FeatureFeasign* ret = reinterpret_cast(sign_buffer()); return *ret; } uint16_t& slot() { return slot_; } const uint16_t& slot() const { return slot_; } private: char* sign_buffer() const { return const_cast(sign_); } char sign_[sizeof(FeatureFeasign)]; uint16_t slot_; }; struct AllSlotInfo { std::string slot; std::string type; int used_idx; int slot_value_idx; }; struct UsedSlotInfo { int idx; int slot_value_idx; std::string slot; std::string type; bool dense; std::vector local_shape; int total_dims_without_inductive; int inductive_shape_index; }; struct SlotRecordObject { uint64_t search_id; uint32_t rank; uint32_t cmatch; std::string ins_id_; SlotValues slot_uint64_feasigns_; SlotValues slot_float_feasigns_; ~SlotRecordObject() { clear(true); } void reset(void) { clear(FLAGS_enable_slotrecord_reset_shrink); } void clear(bool shrink) { slot_uint64_feasigns_.clear(shrink); slot_float_feasigns_.clear(shrink); } }; using SlotRecord = SlotRecordObject*; // sizeof Record is much less than std::vector struct Record { std::vector uint64_feasigns_; std::vector float_feasigns_; std::string ins_id_; std::string content_; uint64_t search_id; uint32_t rank; uint32_t cmatch; std::string uid_; }; inline SlotRecord make_slotrecord() { static const size_t slot_record_byte_size = sizeof(SlotRecordObject); void* p = malloc(slot_record_byte_size); new (p) SlotRecordObject; return reinterpret_cast(p); } inline void free_slotrecord(SlotRecordObject* p) { p->~SlotRecordObject(); free(p); } template class SlotObjAllocator { public: explicit SlotObjAllocator(std::function deleter) : free_nodes_(NULL), capacity_(0), deleter_(deleter) {} ~SlotObjAllocator() { clear(); } void clear() { T* tmp = NULL; while (free_nodes_ != NULL) { tmp = reinterpret_cast(reinterpret_cast(free_nodes_)); free_nodes_ = free_nodes_->next; deleter_(tmp); --capacity_; } CHECK_EQ(capacity_, static_cast(0)); } T* acquire(void) { T* x = NULL; x = reinterpret_cast(reinterpret_cast(free_nodes_)); free_nodes_ = free_nodes_->next; --capacity_; return x; } void release(T* x) { Node* node = reinterpret_cast(reinterpret_cast(x)); node->next = free_nodes_; free_nodes_ = node; ++capacity_; } size_t capacity(void) { return capacity_; } private: struct alignas(T) Node { union { Node* next; char data[sizeof(T)]; }; }; Node* free_nodes_; // a list size_t capacity_; std::function deleter_ = nullptr; }; static const int OBJPOOL_BLOCK_SIZE = 10000; class SlotObjPool { public: SlotObjPool() : max_capacity_(FLAGS_record_pool_max_size), alloc_(free_slotrecord) { ins_chan_ = MakeChannel(); ins_chan_->SetBlockSize(OBJPOOL_BLOCK_SIZE); for (int i = 0; i < FLAGS_slotpool_thread_num; ++i) { threads_.push_back(std::thread([this]() { run(); })); } disable_pool_ = false; count_ = 0; } ~SlotObjPool() { ins_chan_->Close(); for (auto& t : threads_) { t.join(); } } void disable_pool(bool disable) { disable_pool_ = disable; } void set_max_capacity(size_t max_capacity) { max_capacity_ = max_capacity; } void get(std::vector* output, int n) { output->resize(n); return get(&(*output)[0], n); } void get(SlotRecord* output, int n) { int size = 0; mutex_.lock(); int left = static_cast(alloc_.capacity()); if (left > 0) { size = (left >= n) ? n : left; for (int i = 0; i < size; ++i) { output[i] = alloc_.acquire(); } } mutex_.unlock(); count_ += n; if (size == n) { return; } for (int i = size; i < n; ++i) { output[i] = make_slotrecord(); } } void put(std::vector* input) { size_t size = input->size(); if (size == 0) { return; } put(&(*input)[0], size); input->clear(); } void put(SlotRecord* input, size_t size) { CHECK(ins_chan_->WriteMove(size, input) == size); } void run(void) { std::vector input; while (ins_chan_->ReadOnce(input, OBJPOOL_BLOCK_SIZE)) { if (input.empty()) { continue; } // over max capacity size_t n = input.size(); count_ -= n; if (disable_pool_ || n + capacity() > max_capacity_) { for (auto& t : input) { free_slotrecord(t); } } else { for (auto& t : input) { t->reset(); } mutex_.lock(); for (auto& t : input) { alloc_.release(t); } mutex_.unlock(); } input.clear(); } } void clear(void) { platform::Timer timeline; timeline.Start(); mutex_.lock(); alloc_.clear(); mutex_.unlock(); // wait release channel data if (FLAGS_enable_slotpool_wait_release) { while (!ins_chan_->Empty()) { sleep(1); } } timeline.Pause(); VLOG(3) << "clear slot pool data size=" << count_.load() << ", span=" << timeline.ElapsedSec(); } size_t capacity(void) { mutex_.lock(); size_t total = alloc_.capacity(); mutex_.unlock(); return total; } private: size_t max_capacity_; Channel ins_chan_; std::vector threads_; std::mutex mutex_; SlotObjAllocator alloc_; bool disable_pool_; std::atomic count_; // NOLINT }; inline SlotObjPool& SlotRecordPool() { static SlotObjPool pool; return pool; } struct PvInstanceObject { std::vector ads; void merge_instance(Record* ins) { ads.push_back(ins); } }; using PvInstance = PvInstanceObject*; inline PvInstance make_pv_instance() { return new PvInstanceObject(); } struct SlotConf { std::string name; std::string type; int use_slots_index; int use_slots_is_dense; }; class CustomParser { public: CustomParser() {} virtual ~CustomParser() {} virtual void Init(const std::vector& slots) = 0; virtual bool Init(const std::vector& slots) = 0; virtual void ParseOneInstance(const char* str, Record* instance) = 0; virtual int ParseInstance(int len UNUSED, const char* str UNUSED, std::vector* instances UNUSED) { return 0; } virtual bool ParseOneInstance( const std::string& line UNUSED, std::function&, int)> GetInsFunc UNUSED) { // NOLINT return true; } virtual bool ParseFileInstance( std::function ReadBuffFunc UNUSED, std::function&, int, int)> PullRecordsFunc UNUSED, // NOLINT int& lines UNUSED) { // NOLINT return false; } }; struct UsedSlotGpuType { int is_uint64_value; int slot_value_idx; }; #if defined(PADDLE_WITH_CUDA) && defined(PADDLE_WITH_HETERPS) template struct CudaBuffer { T* cu_buffer; uint64_t buf_size; CudaBuffer() { cu_buffer = NULL; buf_size = 0; } ~CudaBuffer() { free(); } T* data() { return cu_buffer; } uint64_t size() { return buf_size; } void malloc(uint64_t size) { buf_size = size; CUDA_CHECK( cudaMalloc(reinterpret_cast(&cu_buffer), size * sizeof(T))); } void free() { if (cu_buffer != NULL) { CUDA_CHECK(cudaFree(cu_buffer)); cu_buffer = NULL; } buf_size = 0; } void resize(uint64_t size) { if (size <= buf_size) { return; } free(); malloc(size); } }; template struct HostBuffer { T* host_buffer; size_t buf_size; size_t data_len; HostBuffer() { host_buffer = NULL; buf_size = 0; data_len = 0; } ~HostBuffer() { free(); } T* data() { return host_buffer; } const T* data() const { return host_buffer; } size_t size() const { return data_len; } void clear() { free(); } T& back() { return host_buffer[data_len - 1]; } T& operator[](size_t i) { return host_buffer[i]; } const T& operator[](size_t i) const { return host_buffer[i]; } void malloc(size_t len) { buf_size = len; CUDA_CHECK(cudaHostAlloc(reinterpret_cast(&host_buffer), buf_size * sizeof(T), cudaHostAllocDefault)); CHECK(host_buffer != NULL); } void free() { if (host_buffer != NULL) { CUDA_CHECK(cudaFreeHost(host_buffer)); host_buffer = NULL; } buf_size = 0; } void resize(size_t size) { if (size <= buf_size) { data_len = size; return; } data_len = size; free(); malloc(size); } }; struct BatchCPUValue { HostBuffer h_uint64_lens; HostBuffer h_uint64_keys; HostBuffer h_uint64_offset; HostBuffer h_float_lens; HostBuffer h_float_keys; HostBuffer h_float_offset; HostBuffer h_rank; HostBuffer h_cmatch; HostBuffer h_ad_offset; }; struct BatchGPUValue { CudaBuffer d_uint64_lens; CudaBuffer d_uint64_keys; CudaBuffer d_uint64_offset; CudaBuffer d_float_lens; CudaBuffer d_float_keys; CudaBuffer d_float_offset; CudaBuffer d_rank; CudaBuffer d_cmatch; CudaBuffer d_ad_offset; }; class MiniBatchGpuPack { public: MiniBatchGpuPack(const paddle::platform::Place& place, const std::vector& infos, phi::StreamId stream_id); ~MiniBatchGpuPack(); bool is_use() { return is_using_; } void set_use_flag(bool is_use) { is_using_ = is_use; } void reset(const paddle::platform::Place& place); void pack_instance(const SlotRecord* ins_vec, int num); int ins_num() { return ins_num_; } int pv_num() { return pv_num_; } BatchGPUValue& value() { return value_; } BatchCPUValue& cpu_value() { return buf_; } UsedSlotGpuType* get_gpu_slots(void) { return reinterpret_cast(gpu_slots_.data()); } SlotRecord* get_records(void) { return &ins_vec_[0]; } // tensor gpu memory reused void resize_tensor(void) { if (used_float_num_ > 0) { int float_total_len = buf_.h_float_lens.back(); if (float_total_len > 0) { float_tensor_.mutable_data({float_total_len, 1}, this->place_); } } if (used_uint64_num_ > 0) { int uint64_total_len = buf_.h_uint64_lens.back(); if (uint64_total_len > 0) { uint64_tensor_.mutable_data({uint64_total_len, 1}, this->place_); } } } phi::DenseTensor& float_tensor(void) { return float_tensor_; } phi::DenseTensor& uint64_tensor(void) { return uint64_tensor_; } std::vector& float_tensor_vec(void) { return float_tensor_vec_; } std::vector& uint64_tensor_vec(void) { return uint64_tensor_vec_; } HostBuffer& offsets(void) { return offsets_; } HostBuffer& h_tensor_ptrs(void) { return h_tensor_ptrs_; } void* gpu_slot_offsets(void) { return gpu_slot_offsets_->ptr(); } void* slot_buf_ptr(void) { return slot_buf_ptr_->ptr(); } void resize_gpu_slot_offsets(const size_t slot_total_bytes) { if (gpu_slot_offsets_ == nullptr) { gpu_slot_offsets_ = memory::AllocShared(place_, slot_total_bytes); } else if (gpu_slot_offsets_->size() < slot_total_bytes) { auto buf = memory::AllocShared(place_, slot_total_bytes); gpu_slot_offsets_.swap(buf); buf = nullptr; } } const std::string& get_lineid(int idx) { if (enable_pv_) { return ins_vec_[idx]->ins_id_; } return batch_ins_[idx]->ins_id_; } cudaStream_t get_stream() { return stream_; } private: void transfer_to_gpu(void); void pack_all_data(const SlotRecord* ins_vec, int num); void pack_uint64_data(const SlotRecord* ins_vec, int num); void pack_float_data(const SlotRecord* ins_vec, int num); public: template void copy_host2device(CudaBuffer* buf, const T* val, size_t size) { if (size == 0) { return; } buf->resize(size); CUDA_CHECK(cudaMemcpyAsync( buf->data(), val, size * sizeof(T), cudaMemcpyHostToDevice, stream_)); } template void copy_host2device(CudaBuffer* buf, const HostBuffer& val) { copy_host2device(buf, val.data(), val.size()); } private: bool is_using_ = false; paddle::platform::Place place_; std::unique_ptr stream_holder_; cudaStream_t stream_; BatchGPUValue value_; BatchCPUValue buf_; int ins_num_ = 0; int pv_num_ = 0; bool enable_pv_ = false; int used_float_num_ = 0; int used_uint64_num_ = 0; int used_slot_size_ = 0; CudaBuffer gpu_slots_; std::vector gpu_used_slots_; std::vector ins_vec_; const SlotRecord* batch_ins_ = nullptr; // uint64 tensor phi::DenseTensor uint64_tensor_; std::vector uint64_tensor_vec_; // float tensor phi::DenseTensor float_tensor_; std::vector float_tensor_vec_; // batch HostBuffer offsets_; HostBuffer h_tensor_ptrs_; std::shared_ptr gpu_slot_offsets_ = nullptr; std::shared_ptr slot_buf_ptr_ = nullptr; }; class MiniBatchGpuPackMgr { static const int MAX_DEIVCE_NUM = 16; public: MiniBatchGpuPackMgr() { pack_list_.resize(MAX_DEIVCE_NUM); for (int i = 0; i < MAX_DEIVCE_NUM; ++i) { pack_list_[i].clear(); } } ~MiniBatchGpuPackMgr() { for (int i = 0; i < MAX_DEIVCE_NUM; ++i) { for (size_t j = 0; j < pack_list_[i].size(); j++) { if (pack_list_[i][j] == nullptr) { continue; } delete pack_list_[i][j]; pack_list_[i][j] = nullptr; } } } // thread unsafe MiniBatchGpuPack* get(const paddle::platform::Place& place, const std::vector& infos) { int device_id = place.GetDeviceId(); for (size_t i = 0; i < pack_list_[device_id].size(); i++) { if (!pack_list_[device_id][i]->is_use()) { pack_list_[device_id][i]->set_use_flag(true); pack_list_[device_id][i]->reset(place); return pack_list_[device_id][i]; } } { std::lock_guard lock(mutex_); if (!alloc_stream_map_.count(device_id)) { alloc_stream_map_.emplace(device_id, new phi::CUDAStream(place)); } } phi::StreamId alloc_stream_id = reinterpret_cast( alloc_stream_map_[device_id]->raw_stream()); auto* pack = new MiniBatchGpuPack(place, infos, alloc_stream_id); pack->set_use_flag(true); pack_list_[device_id].push_back(pack); return pack; } private: std::vector> pack_list_; std::unordered_map> alloc_stream_map_; std::mutex mutex_; }; // global mgr inline MiniBatchGpuPackMgr& BatchGpuPackMgr() { static MiniBatchGpuPackMgr mgr; return mgr; } #endif typedef paddle::framework::CustomParser* (*CreateParserObjectFunc)(); class DLManager { struct DLHandle { void* module; paddle::framework::CustomParser* parser; }; public: DLManager() {} ~DLManager() { #ifdef _LINUX std::lock_guard lock(mutex_); for (auto it = handle_map_.begin(); it != handle_map_.end(); ++it) { delete it->second.parser; dlclose(it->second.module); } #endif } bool Close(const std::string& name) { #ifdef _LINUX auto it = handle_map_.find(name); if (it == handle_map_.end()) { return true; } delete it->second.parser; dlclose(it->second.module); #endif VLOG(0) << "Not implement in windows"; return false; } paddle::framework::CustomParser* Load(const std::string& name, const std::vector& conf) { #ifdef _LINUX std::lock_guard lock(mutex_); DLHandle handle; std::map::iterator it = handle_map_.find(name); if (it != handle_map_.end()) { return it->second.parser; } handle.module = dlopen(name.c_str(), RTLD_NOW); if (handle.module == nullptr) { VLOG(0) << "Create so of " << name << " fail, " << dlerror(); return nullptr; } CreateParserObjectFunc create_parser_func = (CreateParserObjectFunc)dlsym(handle.module, "CreateParserObject"); handle.parser = create_parser_func(); handle.parser->Init(conf); handle_map_.insert({name, handle}); return handle.parser; #endif VLOG(0) << "Not implement in windows"; return nullptr; } paddle::framework::CustomParser* Load(const std::string& name, const std::vector& conf) { #ifdef _LINUX std::lock_guard lock(mutex_); DLHandle handle; std::map::iterator it = handle_map_.find(name); if (it != handle_map_.end()) { return it->second.parser; } handle.module = dlopen(name.c_str(), RTLD_NOW); if (handle.module == nullptr) { VLOG(0) << "Create so of " << name << " fail"; exit(-1); return nullptr; } CreateParserObjectFunc create_parser_func = (CreateParserObjectFunc)dlsym(handle.module, "CreateParserObject"); handle.parser = create_parser_func(); handle.parser->Init(conf); handle_map_.insert({name, handle}); return handle.parser; #endif VLOG(0) << "Not implement in windows"; return nullptr; } paddle::framework::CustomParser* ReLoad(const std::string& name, const std::vector& conf) { Close(name); return Load(name, conf); } private: std::mutex mutex_; std::map handle_map_; }; struct engine_wrapper_t { std::default_random_engine engine; #if !defined(_WIN32) engine_wrapper_t() { struct timespec tp; clock_gettime(CLOCK_REALTIME, &tp); double cur_time = tp.tv_sec + tp.tv_nsec * 1e-9; static std::atomic x(0); std::seed_seq sseq = {x++, x++, x++, (uint64_t)(cur_time * 1000)}; engine.seed(sseq); } #endif }; struct BufState { int left; int right; int central_word; int step; engine_wrapper_t random_engine_; int len; int cursor; int row_num; int batch_size; int walk_len; std::vector* window; BufState() {} ~BufState() {} void Init(int graph_batch_size, int graph_walk_len, std::vector* graph_window) { batch_size = graph_batch_size; walk_len = graph_walk_len; window = graph_window; left = 0; right = window->size() - 1; central_word = -1; step = -1; len = 0; cursor = 0; row_num = 0; for (size_t i = 0; i < graph_window->size(); i++) { VLOG(2) << "graph_window[" << i << "] = " << (*graph_window)[i]; } } void Reset(int total_rows) { cursor = 0; row_num = total_rows; int tmp_len = cursor + batch_size > row_num ? row_num - cursor : batch_size; len = tmp_len; central_word = -1; step = -1; GetNextCentrolWord(); } int GetNextStep() { step++; if (step <= right && central_word + (*window)[step] < walk_len) { return 1; } return 0; } void Debug() { VLOG(2) << "left: " << left << " right: " << right << " central_word: " << central_word << " step: " << step << " cursor: " << cursor << " len: " << len << " row_num: " << row_num; } int GetNextCentrolWord() { if (++central_word >= walk_len) { return 0; } int window_size = window->size() / 2; int random_window = random_engine_.engine() % window_size + 1; left = window_size - random_window; right = window_size + random_window - 1; VLOG(2) << "random window: " << random_window << " window[" << left << "] = " << (*window)[left] << " window[" << right << "] = " << (*window)[right]; for (step = left; step <= right; step++) { if (central_word + (*window)[step] >= 0) { return 1; } } return 0; } int GetNextBatch() { cursor += len; if (row_num - cursor < 0) { return 0; } int tmp_len = cursor + batch_size > row_num ? row_num - cursor : batch_size; if (tmp_len == 0) { return 0; } len = tmp_len; central_word = -1; step = -1; GetNextCentrolWord(); return tmp_len != 0; } }; class GraphDataGenerator { public: GraphDataGenerator() {} virtual ~GraphDataGenerator() {} void SetConfig(const paddle::framework::DataFeedDesc& data_feed_desc); void AllocResource(int thread_id, std::vector feed_vec); void AllocTrainResource(int thread_id); void SetFeedVec(std::vector feed_vec); int AcquireInstance(BufState* state); int GenerateBatch(); int FillWalkBuf(); int FillWalkBufMultiPath(); int FillInferBuf(); void DoWalkandSage(); int FillSlotFeature(uint64_t* d_walk); int FillFeatureBuf(uint64_t* d_walk, uint64_t* d_feature, size_t key_num); int FillFeatureBuf(std::shared_ptr d_walk, std::shared_ptr d_feature); void FillOneStep(uint64_t* start_ids, int etype_id, uint64_t* walk, uint8_t* walk_ntype, int len, NeighborSampleResult& sample_res, // NOLINT int cur_degree, int step, int* len_per_row); int FillInsBuf(cudaStream_t stream); int FillIdShowClkTensor(int total_instance, bool gpu_graph_training, size_t cursor = 0); int FillGraphIdShowClkTensor(int uniq_instance, int total_instance, int index); int FillGraphSlotFeature( int total_instance, bool gpu_graph_training, std::shared_ptr final_sage_nodes = nullptr); int FillSlotFeature(uint64_t* d_walk, size_t key_num); int MakeInsPair(cudaStream_t stream); uint64_t CopyUniqueNodes(); int GetPathNum() { return total_row_; } void ResetPathNum() { total_row_ = 0; } void ResetEpochFinish() { epoch_finish_ = false; } void ClearSampleState(); void DumpWalkPath(std::string dump_path, size_t dump_rate); void SetDeviceKeys(std::vector* device_keys UNUSED, int type UNUSED) { // type_to_index_[type] = h_device_keys_.size(); // h_device_keys_.push_back(device_keys); } std::vector> SampleNeighbors( int64_t* uniq_nodes, int len, int sample_size, std::vector& edges_split_num, // NOLINT int64_t* neighbor_len); std::shared_ptr FillReindexHashTable(int64_t* input, int num_input, int64_t len_hashtable, int64_t* keys, int* values, int* key_index, int* final_nodes_len); std::shared_ptr GetReindexResult(int64_t* reindex_src_data, int64_t* center_nodes, int* final_nodes_len, int node_len, int64_t neighbor_len); std::shared_ptr GenerateSampleGraph( uint64_t* node_ids, int len, int* uniq_len, std::shared_ptr& inverse); // NOLINT std::shared_ptr GetNodeDegree(uint64_t* node_ids, int len); int InsertTable(const uint64_t* d_keys, uint64_t len, std::shared_ptr d_uniq_node_num); std::vector& GetHostVec() { return host_vec_; } bool get_epoch_finish() { return epoch_finish_; } void clear_gpu_mem(); protected: HashTable* table_; int walk_degree_; int walk_len_; int window_; int once_sample_startid_len_; int gpuid_; size_t cursor_; int thread_id_; size_t jump_rows_; int edge_to_id_len_; int64_t* id_tensor_ptr_; int* index_tensor_ptr_; int64_t* show_tensor_ptr_; int64_t* clk_tensor_ptr_; int* degree_tensor_ptr_; cudaStream_t train_stream_; cudaStream_t sample_stream_; paddle::platform::Place place_; std::vector feed_vec_; std::vector offset_; std::shared_ptr d_prefix_sum_; std::vector> d_device_keys_; std::shared_ptr d_train_metapath_keys_; std::shared_ptr d_walk_; std::shared_ptr d_walk_ntype_; std::shared_ptr d_excluded_train_pair_; std::shared_ptr d_feature_list_; std::shared_ptr d_feature_; std::shared_ptr d_len_per_row_; std::shared_ptr d_random_row_; std::shared_ptr d_uniq_node_num_; std::shared_ptr d_slot_feature_num_map_; std::shared_ptr d_actual_slot_id_map_; std::shared_ptr d_fea_offset_map_; std::vector> d_sampleidx2rows_; int cur_sampleidx2row_; // record the keys to call graph_neighbor_sample std::shared_ptr d_sample_keys_; int sample_keys_len_; std::shared_ptr d_ins_buf_; std::shared_ptr d_feature_size_list_buf_; std::shared_ptr d_feature_size_prefixsum_buf_; std::shared_ptr d_pair_num_; std::shared_ptr d_slot_tensor_ptr_; std::shared_ptr d_slot_lod_tensor_ptr_; std::shared_ptr d_reindex_table_key_; std::shared_ptr d_reindex_table_value_; std::shared_ptr d_reindex_table_index_; std::vector> edge_type_graph_; std::shared_ptr d_sorted_keys_; std::shared_ptr d_sorted_idx_; std::shared_ptr d_offset_; std::shared_ptr d_merged_cnts_; std::shared_ptr d_buf_; // sage mode batch data std::vector> inverse_vec_; std::vector> final_sage_nodes_vec_; std::vector> node_degree_vec_; std::vector uniq_instance_vec_; std::vector total_instance_vec_; std::vector>> graph_edges_vec_; std::vector>> edges_split_num_vec_; int excluded_train_pair_len_; int64_t reindex_table_size_; int sage_batch_count_; int sage_batch_num_; int ins_buf_pair_len_; // size of a d_walk buf size_t buf_size_; int repeat_time_; std::vector window_step_; BufState buf_state_; int batch_size_; int slot_num_; std::vector h_slot_feature_num_map_; int fea_num_per_node_; int shuffle_seed_; int debug_mode_; bool gpu_graph_training_; bool sage_mode_; std::vector samples_; bool epoch_finish_; std::vector host_vec_; std::vector h_device_keys_len_; uint64_t h_train_metapath_keys_len_; uint64_t train_table_cap_; uint64_t infer_table_cap_; uint64_t copy_unique_len_; int total_row_; size_t infer_node_start_; size_t infer_node_end_; std::set infer_node_type_index_set_; std::string infer_node_type_; bool get_degree_; }; class DataFeed { public: DataFeed() { mutex_for_pick_file_ = nullptr; file_idx_ = nullptr; mutex_for_fea_num_ = nullptr; total_fea_num_ = nullptr; } virtual ~DataFeed() {} virtual void Init(const DataFeedDesc& data_feed_desc) = 0; virtual bool CheckFile(const char* filename UNUSED) { PADDLE_THROW(platform::errors::Unimplemented( "This function(CheckFile) is not implemented.")); } // Set filelist for DataFeed. // Pay attention that it must init all readers before call this function. // Otherwise, Init() function will init finish_set_filelist_ flag. virtual bool SetFileList(const std::vector& files); virtual bool Start() = 0; // The trainer calls the Next() function, and the DataFeed will load a new // batch to the feed_vec. The return value of this function is the batch // size of the current batch. virtual int Next() = 0; // Get all slots' alias which defined in protofile virtual const std::vector& GetAllSlotAlias() { return all_slots_; } // Get used slots' alias which defined in protofile virtual const std::vector& GetUseSlotAlias() { return use_slots_; } // This function is used for binding feed_vec memory virtual void AddFeedVar(Variable* var, const std::string& name); // This function is used for binding feed_vec memory in a given scope virtual void AssignFeedVar(const Scope& scope); virtual std::vector GetInputVarNames() { return std::vector(); } // This function will do nothing at default virtual void SetInputPvChannel(void* channel UNUSED) {} // This function will do nothing at default virtual void SetOutputPvChannel(void* channel UNUSED) {} // This function will do nothing at default virtual void SetConsumePvChannel(void* channel UNUSED) {} // This function will do nothing at default virtual void SetInputChannel(void* channel UNUSED) {} // This function will do nothing at default virtual void SetOutputChannel(void* channel UNUSED) {} // This function will do nothing at default virtual void SetConsumeChannel(void* channel UNUSED) {} // This function will do nothing at default virtual void SetThreadId(int thread_id UNUSED) {} // This function will do nothing at default virtual void SetThreadNum(int thread_num UNUSED) {} // This function will do nothing at default virtual void SetParseInsId(bool parse_ins_id UNUSED) {} virtual void SetParseUid(bool parse_uid UNUSED) {} virtual void SetParseContent(bool parse_content UNUSED) {} virtual void SetParseLogKey(bool parse_logkey UNUSED) {} virtual void SetEnablePvMerge(bool enable_pv_merge UNUSED) {} virtual void SetCurrentPhase(int current_phase UNUSED) {} #if defined(PADDLE_WITH_GPU_GRAPH) && defined(PADDLE_WITH_HETERPS) virtual void InitGraphResource() {} virtual void InitGraphTrainResource() {} virtual void SetDeviceKeys(std::vector* device_keys, int type) { gpu_graph_data_generator_.SetDeviceKeys(device_keys, type); } #endif virtual void SetGpuGraphMode(int gpu_graph_mode) { gpu_graph_mode_ = gpu_graph_mode; } virtual void SetFileListMutex(std::mutex* mutex) { mutex_for_pick_file_ = mutex; } virtual void SetFeaNumMutex(std::mutex* mutex) { mutex_for_fea_num_ = mutex; } virtual void SetFileListIndex(size_t* file_index) { file_idx_ = file_index; } virtual void SetFeaNum(uint64_t* fea_num) { total_fea_num_ = fea_num; } virtual const std::vector& GetInsIdVec() const { return ins_id_vec_; } virtual const std::vector& GetInsContentVec() const { return ins_content_vec_; } virtual void SetCurBatchSize(const int batch_size) { batch_size_ = batch_size; } virtual int GetCurBatchSize() { return batch_size_; } virtual int GetGraphPathNum() { #if defined(PADDLE_WITH_GPU_GRAPH) && defined(PADDLE_WITH_HETERPS) return gpu_graph_data_generator_.GetPathNum(); #else return 0; #endif } #if defined(PADDLE_WITH_GPU_GRAPH) && defined(PADDLE_WITH_HETERPS) virtual const std::vector* GetHostVec() { return &(gpu_graph_data_generator_.GetHostVec()); } virtual void clear_gpu_mem() { gpu_graph_data_generator_.clear_gpu_mem(); } virtual bool get_epoch_finish() { return gpu_graph_data_generator_.get_epoch_finish(); } virtual void ResetPathNum() { gpu_graph_data_generator_.ResetPathNum(); } virtual void ClearSampleState() { gpu_graph_data_generator_.ClearSampleState(); } virtual void ResetEpochFinish() { gpu_graph_data_generator_.ResetEpochFinish(); } virtual void DoWalkandSage() { PADDLE_THROW(platform::errors::Unimplemented( "This function(DoWalkandSage) is not implemented.")); } #endif virtual bool IsTrainMode() { return train_mode_; } virtual void LoadIntoMemory() { PADDLE_THROW(platform::errors::Unimplemented( "This function(LoadIntoMemory) is not implemented.")); } virtual void SetPlace(const paddle::platform::Place& place) { place_ = place; } virtual const paddle::platform::Place& GetPlace() const { return place_; } #if defined(PADDLE_WITH_CUDA) && defined(PADDLE_WITH_HETERPS) virtual MiniBatchGpuPack* get_pack(MiniBatchGpuPack* last_pack) { return nullptr; } virtual void PackToScope(MiniBatchGpuPack* pack, const Scope* scope) { PADDLE_THROW(platform::errors::Unimplemented( "This function(PackToScope) is not implemented.")); } virtual void SetInsIdVec(MiniBatchGpuPack* pack) {} #endif virtual void DumpWalkPath(std::string dump_path UNUSED, size_t dump_rate UNUSED) { PADDLE_THROW(platform::errors::Unimplemented( "This function(DumpWalkPath) is not implemented.")); } protected: // The following three functions are used to check if it is executed in this // order: // Init() -> SetFileList() -> Start() -> Next() virtual void CheckInit(); virtual void CheckSetFileList(); virtual void CheckStart(); virtual void SetBatchSize( int batch); // batch size will be set in Init() function // This function is used to pick one file from the global filelist(thread // safe). virtual bool PickOneFile(std::string* filename); virtual void CopyToFeedTensor(void* dst, const void* src, size_t size); std::vector filelist_; size_t* file_idx_; std::mutex* mutex_for_pick_file_; std::mutex* mutex_for_fea_num_ = nullptr; uint64_t* total_fea_num_ = nullptr; uint64_t fea_num_ = 0; // the alias of used slots, and its order is determined by // data_feed_desc(proto object) std::vector use_slots_; std::vector use_slots_is_dense_; // the alias of all slots, and its order is determined by data_feed_desc(proto // object) std::vector all_slots_; std::vector all_slots_type_; std::vector> use_slots_shape_; std::vector inductive_shape_index_; std::vector total_dims_without_inductive_; // For the inductive shape passed within data std::vector> multi_inductive_shape_index_; std::vector use_slots_index_; // -1: not used; >=0: the index of use_slots_ // The data read by DataFeed will be stored here std::vector feed_vec_; phi::DenseTensor* rank_offset_; // the batch size defined by user int default_batch_size_; // current batch size int batch_size_; bool finish_init_; bool finish_set_filelist_; bool finish_start_; std::string pipe_command_; std::string so_parser_name_; std::vector slot_conf_; std::vector ins_id_vec_; std::vector ins_content_vec_; platform::Place place_; std::string uid_slot_; // The input type of pipe reader, 0 for one sample, 1 for one batch int input_type_; int gpu_graph_mode_ = 0; #if defined(PADDLE_WITH_GPU_GRAPH) && defined(PADDLE_WITH_HETERPS) GraphDataGenerator gpu_graph_data_generator_; #endif bool train_mode_; }; // PrivateQueueDataFeed is the base virtual class for ohther DataFeeds. // It use a read-thread to read file and parse data to a private-queue // (thread level), and get data from this queue when trainer call Next(). template class PrivateQueueDataFeed : public DataFeed { public: PrivateQueueDataFeed() {} virtual ~PrivateQueueDataFeed() {} virtual bool Start(); virtual int Next(); protected: // The thread implementation function for reading file and parse. virtual void ReadThread(); // This function is used to set private-queue size, and the most // efficient when the queue size is close to the batch size. virtual void SetQueueSize(int queue_size); // The reading and parsing method called in the ReadThread. virtual bool ParseOneInstance(T* instance) = 0; virtual bool ParseOneInstanceFromPipe(T* instance) = 0; // This function is used to put instance to vec_ins virtual void AddInstanceToInsVec(T* vec_ins, const T& instance, int index) = 0; // This function is used to put ins_vec to feed_vec virtual void PutToFeedVec(const T& ins_vec) = 0; // The thread for read files std::thread read_thread_; // using ifstream one line and one line parse is faster // than using fread one buffer and one buffer parse. // for a 601M real data: // ifstream one line and one line parse: 6034 ms // fread one buffer and one buffer parse: 7097 ms std::ifstream file_; std::shared_ptr fp_; size_t queue_size_; string::LineFileReader reader_; // The queue for store parsed data std::shared_ptr> queue_; }; template class InMemoryDataFeed : public DataFeed { public: InMemoryDataFeed(); virtual ~InMemoryDataFeed() {} virtual void Init(const DataFeedDesc& data_feed_desc) = 0; virtual bool Start(); virtual int Next(); virtual void SetInputPvChannel(void* channel); virtual void SetOutputPvChannel(void* channel); virtual void SetConsumePvChannel(void* channel); virtual void SetInputChannel(void* channel); virtual void SetOutputChannel(void* channel); virtual void SetConsumeChannel(void* channel); virtual void SetThreadId(int thread_id); virtual void SetThreadNum(int thread_num); virtual void SetParseInsId(bool parse_ins_id); virtual void SetParseUid(bool parse_uid); virtual void SetParseContent(bool parse_content); virtual void SetParseLogKey(bool parse_logkey); virtual void SetEnablePvMerge(bool enable_pv_merge); virtual void SetCurrentPhase(int current_phase); virtual void LoadIntoMemory(); virtual void LoadIntoMemoryFromSo(); virtual void SetRecord(T* records) { records_ = records; } int GetDefaultBatchSize() { return default_batch_size_; } void AddBatchOffset(const std::pair& offset) { batch_offsets_.push_back(offset); } protected: virtual bool ParseOneInstance(T* instance) = 0; virtual bool ParseOneInstanceFromPipe(T* instance) = 0; virtual void ParseOneInstanceFromSo(const char* str UNUSED, T* instance UNUSED, CustomParser* parser UNUSED) {} virtual int ParseInstanceFromSo(int len UNUSED, const char* str UNUSED, std::vector* instances UNUSED, CustomParser* parser UNUSED) { return 0; } virtual void PutToFeedVec(const std::vector& ins_vec) = 0; virtual void PutToFeedVec(const T* ins_vec, int num) = 0; std::vector> batch_float_feasigns_; std::vector> batch_uint64_feasigns_; std::vector> offset_; std::vector visit_; int thread_id_; int thread_num_; bool parse_ins_id_; bool parse_uid_; bool parse_content_; bool parse_logkey_; bool enable_pv_merge_; int current_phase_{-1}; // only for untest std::ifstream file_; std::shared_ptr fp_; paddle::framework::ChannelObject* input_channel_; paddle::framework::ChannelObject* output_channel_; paddle::framework::ChannelObject* consume_channel_; paddle::framework::ChannelObject* input_pv_channel_; paddle::framework::ChannelObject* output_pv_channel_; paddle::framework::ChannelObject* consume_pv_channel_; std::vector> batch_offsets_; uint64_t offset_index_ = 0; bool enable_heterps_ = false; T* records_ = nullptr; }; // This class define the data type of instance(ins_vec) in MultiSlotDataFeed class MultiSlotType { public: MultiSlotType() {} ~MultiSlotType() {} void Init(const std::string& type, size_t reserved_size = 0) { CheckType(type); if (type_[0] == 'f') { float_feasign_.clear(); if (reserved_size) { float_feasign_.reserve(reserved_size); } } else if (type_[0] == 'u') { uint64_feasign_.clear(); if (reserved_size) { uint64_feasign_.reserve(reserved_size); } } type_ = type; } void InitOffset(size_t max_batch_size = 0) { if (max_batch_size > 0) { offset_.reserve(max_batch_size + 1); } offset_.resize(1); // LoDTensor' lod is counted from 0, the size of lod // is one size larger than the size of data. offset_[0] = 0; } const std::vector& GetOffset() const { return offset_; } std::vector& MutableOffset() { return offset_; } void AddValue(const float v) { CheckFloat(); float_feasign_.push_back(v); } void AddValue(const uint64_t v) { CheckUint64(); uint64_feasign_.push_back(v); } void CopyValues(const float* input, size_t size) { CheckFloat(); float_feasign_.resize(size); memcpy(float_feasign_.data(), input, size * sizeof(float)); } void CopyValues(const uint64_t* input, size_t size) { CheckUint64(); uint64_feasign_.resize(size); memcpy(uint64_feasign_.data(), input, size * sizeof(uint64_t)); } void AddIns(const MultiSlotType& ins) { if (ins.GetType()[0] == 'f') { // float CheckFloat(); auto& vec = ins.GetFloatData(); offset_.push_back(offset_.back() + vec.size()); float_feasign_.insert(float_feasign_.end(), vec.begin(), vec.end()); } else if (ins.GetType()[0] == 'u') { // uint64 CheckUint64(); auto& vec = ins.GetUint64Data(); offset_.push_back(offset_.back() + vec.size()); uint64_feasign_.insert(uint64_feasign_.end(), vec.begin(), vec.end()); } } void AppendValues(const uint64_t* input, size_t size) { CheckUint64(); offset_.push_back(offset_.back() + size); uint64_feasign_.insert(uint64_feasign_.end(), input, input + size); } void AppendValues(const float* input, size_t size) { CheckFloat(); offset_.push_back(offset_.back() + size); float_feasign_.insert(float_feasign_.end(), input, input + size); } const std::vector& GetFloatData() const { return float_feasign_; } std::vector& MutableFloatData() { return float_feasign_; } const std::vector& GetUint64Data() const { return uint64_feasign_; } std::vector& MutableUint64Data() { return uint64_feasign_; } const std::string& GetType() const { return type_; } size_t GetBatchSize() { return offset_.size() - 1; } std::string& MutableType() { return type_; } std::string DebugString() { std::stringstream ss; ss << "\ntype: " << type_ << "\n"; ss << "offset: "; ss << "["; for (const size_t& i : offset_) { ss << offset_[i] << ","; } ss << "]\ndata: ["; if (type_[0] == 'f') { for (const float& i : float_feasign_) { ss << i << ","; } } else { for (const uint64_t& i : uint64_feasign_) { ss << i << ","; } } ss << "]\n"; return ss.str(); } private: void CheckType(const std::string& type) const { PADDLE_ENFORCE_EQ((type == "uint64" || type == "float"), true, platform::errors::InvalidArgument( "MultiSlotType error, expect type is uint64 or " "float, but received type is %s.", type)); } void CheckFloat() const { PADDLE_ENFORCE_EQ( type_[0], 'f', platform::errors::InvalidArgument( "MultiSlotType error, add %s value to float slot.", type_)); } void CheckUint64() const { PADDLE_ENFORCE_EQ( type_[0], 'u', platform::errors::InvalidArgument( "MultiSlotType error, add %s value to uint64 slot.", type_)); } std::vector float_feasign_; std::vector uint64_feasign_; std::string type_; std::vector offset_; }; template paddle::framework::Archive& operator<<(paddle::framework::Archive& ar, const MultiSlotType& ins) { ar << ins.GetType(); #ifdef _LINUX ar << ins.GetOffset(); #else const auto& offset = ins.GetOffset(); ar << (uint64_t)offset.size(); for (const size_t& x : offset) { ar << (const uint64_t)x; } #endif ar << ins.GetFloatData(); ar << ins.GetUint64Data(); return ar; } template paddle::framework::Archive& operator>>(paddle::framework::Archive& ar, MultiSlotType& ins) { ar >> ins.MutableType(); #ifdef _LINUX ar >> ins.MutableOffset(); #else auto& offset = ins.MutableOffset(); offset.resize(ar.template Get()); for (size_t& x : offset) { uint64_t t; ar >> t; x = static_cast(t); } #endif ar >> ins.MutableFloatData(); ar >> ins.MutableUint64Data(); return ar; } struct RecordCandidate { std::string ins_id_; std::unordered_multimap feas_; size_t shadow_index_ = -1; // Optimization for Reservoir Sample RecordCandidate() {} RecordCandidate(const Record& rec, const std::unordered_set& slot_index_to_replace) { for (const auto& fea : rec.uint64_feasigns_) { if (slot_index_to_replace.find(fea.slot()) != slot_index_to_replace.end()) { feas_.insert({fea.slot(), fea.sign()}); } } } RecordCandidate& operator=(const Record& rec) { feas_.clear(); ins_id_ = rec.ins_id_; for (auto& fea : rec.uint64_feasigns_) { feas_.insert({fea.slot(), fea.sign()}); } return *this; } }; class RecordCandidateList { public: RecordCandidateList() = default; RecordCandidateList(const RecordCandidateList& UNUSED) {} size_t Size() { return cur_size_; } void ReSize(size_t length); void ReInit(); void ReInitPass() { for (size_t i = 0; i < cur_size_; ++i) { if (candidate_list_[i].shadow_index_ != i) { candidate_list_[i].ins_id_ = candidate_list_[candidate_list_[i].shadow_index_].ins_id_; candidate_list_[i].feas_.swap( candidate_list_[candidate_list_[i].shadow_index_].feas_); candidate_list_[i].shadow_index_ = i; } } candidate_list_.resize(cur_size_); } void AddAndGet(const Record& record, RecordCandidate* result); void AddAndGet(const Record& record, size_t& index_result) { // NOLINT // std::unique_lock lock(mutex_); size_t index = 0; ++total_size_; auto fleet_ptr = FleetWrapper::GetInstance(); if (!full_) { candidate_list_.emplace_back(record, slot_index_to_replace_); candidate_list_.back().shadow_index_ = cur_size_; ++cur_size_; full_ = (cur_size_ == capacity_); } else { index = fleet_ptr->LocalRandomEngine()() % total_size_; if (index < capacity_) { candidate_list_.emplace_back(record, slot_index_to_replace_); candidate_list_[index].shadow_index_ = candidate_list_.size() - 1; } } index = fleet_ptr->LocalRandomEngine()() % cur_size_; index_result = candidate_list_[index].shadow_index_; } const RecordCandidate& Get(size_t index) const { PADDLE_ENFORCE_LT( index, candidate_list_.size(), platform::errors::OutOfRange("Your index [%lu] exceeds the number of " "elements in candidate_list[%lu].", index, candidate_list_.size())); return candidate_list_[index]; } void SetSlotIndexToReplace( const std::unordered_set& slot_index_to_replace) { slot_index_to_replace_ = slot_index_to_replace; } private: size_t capacity_ = 0; std::mutex mutex_; bool full_ = false; size_t cur_size_ = 0; size_t total_size_ = 0; std::vector candidate_list_; std::unordered_set slot_index_to_replace_; }; template paddle::framework::Archive& operator<<(paddle::framework::Archive& ar, const FeatureFeasign& fk) { ar << fk.uint64_feasign_; ar << fk.float_feasign_; return ar; } template paddle::framework::Archive& operator>>(paddle::framework::Archive& ar, FeatureFeasign& fk) { ar >> fk.uint64_feasign_; ar >> fk.float_feasign_; return ar; } template paddle::framework::Archive& operator<<(paddle::framework::Archive& ar, const FeatureItem& fi) { ar << fi.sign(); ar << fi.slot(); return ar; } template paddle::framework::Archive& operator>>(paddle::framework::Archive& ar, FeatureItem& fi) { ar >> fi.sign(); ar >> fi.slot(); return ar; } template paddle::framework::Archive& operator<<(paddle::framework::Archive& ar, const Record& r) { ar << r.uint64_feasigns_; ar << r.float_feasigns_; ar << r.ins_id_; return ar; } template paddle::framework::Archive& operator>>(paddle::framework::Archive& ar, Record& r) { ar >> r.uint64_feasigns_; ar >> r.float_feasigns_; ar >> r.ins_id_; return ar; } // This DataFeed is used to feed multi-slot type data. // The format of multi-slot type data: // [n feasign_0 feasign_1 ... feasign_n]* class MultiSlotDataFeed : public PrivateQueueDataFeed> { public: MultiSlotDataFeed() {} virtual ~MultiSlotDataFeed() {} virtual void Init(const DataFeedDesc& data_feed_desc); virtual bool CheckFile(const char* filename); protected: virtual void ReadThread(); virtual void AddInstanceToInsVec(std::vector* vec_ins, const std::vector& instance, int index); virtual bool ParseOneInstance(std::vector* instance); virtual bool ParseOneInstanceFromPipe(std::vector* instance); virtual void PutToFeedVec(const std::vector& ins_vec); }; class MultiSlotInMemoryDataFeed : public InMemoryDataFeed { public: MultiSlotInMemoryDataFeed() {} virtual ~MultiSlotInMemoryDataFeed() {} virtual void Init(const DataFeedDesc& data_feed_desc); // void SetRecord(Record* records) { records_ = records; } protected: virtual bool ParseOneInstance(Record* instance); virtual bool ParseOneInstanceFromPipe(Record* instance); virtual void ParseOneInstanceFromSo(const char* str UNUSED, Record* instance UNUSED, CustomParser* parser UNUSED) {} virtual int ParseInstanceFromSo(int len, const char* str, std::vector* instances, CustomParser* parser); virtual void PutToFeedVec(const std::vector& ins_vec); virtual void GetMsgFromLogKey(const std::string& log_key, uint64_t* search_id, uint32_t* cmatch, uint32_t* rank); virtual void PutToFeedVec(const Record* ins_vec, int num); }; class SlotRecordInMemoryDataFeed : public InMemoryDataFeed { public: SlotRecordInMemoryDataFeed() {} virtual ~SlotRecordInMemoryDataFeed(); void Init(const DataFeedDesc& data_feed_desc) override; void LoadIntoMemory() override; void ExpandSlotRecord(SlotRecord* ins); protected: bool Start() override; int Next() override; bool ParseOneInstance(SlotRecord* instance UNUSED) override { return false; } bool ParseOneInstanceFromPipe(SlotRecord* instance UNUSED) override { return false; } // virtual void ParseOneInstanceFromSo(const char* str, T* instance, // CustomParser* parser) {} void PutToFeedVec(const std::vector& ins_vec UNUSED) override {} virtual void LoadIntoMemoryByCommand(void); virtual void LoadIntoMemoryByLib(void); virtual void LoadIntoMemoryByLine(void); virtual void LoadIntoMemoryByFile(void); void SetInputChannel(void* channel) override { input_channel_ = static_cast*>(channel); } bool ParseOneInstance(const std::string& line, SlotRecord* rec); void PutToFeedVec(const SlotRecord* ins_vec, int num) override; void AssignFeedVar(const Scope& scope) override; std::vector GetInputVarNames() override { std::vector var_names; for (int i = 0; i < use_slot_size_; ++i) { var_names.push_back(used_slots_info_[i].slot); } return var_names; } #if defined(PADDLE_WITH_CUDA) && defined(PADDLE_WITH_HETERPS) void BuildSlotBatchGPU(const int ins_num, MiniBatchGpuPack* pack); virtual MiniBatchGpuPack* get_pack(MiniBatchGpuPack* last_pack); virtual void PackToScope(MiniBatchGpuPack* pack, const Scope* scope = nullptr); void FillSlotValueOffset(const int ins_num, const int used_slot_num, size_t* slot_value_offsets, const int* uint64_offsets, const int uint64_slot_size, const int* float_offsets, const int float_slot_size, const UsedSlotGpuType* used_slots, cudaStream_t stream); void CopyForTensor(const int ins_num, const int used_slot_num, void** dest, const size_t* slot_value_offsets, const uint64_t* uint64_feas, const int* uint64_offsets, const int* uint64_ins_lens, const int uint64_slot_size, const float* float_feas, const int* float_offsets, const int* float_ins_lens, const int float_slot_size, const UsedSlotGpuType* used_slots, cudaStream_t stream); #endif #if defined(PADDLE_WITH_GPU_GRAPH) && defined(PADDLE_WITH_HETERPS) virtual void InitGraphResource(void); virtual void InitGraphTrainResource(void); virtual void DoWalkandSage(); void SetInsIdVec(MiniBatchGpuPack* pack) override { if (parse_ins_id_) { size_t ins_num = pack->ins_num(); ins_id_vec_.clear(); ins_id_vec_.resize(ins_num); for (size_t i = 0; i < ins_num; i++) { ins_id_vec_[i] = pack->get_lineid(i); } } } #endif void DumpWalkPath(std::string dump_path, size_t dump_rate) override; float sample_rate_ = 1.0f; int use_slot_size_ = 0; int float_use_slot_size_ = 0; int uint64_use_slot_size_ = 0; std::vector all_slots_info_; std::vector used_slots_info_; size_t float_total_dims_size_ = 0; std::vector float_total_dims_without_inductives_; #if defined(PADDLE_WITH_CUDA) && defined(PADDLE_WITH_HETERPS) int pack_thread_num_{5}; std::vector pack_threads_; std::vector pack_vec_; BlockingQueue free_pack_queue_; BlockingQueue using_pack_queue_; std::atomic pack_is_end_{false}; std::atomic pack_offset_index_{0}; MiniBatchGpuPack* last_pack_{nullptr}; std::atomic stop_token_{false}; std::atomic thread_count_{0}; std::mutex pack_mutex_; // async infershape std::map> scpoe_feed_vec_; #endif }; class PaddleBoxDataFeed : public MultiSlotInMemoryDataFeed { public: PaddleBoxDataFeed() {} virtual ~PaddleBoxDataFeed() {} protected: virtual void Init(const DataFeedDesc& data_feed_desc); virtual bool Start(); virtual int Next(); virtual void AssignFeedVar(const Scope& scope); virtual void PutToFeedVec(const std::vector& pv_vec); virtual void PutToFeedVec(const std::vector& ins_vec); virtual int GetCurrentPhase(); virtual void GetRankOffset(const std::vector& pv_vec, int ins_number); std::string rank_offset_name_; int pv_batch_size_; }; #if (defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)) && !defined(_WIN32) template class PrivateInstantDataFeed : public DataFeed { public: PrivateInstantDataFeed() {} virtual ~PrivateInstantDataFeed() {} void Init(const DataFeedDesc& data_feed_desc) override; bool Start() override { return true; } int Next() override; protected: // The batched data buffer std::vector ins_vec_; // This function is used to preprocess with a given filename, e.g. open it or // mmap virtual bool Preprocess(const std::string& filename) = 0; // This function is used to postprocess system resource such as closing file // NOTICE: Ensure that it is safe to call before Preprocess virtual bool Postprocess() = 0; // The reading and parsing method. virtual bool ParseOneMiniBatch() = 0; // This function is used to put ins_vec to feed_vec virtual void PutToFeedVec(); }; class MultiSlotFileInstantDataFeed : public PrivateInstantDataFeed> { public: MultiSlotFileInstantDataFeed() {} virtual ~MultiSlotFileInstantDataFeed() {} protected: int fd_{-1}; char* buffer_{nullptr}; size_t end_{0}; size_t offset_{0}; bool Preprocess(const std::string& filename) override; bool Postprocess() override; bool ParseOneMiniBatch() override; }; #endif } // namespace framework } // namespace paddle