Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 25 additions & 16 deletions ggml/src/ggml-alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1124,6 +1124,20 @@ static void free_buffers(ggml_backend_buffer_t ** buffers, const size_t * n_buff
free(*buffers);
}

static bool alloc_ctx_tensors_finalize_views(struct ggml_context * ctx) {
for (struct ggml_tensor * t = ggml_get_first_tensor(ctx); t != NULL; t = ggml_get_next_tensor(ctx, t)) {
if (t->view_src != NULL && t->buffer == NULL) {
enum ggml_status status = ggml_backend_view_init(t);
if (status != GGML_STATUS_SUCCESS) {
GGML_LOG_ERROR("%s: failed to initialize view tensor %s\n", __func__, t->name);
return false;
}
}
}

return true;
}

static bool alloc_tensor_range(struct ggml_context * ctx,
struct ggml_tensor * first, struct ggml_tensor * last,
ggml_backend_buffer_type_t buft, size_t size,
Expand All @@ -1142,24 +1156,14 @@ static bool alloc_tensor_range(struct ggml_context * ctx,
struct ggml_tallocr tallocr = ggml_tallocr_new(buffer);

for (struct ggml_tensor * t = first; t != last; t = ggml_get_next_tensor(ctx, t)) {
enum ggml_status status = GGML_STATUS_SUCCESS;
if (t->data == NULL) {
if (t->view_src == NULL) {
status = ggml_tallocr_alloc(&tallocr, t);
} else if (t->buffer == NULL) {
status = ggml_backend_view_init(t);
}
} else {
if (t->view_src != NULL && t->buffer == NULL) {
// view of a pre-allocated tensor
status = ggml_backend_view_init(t);
if (t->view_src == NULL && t->data == NULL) {
enum ggml_status status = ggml_tallocr_alloc(&tallocr, t);
if (status != GGML_STATUS_SUCCESS) {
GGML_LOG_ERROR("%s: failed to allocate tensor %s\n", __func__, t->name);
free_buffers(buffers, n_buffers);
return false;
}
}
if (status != GGML_STATUS_SUCCESS) {
GGML_LOG_ERROR("%s: failed to initialize tensor %s\n", __func__, t->name);
free_buffers(buffers, n_buffers);
return false;
}
}

return true;
Expand Down Expand Up @@ -1217,6 +1221,11 @@ static ggml_backend_buffer_t ggml_backend_alloc_ctx_tensors_from_buft_impl(
return NULL;
}

if (!alloc_ctx_tensors_finalize_views(ctx)) {
free_buffers(&buffers, &n_buffers);
return NULL;
}

ggml_backend_buffer_t buffer;
if (n_buffers == 1) {
buffer = buffers[0];
Expand Down
26 changes: 26 additions & 0 deletions tests/test-alloc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,31 @@ static void test_reallocation() {
}
}

// Parent nbytes > max_size leaves cur_buf_size > max_size. A following view
// then triggers a split with this_size == 0, so the view-only residual range
// skips alloc_tensor_range unless views are finalized after all splits.
static void test_view_init_after_max_size_split() {
const size_t max_size = 16;
dummy_backend backend = dummy_backend_init(max_size);
auto [ctx, graph, ctx_ptr] = make_context();
(void) graph;

ggml_tensor * parent = make_input_with_size(ctx, 24); // 6 x f32, > max_size
ggml_tensor * view0 = ggml_view_1d(ctx, parent, 2, 0);
ggml_tensor * view1 = ggml_view_1d(ctx, parent, 2, 2 * sizeof(float));
assign_names(ctx);

ggml_backend_buffer_ptr buf(ggml_backend_alloc_ctx_tensors_from_buft(ctx, &backend.buffer_type));
GGML_ASSERT(buf);

for (ggml_tensor * t = ggml_get_first_tensor(ctx); t; t = ggml_get_next_tensor(ctx, t)) {
GGML_ASSERT(t->buffer != nullptr);
GGML_ASSERT(t->data != nullptr);
}
GGML_ASSERT(view0->view_src == parent);
GGML_ASSERT(view1->view_src == parent);
}

static void run(const char * name, void (*f)()) {
printf("%s ", name);
fflush(stdout);
Expand All @@ -604,5 +629,6 @@ int main() {
run("test_multiple_buffer_types", test_multiple_buffer_types);
run("test_buffer_size_zero", test_buffer_size_zero);
run("test_reallocation", test_reallocation);
run("test_view_init_after_max_size_split", test_view_init_after_max_size_split);
return 0;
}