Skip to content

Commit 051fcac

Browse files
committed
Fix: AMD ROCm/HIP tiered cache improvements
- Fix Issue 1: Replace CUDA API calls with HIP API in ggml-cuda.cu - cudaMemcpyPeerAsync → hipMemcpyPeerAsync - cudaError_t → hipError_t - cudaSuccess → hipSuccess - Fix Issue 2: Fix typo std.max → std::max in llama-eviction-policy.h - Fix Issue 3: Implement migrate_tokens and batch_migrate_tokens with HIP-aware memory copies - Fix Issue 4: Implement save_to_ssd and load_from_ssd using llama_ssd_storage_format - Fix Issue 5: Add ggml tensor handles (ggml_tensor*) for K and V data to tier class - Fix Issue 6: Add device-to-host copy for hot→warm path before serialization - Added is_device_data parameter to save_to_ssd() - Added to_device parameter to load_from_ssd() - Uses hipMemcpy with hipMemcpyDeviceToHost/hipMemcpyHostToDevice as needed
1 parent 1f0fb2e commit 051fcac

12 files changed

Lines changed: 1954 additions & 0 deletions

.gitignore

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,3 +148,28 @@ a.out.*
148148
.gitnexus
149149
.claude/
150150
.agent.md
151+
152+
# cmake root-level build artifacts
153+
/CMakeFiles/
154+
/CMakeCache.txt
155+
/CTestTestfile.cmake
156+
/DartConfiguration.tcl
157+
/cmake_install.cmake
158+
/bin/
159+
/CPackConfig.cmake
160+
/CPackSourceConfig.cmake
161+
*.so
162+
*.so.*
163+
164+
# nested cmake build artifacts
165+
**/CMakeFiles/
166+
**/cmake_install.cmake
167+
**/CTestTestfile.cmake
168+
**/Makefile
169+
compile_commands.json
170+
error.txt
171+
license.cpp
172+
llama.pc
173+
ggml/ggml-config.cmake
174+
ggml/ggml-version.cmake
175+
tests/libgguf-model-data.a

common/arg.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <list>
3232
#include <regex>
3333
#include <set>
34+
#include <sstream>
3435
#include <string>
3536
#include <thread> // for hardware_concurrency
3637
#include <vector>
@@ -1310,6 +1311,53 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
13101311
params.cache_ram_mib = value;
13111312
}
13121313
).set_env("LLAMA_ARG_CACHE_RAM").set_examples({LLAMA_EXAMPLE_SERVER, LLAMA_EXAMPLE_CLI}));
1314+
add_opt(common_arg(
1315+
{"--kv-tiered"}, "VRAM%,RAM%,SSD%",
1316+
"enable tiered KV cache with percentages for VRAM, RAM, SSD (e.g., 25,25,50 for 25% VRAM, 25% RAM, 50% SSD)",
1317+
[](common_params & params, const std::string & value) {
1318+
params.kv_tiered_enabled = true;
1319+
// Parse the percentage string
1320+
std::vector<std::string> parts;
1321+
std::stringstream ss(value);
1322+
std::string part;
1323+
while (std::getline(ss, part, ',')) {
1324+
parts.push_back(part);
1325+
}
1326+
if (parts.size() == 3) {
1327+
params.kv_tier_hot_pct = std::stof(parts[0]);
1328+
params.kv_tier_warm_pct = std::stof(parts[1]);
1329+
params.kv_tier_cold_pct = std::stof(parts[2]);
1330+
}
1331+
}
1332+
).set_env("LLAMA_ARG_KT_TIERED").set_examples({LLAMA_EXAMPLE_SERVER}));
1333+
add_opt(common_arg(
1334+
{"--tier-ssd-path"}, "PATH",
1335+
"directory for cold tier (SSD) storage",
1336+
[](common_params & params, const std::string & value) {
1337+
params.kv_tier_ssd_path = value;
1338+
}
1339+
).set_env("LLAMA_ARG_TIER_SSD_PATH").set_examples({LLAMA_EXAMPLE_SERVER}));
1340+
add_opt(common_arg(
1341+
{"--tier-eviction-policy"}, "POLICY",
1342+
"eviction policy: 0=LRU, 1=LFU, 2=attention, 3=hybrid (default)",
1343+
[](common_params & params, int value) {
1344+
params.kv_tier_eviction_policy = value;
1345+
}
1346+
).set_env("LLAMA_ARG_TIER_EVICTION_POLICY").set_examples({LLAMA_EXAMPLE_SERVER}));
1347+
add_opt(common_arg(
1348+
{"--tier-compression"}, "TYPE",
1349+
"compression type: 0=none, 1=int4, 2=int8, 3=lz4, 4=quantized",
1350+
[](common_params & params, int value) {
1351+
params.kv_tier_compression = value;
1352+
}
1353+
).set_env("LLAMA_ARG_TIER_COMPRESSION").set_examples({LLAMA_EXAMPLE_SERVER}));
1354+
add_opt(common_arg(
1355+
{"--tier-attention-threshold"}, "THRESH",
1356+
"attention threshold for eviction (0.0-1.0, default: 0.1)",
1357+
[](common_params & params, int value) {
1358+
params.kv_tier_attention_threshold = float(value) / 100.0f;
1359+
}
1360+
).set_env("LLAMA_ARG_TIER_ATTENTION_THRESHOLD").set_examples({LLAMA_EXAMPLE_SERVER}));
13131361
add_opt(common_arg(
13141362
{"-kvu", "--kv-unified"},
13151363
{"-no-kvu", "--no-kv-unified"},

common/common.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,16 @@ struct common_params {
573573
int32_t checkpoint_every_nt = 8192; // make a checkpoint every n tokens during prefill
574574
int32_t cache_ram_mib = 8192; // -1 = no limit, 0 - disable, 1 = 1 MiB, etc.
575575

576+
// tiered KV cache parameters
577+
bool kv_tiered_enabled = false; // enable tiered KV cache
578+
float kv_tier_hot_pct = 25.0f; // hot tier percentage (VRAM)
579+
float kv_tier_warm_pct = 25.0f; // warm tier percentage (RAM)
580+
float kv_tier_cold_pct = 50.0f; // cold tier percentage (SSD)
581+
std::string kv_tier_ssd_path = ""; // SSD path for cold tier storage
582+
int kv_tier_eviction_policy = 3; // 0=LRU, 1=LFU, 2=attention, 3=hybrid (default)
583+
int kv_tier_compression = 1; // 0=none, 1=int4, 2=int8, 3=lz4, 4=quantized
584+
float kv_tier_attention_threshold = 0.1f; // attention threshold for eviction
585+
576586
std::string hostname = "127.0.0.1";
577587
std::string public_path = ""; // NOLINT
578588
std::string api_prefix = ""; // NOLINT

ggml/src/ggml-cuda/ggml-cuda.cu

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1426,6 +1426,54 @@ static cudaError_t ggml_cuda_cpy_tensor_2d(
14261426
const int64_t i1_diff = i1_high - i1_low;
14271427

14281428
const char * x = src_ptr + i1_low*nb1 + i2*nb2 + i3*nb3;
1429+
1430+
#if defined(GGML_USE_HIP)
1431+
// hipMemcpy2DAsync with hipMemcpyDeviceToDevice requires P2P access between devices.
1432+
// For mixed-architecture multi-GPU setups (e.g. gfx1201 + gfx1030) without P2P,
1433+
// it fails asynchronously with hipErrorNoBinaryForGpu when the internal copy kernel
1434+
// isn't compiled for the destination device. Detect cross-device copies via pointer
1435+
// attributes and fall back to row-wise hipMemcpyPeerAsync, which stages through the
1436+
// host when P2P is unavailable. Mirrors the fix in ggml_cuda_Memcpy2DPeerAsync.
1437+
hipPointerAttribute_t src_attr = {};
1438+
hipPointerAttribute_t dst_attr = {};
1439+
const bool src_ok = hipPointerGetAttributes(&src_attr, x) == hipSuccess;
1440+
const bool dst_ok = hipPointerGetAttributes(&dst_attr, dst_ptr) == hipSuccess;
1441+
if (src_ok && dst_ok && src_attr.device != dst_attr.device) {
1442+
const int src_dev = src_attr.device;
1443+
const int dst_dev = dst_attr.device;
1444+
if (nb0 == ts && nb1 == ts*ne0/bs) {
1445+
return hipMemcpyPeerAsync(dst_ptr, dst_dev, x, src_dev, i1_diff*nb1, stream);
1446+
} else if (nb0 == ts) {
1447+
const size_t row_bytes = ts*ne0/bs;
1448+
for (int64_t i1 = 0; i1 < i1_diff; i1++) {
1449+
hipError_t err = hipMemcpyPeerAsync(
1450+
dst_ptr + i1*row_bytes, dst_dev,
1451+
x + i1*nb1, src_dev,
1452+
row_bytes, stream);
1453+
if (err != hipSuccess) {
1454+
return err;
1455+
}
1456+
}
1457+
return hipSuccess;
1458+
} else {
1459+
for (int64_t i1 = 0; i1 < i1_diff; i1++) {
1460+
const char * rx = x + i1*nb1;
1461+
char * rd = dst_ptr + i1*ts*ne0/bs;
1462+
for (int64_t e = 0; e < ne0; e++) {
1463+
hipError_t err = hipMemcpyPeerAsync(
1464+
rd + e*(ts/bs), dst_dev,
1465+
rx + e*nb0, src_dev,
1466+
ts/bs, stream);
1467+
if (err != hipSuccess) {
1468+
return err;
1469+
}
1470+
}
1471+
}
1472+
return hipSuccess;
1473+
}
1474+
}
1475+
#endif
1476+
14291477
if (nb0 == ts && nb1 == ts*ne0/bs) {
14301478
return cudaMemcpyAsync(dst_ptr, x, i1_diff*nb1, cudaMemcpyDeviceToDevice, stream);
14311479
} else if (nb0 == ts) {

0 commit comments

Comments
 (0)