| 1 | #ifndef VLLM_NUMA_DISABLED |
| 2 | #include <numa.h> |
| 3 | #include <unistd.h> |
| 4 | #include <string> |
| 5 | #include <sched.h> |
| 6 | #endif |
| 7 | #if __GLIBC__ == 2 && __GLIBC_MINOR__ < 30 |
| 8 | #include <unistd.h> |
| 9 | #include <sys/syscall.h> |
| 10 | #define gettid() syscall(SYS_gettid) |
| 11 | #endif |
| 12 | |
| 13 | #include "cpu/utils.hpp" |
| 14 | |
| 15 | #ifdef VLLM_NUMA_DISABLED |
| 16 | void init_cpu_memory_env(std::vector<int64_t> node_ids) {} |
| 17 | #else |
| 18 | void init_cpu_memory_env(std::vector<int64_t> node_ids) { |
| 19 | // Memory node binding |
| 20 | if (numa_available() != -1) { |
| 21 | // Concatenate all node_ids into a single comma-separated string |
| 22 | if (!node_ids.empty()) { |
| 23 | std::string node_ids_str; |
| 24 | for (const int node_id : node_ids) { |
| 25 | if (!node_ids_str.empty()) { |
| 26 | node_ids_str += ","; |
| 27 | } |
| 28 | node_ids_str += std::to_string(node_id); |
| 29 | } |
| 30 | |
| 31 | bitmask* mask = numa_parse_nodestring(node_ids_str.c_str()); |
| 32 | bitmask* src_mask = numa_get_mems_allowed(); |
| 33 | |
| 34 | int pid = getpid(); |
| 35 | |
| 36 | if (mask && src_mask) { |
| 37 | // move all existing pages to the specified numa node. |
| 38 | *(src_mask->maskp) = *(src_mask->maskp) ^ *(mask->maskp); |
| 39 | int page_num = numa_migrate_pages(pid, src_mask, mask); |
| 40 | if (page_num == -1) { |
| 41 | TORCH_WARN("numa_migrate_pages failed. errno: " + |
| 42 | std::to_string(errno)); |
| 43 | } |
| 44 | |
| 45 | // Restrict memory allocation to the selected NUMA node(s). |
| 46 | // Enhances memory locality for the threads bound to those NUMA CPUs. |
| 47 | if (node_ids.size() > 1) { |
| 48 | errno = 0; |
| 49 | numa_set_interleave_mask(mask); |
| 50 | if (errno != 0) { |
| 51 | TORCH_WARN("numa_set_interleave_mask failed. errno: " + |
| 52 | std::to_string(errno)); |
| 53 | } else { |
| 54 | TORCH_WARN( |
| 55 | "NUMA binding: Using INTERLEAVE policy for memory " |
| 56 | "allocation across multiple NUMA nodes (nodes: " + |
| 57 | node_ids_str + |
| 58 | "). Memory allocations will be " |
| 59 | "interleaved across the specified NUMA nodes."); |
| 60 | } |
| 61 | } else { |
| 62 | errno = 0; |
| 63 | numa_set_membind(mask); |
| 64 | if (errno != 0) { |
| 65 | TORCH_WARN("numa_set_membind failed. errno: " + |
| 66 | std::to_string(errno)); |
| 67 | } else { |
| 68 | TORCH_WARN( |
| 69 | "NUMA binding: Using MEMBIND policy for memory " |
| 70 | "allocation on the NUMA nodes (" + |
| 71 | node_ids_str + |
| 72 | "). Memory allocations will be " |
| 73 | "strictly bound to these NUMA nodes."); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | numa_set_strict(1); |
| 78 | |
| 79 | numa_free_nodemask(mask); |
| 80 | numa_free_nodemask(src_mask); |
| 81 | } else { |
| 82 | TORCH_WARN( |
| 83 | "numa_parse_nodestring or numa_get_run_node_mask failed. errno: " + |
| 84 | std::to_string(errno)); |
| 85 | } |
| 86 | } |
| 87 | } |
| 88 | } |
| 89 | #endif // VLLM_NUMA_DISABLED |
| 90 | |
| 91 | namespace cpu_utils { |
| 92 | ScratchPadManager::ScratchPadManager() : size_(0), ptr_(nullptr) { |
| 93 | this->realloc(allocation_unit * 128); |
| 94 | } |
| 95 | |
| 96 | void ScratchPadManager::realloc(size_t new_size) { |
| 97 | new_size = round(new_size); |
| 98 | if (new_size > size_) { |
| 99 | void* new_ptr = std::aligned_alloc(64, new_size); |
| 100 | TORCH_CHECK(new_ptr != nullptr, |
| 101 | "ScratchPadManager: aligned_alloc failed for size ", new_size); |
| 102 | if (ptr_ != nullptr) { |
| 103 | std::free(ptr_); |
| 104 | } |
| 105 | ptr_ = new_ptr; |
| 106 | size_ = new_size; |
| 107 | } |
| 108 | } |
| 109 | |
| 110 | ScratchPadManager* ScratchPadManager::get_scratchpad_manager() { |
| 111 | static ScratchPadManager manager; |
| 112 | return &manager; |
| 113 | } |
| 114 | } // namespace cpu_utils |
| 115 | |
| 116 | void compute_slot_mapping_kernel_impl(const torch::Tensor query_start_loc, |
| 117 | const torch::Tensor positions, |
| 118 | const torch::Tensor block_table, |
| 119 | torch::Tensor slot_mapping, |
| 120 | const int64_t block_size) { |
| 121 | const int32_t req_num = query_start_loc.size(0) - 1; |
| 122 | const int64_t block_table_stride = block_table.stride(0); |
| 123 | |
| 124 | const int32_t* __restrict__ query_start_loc_ptr = |
| 125 | query_start_loc.data_ptr<int32_t>(); |
| 126 | const int64_t* __restrict__ positions_ptr = positions.data_ptr<int64_t>(); |
| 127 | const int32_t* __restrict__ blocktable_ptr = block_table.data_ptr<int32_t>(); |
| 128 | int64_t* __restrict__ slot_mapping_ptr = slot_mapping.data_ptr<int64_t>(); |
| 129 | |
| 130 | #pragma omp parallel for |
| 131 | for (int32_t req_idx = 0; req_idx < req_num; ++req_idx) { |
| 132 | int32_t token_start_idx = query_start_loc_ptr[req_idx]; |
| 133 | int32_t token_end_idx = query_start_loc_ptr[req_idx + 1]; |
| 134 | int32_t token_num = token_end_idx - token_start_idx; |
| 135 | const int64_t* __restrict__ curr_position_ptr = |
| 136 | positions_ptr + token_start_idx; |
| 137 | int64_t* __restrict__ curr_slot_mapping_ptr = |
| 138 | slot_mapping_ptr + token_start_idx; |
| 139 | const int32_t* __restrict__ curr_block_table_ptr = |
| 140 | blocktable_ptr + req_idx * block_table_stride; |
| 141 | |
| 142 | for (int32_t token_idx = 0; token_idx < token_num; ++token_idx) { |
| 143 | int64_t token_position = curr_position_ptr[token_idx]; |
| 144 | int64_t block_id = curr_block_table_ptr[token_position / block_size]; |
| 145 | curr_slot_mapping_ptr[token_idx] = |
| 146 | block_id * block_size + token_position % block_size; |
| 147 | } |
| 148 | } |
| 149 | } |