Skip to content

Commit b6daba8

Browse files
committed
vulkan: Find optimal memory type but with fallback
Some memory properties are nice to have, but not critical. `eHostCached`, for instance, isn't essential, and yet we fail on devices where this memory property isn't available. ggml_vulkan: No suitable memory type found: ErrorOutOfDeviceMemory This change differentiates between those properties that are critical and those that are just nice-to-have, and will fail only when critical properties aren't available. Fixes #5319.
1 parent 9392ebd commit b6daba8

File tree

1 file changed

+43
-18
lines changed

1 file changed

+43
-18
lines changed

ggml-vulkan.cpp

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -652,9 +652,21 @@ static void ggml_vk_queue_cleanup(vk_queue& q) {
652652
q.cmd_buffer_idx = 0;
653653
}
654654

655-
static vk_buffer ggml_vk_create_buffer(size_t size, vk::MemoryPropertyFlags req_flags) {
655+
static int32_t find_properties(const vk::PhysicalDeviceMemoryProperties* mem_props, vk::MemoryRequirements* mem_req, vk::MemoryPropertyFlags flags) {
656+
for (uint32_t i = 0; i < mem_props->memoryTypeCount; ++i) {
657+
vk::MemoryType memory_type = mem_props->memoryTypes[i];
658+
if ((mem_req->memoryTypeBits & ((uint64_t)1 << i)) &&
659+
(flags & memory_type.propertyFlags) == flags &&
660+
mem_props->memoryHeaps[memory_type.heapIndex].size >= mem_req->size) {
661+
return static_cast<int32_t>(i);
662+
}
663+
}
664+
return -1;
665+
}
666+
667+
static vk_buffer ggml_vk_create_buffer(size_t size, vk::MemoryPropertyFlags req_flags, vk::MemoryPropertyFlags desired_flags = vk::MemoryPropertyFlags(0)) {
656668
#ifdef GGML_VULKAN_DEBUG
657-
std::cerr << "ggml_vk_create_buffer(" << size << ", " << to_string(req_flags) << ")" << std::endl;
669+
std::cerr << "ggml_vk_create_buffer(" << size << ", " << to_string(req_flags) << ", " << to_string(desired_flags) << ")" << std::endl;
658670
#endif
659671
GGML_ASSERT(size > 0);
660672

@@ -676,17 +688,15 @@ static vk_buffer ggml_vk_create_buffer(size_t size, vk::MemoryPropertyFlags req_
676688

677689
vk::PhysicalDeviceMemoryProperties mem_props = vk_device.physical_device.getMemoryProperties();
678690

679-
uint32_t memory_type_index = UINT32_MAX;
680-
681-
for (uint32_t i = 0; i < mem_props.memoryTypeCount; ++i) {
682-
vk::MemoryType memory_type = mem_props.memoryTypes[i];
683-
if ((mem_req.memoryTypeBits & ((uint64_t)1 << i)) && (req_flags & memory_type.propertyFlags) == req_flags && mem_props.memoryHeaps[memory_type.heapIndex].size >= mem_req.size) {
684-
memory_type_index = i;
685-
break;
686-
}
691+
uint32_t memory_type_index = -1;
692+
if (desired_flags) {
693+
memory_type_index = find_properties(&mem_props, &mem_req, req_flags | desired_flags);
694+
}
695+
if (memory_type_index == -1) {
696+
memory_type_index = find_properties(&mem_props, &mem_req, req_flags);
687697
}
688698

689-
if (memory_type_index >= mem_props.memoryTypeCount) {
699+
if (memory_type_index == -1) {
690700
throw vk::OutOfDeviceMemoryError("No suitable memory type found");
691701
}
692702

@@ -712,9 +722,9 @@ static vk_buffer ggml_vk_create_buffer(size_t size, vk::MemoryPropertyFlags req_
712722
return buf;
713723
}
714724

715-
static vk_buffer ggml_vk_create_buffer_check(size_t size, vk::MemoryPropertyFlags req_flags) {
725+
static vk_buffer ggml_vk_create_buffer_check(size_t size, vk::MemoryPropertyFlags req_flags, vk::MemoryPropertyFlags desired_flags = vk::MemoryPropertyFlags(0)) {
716726
try {
717-
return ggml_vk_create_buffer(size, req_flags);
727+
return ggml_vk_create_buffer(size, req_flags, desired_flags);
718728
} catch (const vk::SystemError& e) {
719729
std::cerr << "ggml_vulkan: Memory allocation of size " << size << " failed." << std::endl;
720730
std::cerr << "ggml_vulkan: " << e.what() << std::endl;
@@ -729,7 +739,10 @@ static vk_buffer ggml_vk_create_buffer_device(size_t size) {
729739
} catch (const vk::SystemError& e) {
730740
if (vk_device.uma) {
731741
// Fall back to host memory type
732-
buf = ggml_vk_create_buffer_check(size, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent);
742+
buf = ggml_vk_create_buffer_check(
743+
size,
744+
/* required */ vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
745+
/* optional */ vk::MemoryPropertyFlagBits::eHostCached);
733746
} else {
734747
std::cerr << "ggml_vulkan: Device memory allocation of size " << size << " failed." << std::endl;
735748
std::cerr << "ggml_vulkan: " << e.what() << std::endl;
@@ -1261,7 +1274,10 @@ static void * ggml_vk_host_malloc(size_t size) {
12611274
#ifdef GGML_VULKAN_DEBUG
12621275
std::cerr << "ggml_vk_host_malloc(" << size << ")" << std::endl;
12631276
#endif
1264-
vk_buffer buf = ggml_vk_create_buffer(size, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached);
1277+
vk_buffer buf = ggml_vk_create_buffer(
1278+
size,
1279+
/* required */ vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
1280+
/* optional */ vk::MemoryPropertyFlagBits::eHostCached);
12651281

12661282
if(!(buf.memory_property_flags & vk::MemoryPropertyFlagBits::eHostVisible)) {
12671283
fprintf(stderr, "WARNING: failed to allocate %.2f MB of pinned memory\n",
@@ -1408,7 +1424,10 @@ static void deferred_memcpy(void * dst, const void * src, size_t size, std::vect
14081424
static void ensure_sync_staging_buffer(size_t size) {
14091425
if (vk_sync_staging.size < size) {
14101426
ggml_vk_destroy_buffer(vk_sync_staging);
1411-
vk_sync_staging = ggml_vk_create_buffer_check(size, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached);
1427+
vk_sync_staging = ggml_vk_create_buffer_check(
1428+
size,
1429+
/* required */ vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
1430+
/* optional */ vk::MemoryPropertyFlagBits::eHostCached);
14121431
}
14131432
}
14141433

@@ -3812,7 +3831,10 @@ void ggml_vk_preallocate_buffers() {
38123831
std::cerr << "qx_size: " << vk_prealloc_size_qx << " qy_size: " << vk_prealloc_size_qy << " x_size: " << vk_prealloc_size_x << " y_size: " << vk_prealloc_size_y << " split_k_size: " << vk_prealloc_size_split_k << std::endl;
38133832
#endif
38143833
#if defined(GGML_VULKAN_RUN_TESTS)
3815-
vk_staging = ggml_vk_create_buffer_check(100ul * 1024ul * 1024ul, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached);
3834+
vk_staging = ggml_vk_create_buffer_check(
3835+
100ul * 1024ul * 1024ul,
3836+
/* required */ vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
3837+
/* optional */ vk::MemoryPropertyFlagBits::eHostCached);
38163838
ggml_vk_test_transfer(8192 * 1000, false);
38173839
ggml_vk_test_transfer(8192 * 1000, true);
38183840

@@ -3904,7 +3926,10 @@ void ggml_vk_preallocate_buffers() {
39043926
if (vk_staging.size > 0) {
39053927
ggml_vk_destroy_buffer(vk_staging);
39063928
}
3907-
vk_staging = ggml_vk_create_buffer_check(vk_staging_size, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent | vk::MemoryPropertyFlagBits::eHostCached);
3929+
vk_staging = ggml_vk_create_buffer_check(
3930+
vk_staging_size,
3931+
/* required */ vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent,
3932+
/* optional */ vk::MemoryPropertyFlagBits::eHostCached);
39083933
}
39093934
}
39103935

0 commit comments

Comments
 (0)