dmlc--dgl
69a532c1ab
Co-authored-by: xiny <xiny@nvidia.com>
175 行
5.5 KiB
C++
175 行
5.5 KiB
C++
/*
|
|
* Copyright (c) 2023, NVIDIA 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.
|
|
*/
|
|
#pragma once
|
|
#include <nv_util.h>
|
|
|
|
#include <thread>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
namespace gpu_cache {
|
|
|
|
template <typename key_type, typename index_type>
|
|
class HashBlock {
|
|
public:
|
|
key_type* keys;
|
|
size_t num_sets;
|
|
size_t capacity;
|
|
|
|
HashBlock(size_t expected_capacity, int set_size, int batch_size);
|
|
~HashBlock();
|
|
void add(const key_type* new_keys, const size_t num_keys, key_type* missing_keys,
|
|
int* num_missing_keys, cudaStream_t stream);
|
|
void query(const key_type* query_keys, const size_t num_keys, index_type* output_indices,
|
|
key_type* missing_keys, int* missing_positions, int* num_missing_keys,
|
|
cudaStream_t stream);
|
|
void query(const key_type* query_keys, int* num_keys, index_type* output_indices,
|
|
cudaStream_t stream);
|
|
void clear(cudaStream_t stream);
|
|
|
|
private:
|
|
int max_set_size_;
|
|
int batch_size_;
|
|
int* set_sizes_;
|
|
};
|
|
|
|
template <typename vec_type>
|
|
class H2HCopy {
|
|
public:
|
|
H2HCopy(int num_threads) : num_threads_(num_threads), working_(num_threads) {
|
|
for (int i = 0; i < num_threads_; i++) {
|
|
threads_.emplace_back(
|
|
[&](int idx) {
|
|
while (!terminate_) {
|
|
if (working_[idx].load(std::memory_order_relaxed)) {
|
|
working_[idx].store(false, std::memory_order_relaxed);
|
|
if (num_keys_ == 0) continue;
|
|
size_t num_keys_this_thread = (num_keys_ - 1) / num_threads_ + 1;
|
|
size_t begin = idx * num_keys_this_thread;
|
|
if (idx == num_threads_ - 1) {
|
|
num_keys_this_thread = num_keys_ - num_keys_this_thread * idx;
|
|
}
|
|
size_t end = begin + num_keys_this_thread;
|
|
|
|
for (size_t i = begin; i < end; i++) {
|
|
size_t idx_vec = get_index_(i);
|
|
if (idx_vec == std::numeric_limits<size_t>::max()) {
|
|
continue;
|
|
}
|
|
memcpy(dst_data_ptr_ + i * vec_size_, src_data_ptr_ + idx_vec * vec_size_,
|
|
sizeof(vec_type) * vec_size_);
|
|
}
|
|
num_finished_workers_++;
|
|
}
|
|
}
|
|
std::this_thread::sleep_for(std::chrono::microseconds(1));
|
|
},
|
|
i);
|
|
}
|
|
};
|
|
|
|
void copy(vec_type* dst_data_ptr, vec_type* src_data_ptr, size_t num_keys, int vec_size,
|
|
std::function<size_t(size_t)> get_index_func) {
|
|
std::lock_guard<std::mutex> guard(submit_mutex_);
|
|
dst_data_ptr_ = dst_data_ptr;
|
|
src_data_ptr_ = src_data_ptr;
|
|
get_index_ = get_index_func;
|
|
num_keys_ = num_keys;
|
|
vec_size_ = vec_size;
|
|
num_finished_workers_.store(0, std::memory_order_acquire);
|
|
|
|
for (auto& working : working_) {
|
|
working.store(true, std::memory_order_relaxed);
|
|
}
|
|
|
|
while (num_finished_workers_ != num_threads_) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
~H2HCopy() {
|
|
terminate_ = true;
|
|
for (auto& t : threads_) {
|
|
t.join();
|
|
}
|
|
}
|
|
|
|
private:
|
|
vec_type* src_data_ptr_;
|
|
vec_type* dst_data_ptr_;
|
|
|
|
std::function<size_t(size_t)> get_index_;
|
|
|
|
size_t num_keys_;
|
|
int vec_size_;
|
|
|
|
std::mutex submit_mutex_;
|
|
const int num_threads_;
|
|
std::vector<std::thread> threads_;
|
|
std::vector<std::atomic<bool>> working_;
|
|
volatile bool terminate_{false};
|
|
std::atomic<int> num_finished_workers_{0};
|
|
};
|
|
|
|
template <typename key_type, typename index_type, typename vec_type = float>
|
|
class UvmTable {
|
|
public:
|
|
UvmTable(const size_t device_table_capacity, const size_t host_table_capacity,
|
|
const int max_batch_size, const int vec_size,
|
|
const vec_type default_value = (vec_type)0);
|
|
~UvmTable();
|
|
void query(const key_type* d_keys, const int len, vec_type* d_vectors, cudaStream_t stream = 0);
|
|
void add(const key_type* h_keys, const vec_type* h_vectors, const size_t len);
|
|
void clear(cudaStream_t stream = 0);
|
|
|
|
private:
|
|
static constexpr int num_buffers_ = 2;
|
|
key_type* d_keys_buffer_;
|
|
vec_type* d_vectors_buffer_;
|
|
vec_type* d_vectors_;
|
|
|
|
index_type* d_output_indices_;
|
|
index_type* d_output_host_indices_;
|
|
index_type* h_output_host_indices_;
|
|
|
|
key_type* d_missing_keys_;
|
|
int* d_missing_positions_;
|
|
int* d_missing_count_;
|
|
|
|
std::vector<vec_type> h_vectors_;
|
|
key_type* h_missing_keys_;
|
|
|
|
cudaStream_t query_stream_;
|
|
cudaEvent_t query_event_;
|
|
|
|
vec_type* h_cpy_buffers_[num_buffers_];
|
|
vec_type* d_cpy_buffers_[num_buffers_];
|
|
cudaStream_t cpy_streams_[num_buffers_];
|
|
cudaEvent_t cpy_events_[num_buffers_];
|
|
|
|
std::unordered_map<key_type, index_type> h_final_missing_items_;
|
|
|
|
int max_batch_size_;
|
|
int vec_size_;
|
|
size_t num_set_;
|
|
size_t num_host_set_;
|
|
size_t table_capacity_;
|
|
std::vector<vec_type> default_vector_;
|
|
|
|
HashBlock<key_type, index_type> device_table_;
|
|
HashBlock<key_type, index_type> host_table_;
|
|
};
|
|
} // namespace gpu_cache
|