| 80 | } |
| 81 | |
| 82 | void ggml_tallocr_alloc(ggml_tallocr_t alloc, struct ggml_tensor * tensor) { |
| 83 | GGML_ASSERT(!ggml_is_view(tensor)); // views generally get data pointer from one of their sources |
| 84 | GGML_ASSERT(tensor->data == NULL); // avoid allocating tensor which already has memory allocated |
| 85 | |
| 86 | size_t size = ggml_backend_buffer_get_alloc_size(alloc->buffer, tensor); |
| 87 | size = aligned_offset(NULL, size, alloc->alignment); |
| 88 | |
| 89 | AT_PRINTF("%s: allocating %s (%zu bytes) - ", __func__, tensor->name, size); |
| 90 | |
| 91 | size_t max_avail = 0; |
| 92 | |
| 93 | // find the best fitting free block besides the last block |
| 94 | int best_fit_block = -1; |
| 95 | size_t best_fit_size = SIZE_MAX; |
| 96 | for (int i = 0; i < alloc->n_free_blocks - 1; i++) { |
| 97 | struct free_block * block = &alloc->free_blocks[i]; |
| 98 | max_avail = MAX(max_avail, block->size); |
| 99 | if (block->size >= size && block->size <= best_fit_size) { |
| 100 | best_fit_block = i; |
| 101 | best_fit_size = block->size; |
| 102 | } |
| 103 | } |
| 104 | |
| 105 | AT_PRINTF("block %d\n", best_fit_block); |
| 106 | |
| 107 | if (best_fit_block == -1) { |
| 108 | // the last block is our last resort |
| 109 | struct free_block * block = &alloc->free_blocks[alloc->n_free_blocks - 1]; |
| 110 | max_avail = MAX(max_avail, block->size); |
| 111 | if (block->size >= size) { |
| 112 | best_fit_block = alloc->n_free_blocks - 1; |
| 113 | } else { |
| 114 | fprintf(stderr, "%s: not enough space in the buffer (needed %zu, largest block available %zu)\n", |
| 115 | __func__, size, max_avail); |
| 116 | GGML_ASSERT(!"not enough space in the buffer"); |
| 117 | return; |
| 118 | } |
| 119 | } |
| 120 | struct free_block * block = &alloc->free_blocks[best_fit_block]; |
| 121 | void * addr = block->addr; |
| 122 | block->addr = (char*)block->addr + size; |
| 123 | block->size -= size; |
| 124 | if (block->size == 0) { |
| 125 | // remove block if empty |
| 126 | alloc->n_free_blocks--; |
| 127 | for (int j = best_fit_block; j < alloc->n_free_blocks; j++) { |
| 128 | alloc->free_blocks[j] = alloc->free_blocks[j+1]; |
| 129 | } |
| 130 | } |
| 131 | |
| 132 | tensor->data = addr; |
| 133 | tensor->buffer = alloc->buffer; |
| 134 | if (!alloc->measure) { |
| 135 | ggml_backend_buffer_init_tensor(alloc->buffer, tensor); |
| 136 | } |
| 137 | |
| 138 | #ifdef GGML_ALLOCATOR_DEBUG |
| 139 | add_allocated_tensor(alloc, tensor); |
no test coverage detected