Skip to content

Commit a263eb8

Browse files
author
dyzheng
committed
Feat(psi): add PsiStorageMode and device_memory_mode for GPU paging
Port PAGED_GPU infrastructure from LTS-gpu-paged branch: - Add PsiStorageMode enum (ALL_GPU, ALL_CPU, PAGED_GPU) to psi namespace - Add paging members (psi_cpu_, psi_gpu_buffer_, current_k_gpu_, streams) - Add paging methods: set_storage_mode, load_k_to_gpu, store_k_from_gpu, ensure_k_on_gpu, set_psi_cpu_external, get_cpu_pointer - Modify resize() to allocate CPU storage + single-k GPU buffer in PAGED_GPU mode, reducing GPU memory for large k-point calculations - Modify destructor to clean up paging resources - Propagate storage_mode_ in copy constructors - Add device_memory_mode INPUT parameter (''/full_gpu/paged) - Create psi_paging.cpp with paging method implementations Note: uses memcpy for CPU-side transfers (DEVICE_CPU), actual GPU-to-CPU transfers via synchronize_memory_op will be added in a subsequent phase with GPU FFT pipeline integration.
1 parent a04393e commit a263eb8

6 files changed

Lines changed: 302 additions & 17 deletions

File tree

source/source_io/module_parameter/input_parameter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ struct Input_para
8787
///< use mesh, which is used in QE.
8888
int nspin = 1; ///< LDA ; LSDA ; non-linear spin
8989
int gga_grad = 3; ///< GGA gradient method for noncollinear spin (nspin=4): 1=collinear approx, 2=projected div(h), 3=Scalmani-Frisch transform (default, most accurate)
90+
std::string device_memory_mode = ""; ///< GPU memory mode: "" (auto), "full_gpu" (all on GPU), "paged" (CPU storage + k-point paging)
9091
int pw_diag_nmax = 50;
9192
double pw_diag_thr = 0.01; ///< used in cg method
9293
bool diago_smooth_ethr = false; ///< smooth ethr for iter methods

source/source_io/module_parameter/read_input_item_system.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,30 @@ Available options are:
701701
};
702702
this->add_item(item);
703703
}
704+
{
705+
Input_Item item("device_memory_mode");
706+
item.annotation = "GPU memory strategy for wavefunction storage";
707+
item.category = "System variables";
708+
item.type = "String";
709+
item.description = R"(Controls GPU memory strategy for wavefunction storage.
710+
* "" (empty/auto): Automatic selection based on system size.
711+
* "full_gpu": All wavefunction data resides on GPU (default behavior).
712+
* "paged": CPU storage with single k-point paging to GPU, reduces GPU memory at the cost of transfer overhead.
713+
714+
Only relevant when device=gpu and basis_type=pw.)";
715+
item.default_value = "";
716+
item.unit = "";
717+
item.availability = "Only relevant when device=gpu with PW basis";
718+
read_sync_string(input.device_memory_mode);
719+
item.check_value = [](const Input_Item& item, const Parameter& para) {
720+
const std::vector<std::string> avail_list = {"", "full_gpu", "paged"};
721+
if (std::find(avail_list.begin(), avail_list.end(), para.input.device_memory_mode) == avail_list.end())
722+
{
723+
ModuleBase::WARNING_QUIT("ReadInput", "device_memory_mode must be empty, full_gpu, or paged.");
724+
}
725+
};
726+
this->add_item(item);
727+
}
704728
{
705729
Input_Item item("precision");
706730
item.annotation = "the computing precision for ABACUS";

source/source_psi/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_library(
22
psi
33
OBJECT
44
psi.cpp
5+
psi_paging.cpp
56
)
67

78
add_library(

source/source_psi/psi.cpp

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
#include "psi.h"
22

33
#include "source_base/global_variable.h"
4+
#include "source_base/memory.h"
45
#include "source_base/module_device/device.h"
56
#include "source_base/tool_quit.h"
67
#include "source_io/module_parameter/parameter.h"
78

89
#include <cassert>
910
#include <complex>
11+
#include <cstring>
1012
#include <type_traits>
1113

1214
namespace psi
@@ -41,6 +43,16 @@ Psi<T, Device>::~Psi()
4143
{
4244
delete_memory_op()(this->psi);
4345
}
46+
47+
if (psi_cpu_ != nullptr && psi_cpu_owned_)
48+
{
49+
delete[] psi_cpu_;
50+
}
51+
psi_cpu_ = nullptr;
52+
53+
psi_gpu_buffer_ = nullptr;
54+
55+
current_k_gpu_ = -1;
4456
}
4557

4658
// Constructor 1:
@@ -160,12 +172,21 @@ Psi<T, Device>::Psi(const Psi& psi_in)
160172
this->current_k = psi_in.get_current_k();
161173
this->current_b = psi_in.get_current_b();
162174
this->k_first = psi_in.get_k_first();
163-
// this function will copy psi_in.psi to this->psi no matter the device types of each other.
175+
this->storage_mode_ = psi_in.get_storage_mode();
164176

165177
this->resize(psi_in.get_nk(), psi_in.get_nbands(), psi_in.get_nbasis());
166-
base_device::memory::synchronize_memory_op<T, Device, Device>()(this->psi,
167-
psi_in.get_pointer() - psi_in.get_psi_bias(),
168-
psi_in.size());
178+
179+
if (this->storage_mode_ == PsiStorageMode::PAGED_GPU && psi_cpu_ != nullptr)
180+
{
181+
const size_t total_size = static_cast<size_t>(this->nk) * this->nbands * this->nbasis;
182+
std::memcpy(this->psi_cpu_, psi_in.get_pointer() - psi_in.get_psi_bias(), sizeof(T) * total_size);
183+
}
184+
else
185+
{
186+
base_device::memory::synchronize_memory_op<T, Device, Device>()(this->psi,
187+
psi_in.get_pointer() - psi_in.get_psi_bias(),
188+
psi_in.size());
189+
}
169190
this->psi_bias = psi_in.get_psi_bias();
170191
this->current_nbasis = psi_in.get_current_nbas();
171192
this->psi_current = this->psi + psi_in.get_psi_bias();
@@ -184,16 +205,16 @@ Psi<T, Device>::Psi(const Psi<T_in, Device_in>& psi_in)
184205
this->current_k = psi_in.get_current_k();
185206
this->current_b = psi_in.get_current_b();
186207
this->k_first = psi_in.get_k_first();
187-
// this function will copy psi_in.psi to this->psi no matter the device types of each other.
208+
this->storage_mode_ = psi_in.get_storage_mode();
188209

189210
this->resize(psi_in.get_nk(), psi_in.get_nbands(), psi_in.get_nbasis());
190211

191-
// Specifically, if the Device_in type is CPU and the Device type is GPU.
192-
// Which means we need to initialize a GPU psi from a given CPU psi.
193-
// We first malloc a memory in CPU, then cast the memory from T_in to T in CPU.
194-
// Finally, synchronize the memory from CPU to GPU.
195-
// This could help to reduce the peak memory usage of device.
196-
if (std::is_same<Device, base_device::DEVICE_GPU>::value && std::is_same<Device_in, base_device::DEVICE_CPU>::value)
212+
if (this->storage_mode_ == PsiStorageMode::PAGED_GPU && psi_cpu_ != nullptr)
213+
{
214+
const size_t total_size = static_cast<size_t>(this->nk) * this->nbands * this->nbasis;
215+
std::memcpy(this->psi_cpu_, psi_in.get_pointer() - psi_in.get_psi_bias(), sizeof(T) * total_size);
216+
}
217+
else if (std::is_same<Device, base_device::DEVICE_GPU>::value && std::is_same<Device_in, base_device::DEVICE_CPU>::value)
197218
{
198219
auto* arr = (T*)malloc(sizeof(T) * psi_in.size());
199220
// cast the memory from T_in to T in CPU
@@ -250,21 +271,46 @@ Psi<T, Device>& Psi<T, Device>::operator=(const Psi<T, Device>& psi_in)
250271
}
251272

252273
template <typename T, typename Device>
253-
void Psi<T, Device>::resize(const int nks_in, const int nbands_in, const int nbasis_in)
274+
void Psi<T, Device>::resize(const int nks_in, const int nbands_in, const int nbasis_in, const bool skip_psi_cpu_alloc)
254275
{
255276
assert(nks_in > 0 && nbands_in >= 0 && nbasis_in > 0);
256277

257-
// This function will delete the psi array first(if psi exist), then malloc a new memory for it.
258-
resize_memory_op()(this->psi, nks_in * static_cast<std::size_t>(nbands_in) * nbasis_in, "no_record");
278+
if (storage_mode_ == PsiStorageMode::PAGED_GPU)
279+
{
280+
const size_t total_size = static_cast<size_t>(nks_in) * nbands_in * nbasis_in;
281+
if (!skip_psi_cpu_alloc)
282+
{
283+
if (psi_cpu_ != nullptr)
284+
{
285+
delete[] psi_cpu_;
286+
}
287+
psi_cpu_ = new T[total_size]();
288+
ModuleBase::Memory::record("Psi::psi_cpu", sizeof(T) * total_size);
289+
psi_cpu_owned_ = true;
290+
}
291+
292+
const size_t k_size = static_cast<size_t>(nbands_in) * nbasis_in;
293+
resize_memory_op()(this->psi, k_size, "no_record");
294+
#if defined(__CUDA) || defined(__ROCM)
295+
ModuleBase::Memory::record_gpu("Psi::psi_gpu_k", sizeof(T) * k_size);
296+
#endif
259297

260-
// this->zero_out();
298+
psi_gpu_buffer_ = this->psi;
299+
current_k_gpu_ = -1;
300+
}
301+
else
302+
{
303+
resize_memory_op()(this->psi, nks_in * static_cast<std::size_t>(nbands_in) * nbasis_in, "no_record");
304+
#if defined(__CUDA) || defined(__ROCM)
305+
ModuleBase::Memory::record_gpu("Psi_PW", sizeof(T) * nks_in * static_cast<std::size_t>(nbands_in) * nbasis_in);
306+
#endif
307+
}
261308

262309
this->nk = nks_in;
263310
this->nbands = nbands_in;
264311
this->nbasis = nbasis_in;
265312
this->current_nbasis = nbasis_in;
266313
this->psi_current = this->psi;
267-
// GlobalV::ofs_device << "allocated xxx MB memory for psi" << std::endl;
268314
}
269315

270316
template <typename T, typename Device>

source/source_psi/psi.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
namespace psi
1111
{
1212

13+
enum class PsiStorageMode
14+
{
15+
ALL_GPU,
16+
ALL_CPU,
17+
PAGED_GPU
18+
};
19+
1320
// structure for getting range of Psi
1421
// two display method: k index first or bands index first
1522
struct Range
@@ -78,7 +85,7 @@ class Psi
7885
Psi& operator=(const Psi& psi_in);
7986

8087
// allocate psi for three dimensions
81-
void resize(const int nks_in, const int nbands_in, const int nbasis_in);
88+
void resize(const int nks_in, const int nbands_in, const int nbasis_in, const bool skip_psi_cpu_alloc = false);
8289

8390
// get the pointer for the 1st index
8491
T* get_pointer() const;
@@ -139,6 +146,19 @@ class Psi
139146

140147
int get_npol() const;
141148

149+
void set_storage_mode(PsiStorageMode mode);
150+
PsiStorageMode get_storage_mode() const { return storage_mode_; }
151+
152+
void load_k_to_gpu(int ik);
153+
void store_k_from_gpu(int ik);
154+
void ensure_k_on_gpu(int ik);
155+
156+
void set_psi_cpu_external(T* ext_cpu_buf);
157+
158+
int get_current_k_gpu() const { return current_k_gpu_; }
159+
T* get_cpu_pointer(int ik = 0);
160+
const T* get_cpu_pointer(int ik = 0) const;
161+
142162
private:
143163
T* psi = nullptr; // avoid using C++ STL
144164

@@ -164,6 +184,18 @@ class Psi
164184

165185
bool allocate_inside = true; ///< whether allocate psi inside Psi class
166186

187+
PsiStorageMode storage_mode_ = PsiStorageMode::ALL_GPU;
188+
T* psi_cpu_ = nullptr;
189+
bool psi_cpu_owned_ = true;
190+
T* psi_gpu_buffer_ = nullptr;
191+
T* psi_gpu_transfer_buffer_ = nullptr;
192+
int current_k_gpu_ = -1;
193+
194+
#if defined(__CUDA) || defined(__ROCM)
195+
void* compute_stream_ = nullptr;
196+
void* transfer_stream_ = nullptr;
197+
#endif
198+
167199
#ifdef __DSP
168200
using delete_memory_op = base_device::memory::delete_memory_op_mt<T, Device>;
169201
using resize_memory_op = base_device::memory::resize_memory_op_mt<T, Device>;

0 commit comments

Comments
 (0)