Skip to content

Commit 138a502

Browse files
committed
[DRAFT: DONT COMMIT] Enable zero-copy subbuffers across all alloc types for iGPUs
#### Details: Description of the issue (symptom, root-cause, how it was resolved) - Eliminates redundant weight copies during model loading for integrated GPUs by binding mmap'd cache file memory directly to GPU without intermediate usm_device allocation - Reduces memory footprint during inference by reusing host memory as GPU-accessible buffers - Zero-copy enabled when: iGPU, XE2+ architecture, USM host support available - Falls back gracefully to copy-based path when zero-copy requirements not met Implementation changes: - Add ocl_engine::supports_hostbuffer() to validate zero-copy capability (checks for integrated GPU, XE2+ arch, USM host allocation support) - Add ocl_engine::create_hostbuffer_impl() to bind host memory with CL_MEM_USE_HOST_PTR - Simplify zero-copy detection in data.hpp load path (remove redundant capability checks) - Use ib.seek_current_ptr() instead of dummy reads for padding alignment - Remove is_mmap_tensor_4K_aligned() helpers Changed files: src/plugins/intel_gpu/include/intel_gpu/graph/serialization/binary_buffer.hpp src/plugins/intel_gpu/include/intel_gpu/primitives/data.hpp src/plugins/intel_gpu/include/intel_gpu/runtime/device_info.hpp src/plugins/intel_gpu/src/graph/program.cpp src/plugins/intel_gpu/src/runtime/ocl/ocl_device.cpp src/plugins/intel_gpu/src/runtime/ocl/ocl_engine.cpp src/plugins/intel_gpu/tests/unit/test_cases/cache_serialization_test.cpp Reproduction step and snapshot (if applicable. Do not attach for customer model) NA Problematic graph NA #### Checklist - [x] Is it a proper fix? Yes (memory optimization, not a workaround) - [x] Did you include test case for this fix, if necessary? NA - [x] Did you review existing test that can be extended to cover this scenario? NA #### Tickets: - CVS-176160 #### AI Assistance: - AI assistance used: yes - AI was used for code implementation, naming suggestions, and comment refinement.
1 parent bbb6398 commit 138a502

6 files changed

Lines changed: 22 additions & 36 deletions

File tree

src/plugins/intel_gpu/include/intel_gpu/graph/serialization/binary_buffer.hpp

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,12 @@ class BinaryOutputBuffer : public OutputBuffer<BinaryOutputBuffer> {
6161
size_t get_offset() const {
6262
return _offset;
6363
}
64-
bool is_offset_page_aligned() const {
65-
return (get_offset() % CACHE_PAGE_SIZE == 0);
64+
bool is_offset_aligned(const size_t alignment) const {
65+
return (get_offset() % alignment == 0);
6666
}
6767

68-
size_t get_bytes_to_page_boundary() const {
69-
return CACHE_PAGE_SIZE - (get_offset() % CACHE_PAGE_SIZE);
70-
}
71-
72-
bool is_offset_sub_buffer_aligned() const {
73-
return (get_offset() % CACHE_SUB_BUFFER_ALIGNMENT == 0);
74-
}
75-
76-
size_t get_bytes_to_sub_buffer_boundary() const {
77-
return CACHE_SUB_BUFFER_ALIGNMENT - (get_offset() % CACHE_SUB_BUFFER_ALIGNMENT);
68+
size_t get_bytes_to_aligned_boundary(const size_t alignment) const {
69+
return alignment - (get_offset() % alignment);
7870
}
7971

8072
private:
@@ -150,20 +142,11 @@ class BinaryInputBuffer : public InputBuffer<BinaryInputBuffer> {
150142
_stream.seekg(current_pos + static_cast<std::streampos>(size));
151143
_offset += size;
152144
}
153-
bool is_offset_page_aligned() const {
154-
return (get_offset() % CACHE_PAGE_SIZE == 0);
145+
bool is_offset_aligned(const size_t alignment) const {
146+
return (get_offset() % alignment == 0);
155147
}
156-
157-
size_t get_bytes_to_page_boundary() const {
158-
return CACHE_PAGE_SIZE - (get_offset() % CACHE_PAGE_SIZE);
159-
}
160-
161-
bool is_offset_sub_buffer_aligned() const {
162-
return (get_offset() % CACHE_SUB_BUFFER_ALIGNMENT == 0);
163-
}
164-
165-
size_t get_bytes_to_sub_buffer_boundary() const {
166-
return CACHE_SUB_BUFFER_ALIGNMENT - (get_offset() % CACHE_SUB_BUFFER_ALIGNMENT);
148+
size_t get_bytes_to_aligned_boundary(const size_t alignment) const {
149+
return alignment - (get_offset() % alignment);
167150
}
168151
void setKernelImplParams(void* impl_params) {
169152
_impl_params = impl_params;

src/plugins/intel_gpu/include/intel_gpu/primitives/data.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,8 +395,8 @@ struct data : public primitive_base<data> {
395395
bool do_weightless_caching = cache_info->save(ob, data_size);
396396
if (!do_weightless_caching) {
397397
if (is_alloc_host_accessible(_allocation_type)) {
398-
if (!ob.is_encrypted() && !ob.is_offset_sub_buffer_aligned()) {
399-
std::vector<uint8_t> pad(ob.get_bytes_to_sub_buffer_boundary(), 0);
398+
if (!ob.is_encrypted() && !ob.is_offset_aligned(mem->get_engine()->get_device_info().cacheline_size)) {
399+
std::vector<uint8_t> pad(ob.get_bytes_to_aligned_boundary(mem->get_engine()->get_device_info().cacheline_size), 0);
400400
ob << make_data(pad.data(), pad.size());
401401
}
402402
ob << make_data(mem->buffer_ptr(), data_size);
@@ -443,8 +443,8 @@ struct data : public primitive_base<data> {
443443

444444
if (!is_weightless_caching) {
445445
if (is_alloc_host_accessible(_allocation_type)) {
446-
if (!ib.is_encrypted() && !ib.is_offset_sub_buffer_aligned()) {
447-
std::vector<uint8_t> pad(ib.get_bytes_to_sub_buffer_boundary(), 0);
446+
if (!ib.is_encrypted() && !ib.is_offset_aligned(ib.get_engine().get_device_info().cacheline_size)) {
447+
std::vector<uint8_t> pad(ib.get_bytes_to_aligned_boundary(ib.get_engine().get_device_info().cacheline_size), 0);
448448
ib >> make_data(pad.data(), pad.size());
449449
}
450450
if (enable_zero_copy_mode) {

src/plugins/intel_gpu/include/intel_gpu/runtime/device_info.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ struct device_info {
145145
uint32_t num_ccs; ///< Number of compute command streamers
146146
uint32_t sub_device_idx; ///< Index of sub-device
147147
int32_t cacheline_size;
148+
uint32_t sub_buffer_base_alignment;
148149

149150
pci_bus_info pci_info; ///< PCI bus information for the device
150151

src/plugins/intel_gpu/src/graph/program.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1985,9 +1985,8 @@ void program::save(cldnn::BinaryOutputBuffer& ob) const {
19851985
ob << state_initializer.first;
19861986
ob << state_initializer.second;
19871987
}
1988-
1989-
if (!ob.is_encrypted() && !ob.is_offset_page_aligned()) {
1990-
std::vector<uint8_t> pad(ob.get_bytes_to_page_boundary(), 0);
1988+
if (!ob.is_encrypted() && !ob.is_offset_aligned(get_engine().get_device_info().cacheline_size)) {
1989+
std::vector<uint8_t> pad(ob.get_bytes_to_aligned_boundary(get_engine().get_device_info().cacheline_size), 0);
19911990
ob << make_data(pad.data(), pad.size());
19921991
}
19931992
}
@@ -2215,8 +2214,8 @@ void program::load(cldnn::BinaryInputBuffer& ib,
22152214
}
22162215

22172216
// At the end of load
2218-
if (!ib.is_encrypted() && !ib.is_offset_page_aligned()) {
2219-
std::vector<uint8_t> pad(ib.get_bytes_to_page_boundary(), 0);
2217+
if (!ib.is_encrypted() && !ib.is_offset_aligned(get_engine().get_device_info().cacheline_size)) {
2218+
std::vector<uint8_t> pad(ib.get_bytes_to_aligned_boundary(get_engine().get_device_info().cacheline_size), 0);
22202219
ib >> make_data(pad.data(), pad.size());
22212220
}
22222221
}

src/plugins/intel_gpu/src/runtime/ocl/ocl_device.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,9 @@ device_info init_device_info(const cl::Device& device, const cl::Context& contex
209209
info.sub_device_idx = std::numeric_limits<uint32_t>::max();
210210

211211
info.cacheline_size = device.getInfo<CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE>();
212+
// Alignment requirement (in bits) for sub-buffer offsets, converting to bytes and ensuring at least 1 byte alignment.
213+
auto bits = device.getInfo<CL_DEVICE_MEM_BASE_ADDR_ALIGN>();
214+
info.sub_buffer_base_alignment = std::max<uint32_t>(1, bits / 8);
212215
info.execution_units_count = device.getInfo<CL_DEVICE_MAX_COMPUTE_UNITS>();
213216

214217
info.gpu_frequency = static_cast<uint32_t>(device.getInfo<CL_DEVICE_MAX_CLOCK_FREQUENCY>());

src/plugins/intel_gpu/tests/unit/test_cases/cache_serialization_test.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -330,8 +330,8 @@ membuf make_oversized_data_blob(const layout& output_layout, size_t malicious_da
330330
ob << weightless_caching;
331331

332332
// Mirror the reader's alignment padding so stream offsets stay in sync.
333-
if (!ob.is_encrypted() && !ob.is_offset_sub_buffer_aligned()) {
334-
std::vector<uint8_t> pad(ob.get_bytes_to_sub_buffer_boundary(), 0);
333+
if (!ob.is_encrypted() && !ob.is_offset_aligned(128)) {
334+
std::vector<uint8_t> pad(ob.get_bytes_to_aligned_boundary(128), 0);
335335
ob << make_data(pad.data(), pad.size());
336336
}
337337

0 commit comments

Comments
 (0)