char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
21f6b0d22
char/aliceai-t5-moe
1// 2// MIT license 3// Copyright (C) 2024 Intel Corporation 4// SPDX-License-Identifier: MIT 5// 6 7// 8// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 9// See https://llvm.org/LICENSE.txt for license information. 10// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 11// 12 13#include <algorithm> 14#include <array> 15#include <assert.h> 16#include <atomic> 17#include <cinttypes> 18#include <cstddef> 19#include <cstdint> 20#include <cstdlib> 21#include <float.h> 22#include <limits> 23#include <optional> 24#include <stdint.h> 25#include <stdio.h> 26#include <vector> 27#include <cmath> 28#include <iostream> 29#include <fstream> 30#include <stdio.h> 31#include <stdlib.h> 32#include <regex> 33 34#include <sycl/sycl.hpp> 35#include <sycl/backend.hpp> 36#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 37#include <level_zero/ze_api.h> 38#include <level_zero/zes_api.h> 39#endif 40#if defined(GGML_SYCL_GRAPH )&& SYCL_EXT_ONEAPI_ASYNC_MEMORY_ALLOC 41# include <sycl/ext/oneapi/experimental/async_alloc/async_alloc.hpp> 42#endif 43#if SYCL_EXT_ONEAPI_VIRTUAL_MEM 44# include <sycl/ext/oneapi/virtual_mem/physical_mem.hpp> 45# include <sycl/ext/oneapi/virtual_mem/virtual_mem.hpp> 46# define GGML_SYCL_SUPPORT_VMM 47#endif 48#if defined(__INTEL_LLVM_COMPILER ) 49#define GGML_SYCL_DMMV_HAS_ESIMD 50#endif 51#include <sycl/half_type.hpp> 52 53#include "ggml.h" 54#include "ggml-sycl.h" 55#include "ggml-impl.h" 56#include "ggml-backend-impl.h" 57 58#include "ggml-sycl/add-id.hpp" 59#include "ggml-sycl/backend.hpp" 60#include "ggml-sycl/common.hpp" 61#include "ggml-sycl/element_wise.hpp" 62#include "ggml-sycl/fwht.hpp" 63#include "ggml-sycl/gemm.hpp" 64#include "ggml-sycl/getrows.hpp" 65#include "ggml-sycl/mem.hpp" 66#include "ggml-sycl/norm.hpp" 67#include "ggml-sycl/presets.hpp" 68#include "ggml-sycl/quantize.hpp" 69#include "ggml-sycl/repeat_back.hpp" 70#include "ggml-sycl/set_rows.hpp" 71#include "ggml-sycl/set.hpp" 72#include "ggml-sycl/dsv4-hc.hpp" 73#include "ggml-sycl/lightning-indexer.hpp" 74#include "ggml-sycl/conv2d.hpp" 75#include "ggml-sycl/conv2d-dw.hpp" 76#include "ggml-sycl/conv2d-transpose.hpp" 77#include "ggml-sycl/ssm_conv.hpp" 78#include "ggml-sycl/sycl_hw.hpp" 79#include "ggml-sycl/ssm_scan.hpp" 80#include "ggml-sycl/fill.hpp" 81#include "ggml-sycl/cumsum.hpp" 82#include "ggml-sycl/diag.hpp" 83#include "ggml-sycl/opt-step.hpp" 84#include "ggml-sycl/solve_tri.hpp" 85#include "ggml-sycl/gated_delta_net.hpp" 86#include "ggml-sycl/pool.hpp" 87#include "ggml-sycl/cross_entropy_loss.hpp" 88 89#define MEM_SIZE_2M 0x00200000 90#define MEM_SIZE_1G 0x40000000 91 92static bool g_sycl_loaded = false; 93int g_ggml_sycl_debug = 0 ; 94int g_ggml_sycl_dev_debug = 0 ; 95int g_ggml_sycl_enable_optimize = 1 ; 96int g_ggml_sycl_enable_graph = 0 ; 97int g_ggml_sycl_enable_dnn = 1 ; 98int g_ggml_sycl_fa_onednn = 1 ; 99int g_ggml_sycl_fa_onednn_max_kv = 0 ; 100int g_ggml_sycl_enable_mkl_fa = 1 ; 101int g_ggml_sycl_memtrace = 0 ; 102int g_ggml_sycl_memtrace_step = 64 ; 103int g_ggml_sycl_enable_vmm = 1 ; 104int g_ggml_sycl_enable_fusion = 1 ; 105int g_ggml_sycl_enable_esimd = 1 ; 106int g_ggml_sycl_prioritize_dmmv = 0 ; 107int g_ggml_sycl_use_async_mem_op = 0 ; 108int g_ggml_sycl_use_async_mem_op_requested = 1 ; 109int g_ggml_sycl_use_level_zero_api = 0 ; 110int g_ggml_sycl_enable_flash_attention = 1 ; 111int g_ggml_sycl_dev2dev_memcpy = DEV2DEV_MEMCPY_SYCL ; 112int g_ggml_sycl_usm_system = 0 ; 113int g_ggml_sycl_enable_host_pinned_mem = 1 ; 114int g_ggml_sycl_host_pinned_mem_2g = 0 ; 115int g_ggml_sycl_get_mem_api = MEMORY_API_TYPE_LEVEL_ZERO ; 116 117static ggml_sycl_device_info ggml_sycl_init () { 118GGML_SYCL_DEBUG ("[SYCL] call ggml_sycl_init\n" ); 119ggml_sycl_device_info info = {}; 120 121// Do not hard crash when there exists no SYCL devices. 122// We want to allow the user to use non-SYCL tools when SYCL is compiled (such as llama-quantize) 123try { 124info .device_count = dpct::dev_mgr::instance ().device_count (); 125 }catch (sycl::exception const & exc ) { 126GGML_LOG_INFO ("%s: no SYCL device available: %s\n" ,__func__ ,exc .what ()); 127info .device_count = 0 ; 128 } 129if (info .device_count == 0 ) { 130GGML_LOG_ERROR ("%s: failed to initialize: %s\n" ,GGML_SYCL_NAME ,__func__ ); 131return info ; 132 } 133 134GGML_ASSERT (info .device_count <=GGML_SYCL_MAX_DEVICES ); 135 136int64_t total_vram = 0 ; 137/* This is a bit misleading; reserved for later */ 138// #if defined(SYCL_USE_XMX) 139// GGML_LOG_INFO("%s: SYCL_USE_XMX: yes\n", __func__); 140// #else 141// GGML_LOG_INFO("%s: SYCL_USE_XMX: no\n", __func__); 142// #endif 143for (int i = 0 ;i < info .device_count ;++ i ) { 144 dpct::device_info prop ; 145auto & device = dpct::dev_mgr::instance ().get_device (i ); 146 147SYCL_CHECK (CHECK_TRY_ERROR (dpct::get_device_info ( 148prop ,device ))); 149 150#if !defined(GGML_SYCL_SUPPORT_VMM ) 151info .devices [i ].vmm = 0 ; 152#else 153info .devices [i ].vmm = device .has (sycl::aspect::ext_oneapi_virtual_mem ); 154if (info .devices [i ].vmm ) { 155// NB: SYCL's get_mem_granularity always returns the _minimum_ granularity, 156// but the L0 API requires a larger page size for allocs above 2 MiB and 157// rejects non-multiples with UR_RESULT_ERROR_INVALID_VALUE [sic]. 158// Here we clamp it to 2 MiB for simplicity, but other devices may require 159// calling zeVirtualMemQueryPageSize or yet unexposed public API. 160const size_t physical_page = 2ull <<20 ;// 2 MiB 161info .devices [i ].vmm_granularity = std::max < size_t > ( 162 sycl::ext::oneapi::experimental::get_mem_granularity ( 163device , sycl::context (device )), 164physical_page ); 165 } 166#endif 167 168info .default_tensor_split [i ]= total_vram ; 169total_vram += prop .get_global_mem_size (); 170 171info .devices [i ].cc = 172100 * prop .get_major_version ()+ 10 * prop .get_minor_version (); 173info .devices [i ].nsm = prop .get_max_compute_units () /16 ;//16: Number of Xe Cores 174info .devices [i ].opt_feature .reorder = device .ext_oneapi_architecture_is (syclex::arch_category::intel_gpu ); 175info .devices [i ].smpbo = prop .get_local_mem_size (); 176info .devices [i ].warp_size = WARP_SIZE ; 177info .devices [i ].usm_system_support = device .has (sycl::aspect::usm_system_allocations ); 178 179info .max_work_group_sizes [i ]= prop .get_max_work_group_size (); 180info .devices [i ].max_wg_per_cu = info .max_work_group_sizes [i ] /prop .get_max_compute_units (); 181info .devices [i ].hw_info = get_device_hw_info (& device ); 182 183// Only check GPU devices; CPU devices use OpenCL and would otherwise 184// disable Level Zero for the GPUs on systems without ONEAPI_DEVICE_SELECTOR set. 185if (device .is_gpu ()&& device .default_queue ().get_backend ()!= sycl::backend::ext_oneapi_level_zero ) { 186GGML_LOG_WARN ("SYCL GPU device %d does not use Level Zero backend, disabling Level Zero memory API\n" ,i ); 187info .ext_oneapi_level_zero = false; 188 } 189 190#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 191if (info .ext_oneapi_level_zero && device .is_gpu ()&& device .default_queue ().get_backend ()== sycl::backend::ext_oneapi_level_zero ) { 192ze_device_handle_t ze_dev = sycl::get_native < sycl::backend::ext_oneapi_level_zero > (device .default_queue ().get_device ()); 193ze_device_properties_t props = {}; 194props .stype = ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES ; 195ze_result_t r = zeDeviceGetProperties (ze_dev ,& props ); 196if (r == ZE_RESULT_SUCCESS ) { 197info .devices [i ].l0_device_type_valid = true; 198info .devices [i ].l0_discrete_gpu = !(props .flags & ZE_DEVICE_PROPERTY_FLAG_INTEGRATED ); 199 } 200 } 201#endif 202 } 203 204for (int id = 0 ;id < info .device_count ;++ id ) { 205info .default_tensor_split [id ] /=total_vram ; 206 } 207 208#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 209//update g_ggml_sycl_use_level_zero_api according to the device support 210g_ggml_sycl_use_level_zero_api = 211info .ext_oneapi_level_zero && g_ggml_sycl_use_level_zero_api ; 212#endif 213 214return info ; 215} 216 217const ggml_sycl_device_info & ggml_sycl_info () { 218static ggml_sycl_device_info info = ggml_sycl_init (); 219return info ; 220} 221 222static void print_device_detail (int id , sycl::device & device , std::string device_type ) { 223 224 dpct::device_info prop ; 225SYCL_CHECK (CHECK_TRY_ERROR ( 226 dpct::get_device_info (prop ,device ))); 227 228 std::string version ; 229version += std::to_string (prop .get_major_version ()); 230version += "." ; 231version += std::to_string (prop .get_minor_version ()); 232 233device_type = std::regex_replace (device_type , std::regex ("ext_oneapi_" ),"" ); 234 std::string name = std::string (prop .get_name ()); 235name = std::regex_replace (name , std::regex ("\\(R\\)" ),"" ); 236name = std::regex_replace (name , std::regex ("\\(TM\\)" ),"" ); 237 238auto global_mem_size = prop .get_global_mem_size ()/1000000 ; 239GGML_LOG_INFO ("|%2d|%19s|%39s|%7s|%7d|%8d|%5d|%6luM|%21s|\n" ,id ,device_type .c_str (), 240name .c_str (),version .c_str (),prop .get_max_compute_units (), 241prop .get_max_work_group_size (),prop .get_max_sub_group_size (), 242global_mem_size ,device .get_info < sycl::info::device::driver_version > ().c_str ()); 243} 244 245static void print_device_opt_feature (int device_count ) { 246GGML_LOG_INFO ("SYCL Optimization Feature:\n" ); 247GGML_LOG_INFO ( 248"|ID| Device Type|Reorder|\n" ); 249GGML_LOG_INFO ( 250"|--|-------------------|-------|\n" ); 251 std::map < std::string ,size_t > DeviceNums ; 252for (int id = 0 ;id < device_count ;++ id ) { 253 sycl::device device = dpct::dev_mgr::instance ().get_device (id ); 254 std::string backend_type = get_device_backend_and_type (device ); 255int type_id = DeviceNums [backend_type ]++ ; 256 std::stringstream device_type ; 257device_type <<"[" <<backend_type <<":" << std::to_string (type_id ) 258 <<"]" ; 259 std::string device_type_s = device_type .str (); 260device_type_s = std::regex_replace (device_type_s , std::regex ("ext_oneapi_" ),"" ); 261GGML_LOG_INFO ("|%2d|%19s|%7s|\n" ,id ,device_type_s .c_str (), 262ggml_sycl_info ().devices [id ].opt_feature .reorder ?"Y" :"N" ); 263 } 264 265} 266void ggml_backend_sycl_print_sycl_devices () { 267GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_print_sycl_devices\n" ); 268int device_count = dpct::dev_mgr::instance ().device_count (); 269 std::map < std::string ,size_t > DeviceNums ; 270GGML_LOG_INFO ("Found %d SYCL devices:\n" ,device_count ); 271 272GGML_LOG_INFO ( 273"| | | | " 274" |Max | |Max |Global | |\n" ); 275GGML_LOG_INFO ( 276"| | | | " 277" |compute|Max work|sub |mem | |\n" ); 278GGML_LOG_INFO ( 279"|ID| Device Type| " 280"Name|Version|units |group |group|size | Driver version|\n" ); 281GGML_LOG_INFO ( 282"|--|-------------------|---------------------------------------|------" 283"-|-------|--------|-----|-------|---------------------|\n" ); 284 285for (int id = 0 ;id < device_count ;++ id ) { 286 sycl::device device = dpct::dev_mgr::instance ().get_device (id ); 287 std::string backend_type = get_device_backend_and_type (device ); 288int type_id = DeviceNums [backend_type ]++ ; 289 std::stringstream device_type ; 290device_type <<"[" <<backend_type <<":" << std::to_string (type_id ) 291 <<"]" ; 292print_device_detail (id ,device ,device_type .str ()); 293 } 294 295print_device_opt_feature (device_count ); 296} 297 298static const char * dev2dev_int2str (int dev2dev ) { 299if (dev2dev == DEV2DEV_MEMCPY_SYCL ) { 300return "SYCL API" ; 301 }else if (dev2dev == DEV2DEV_MEMCPY_L0 ) { 302return "Level Zero API" ; 303 }else if (dev2dev == DEV2DEV_MEMCPY_FORWARD ) { 304return "Host Forward" ; 305 }else { 306return "Unknown" ; 307 } 308} 309 310/* 311* There are several entry APIs to be called as first function in SYCL backend in different cases. 312* It's the first internal function to be called by them in SYCL backend. 313* This function is used to do initialize work for the SYCL backend and set the global variables. 314*/ 315#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 316static ze_result_t init_zes () { 317ze_result_t res = zesInit (0 ); 318if (res != ZE_RESULT_SUCCESS ) { 319GGML_SYCL_DEBUG ("Warning: [%s] zesInit failed with code %d. Sysman free-memory query be unavailable.\n" , 320__func__ , (int )res ); 321 } 322return res ; 323} 324 325ze_result_t get_zes_init_res () { 326static ze_result_t zes_init_res = init_zes (); 327GGML_SYCL_DEBUG ("[SYCL] call %s: zesInit result: %d\n" ,__func__ , (int )zes_init_res ); 328return zes_init_res ; 329} 330#endif 331 332void initialize_sycl_begining () { 333#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 334//must be called in initialization stage, before any other Level Zero API calls 335GGML_SYCL_DEBUG ("[SYCL] call %s\n" ,__func__ ); 336get_zes_init_res (); 337#endif 338} 339 340static void ggml_check_sycl ()try { 341GGML_SYCL_DEBUG ("[SYCL] ggml_check_sycl()\n" ); 342static bool initialized = false; 343 344if (!initialized ) { 345initialize_sycl_begining (); 346 347g_ggml_sycl_debug = ggml_sycl_get_env ("GGML_SYCL_DEBUG" ,0 ); 348g_ggml_sycl_dev_debug = ggml_sycl_get_env ("GGML_SYCL_DEV_DEBUG" ,0 ); 349g_ggml_sycl_enable_optimize = ggml_sycl_get_env ("GGML_SYCL_ENABLE_OPT" ,1 ); 350g_ggml_sycl_enable_graph = ggml_sycl_get_env ("GGML_SYCL_ENABLE_GRAPH" ,0 ); 351g_ggml_sycl_enable_dnn = ggml_sycl_get_env ("GGML_SYCL_ENABLE_DNN" ,1 ); 352g_ggml_sycl_fa_onednn = ggml_sycl_get_env ("GGML_SYCL_FA_ONEDNN" ,1 ); 353g_ggml_sycl_fa_onednn_max_kv = ggml_sycl_get_env ("GGML_SYCL_FA_ONEDNN_MAX_KV" ,0 ); 354g_ggml_sycl_enable_mkl_fa = ggml_sycl_get_env ("GGML_SYCL_ENABLE_MKL_FA" ,1 ); 355g_ggml_sycl_memtrace = ggml_sycl_get_env ("GGML_SYCL_MEMTRACE" ,0 ); 356g_ggml_sycl_memtrace_step = ggml_sycl_get_env ("GGML_SYCL_MEMTRACE_STEP" ,64 ); 357g_ggml_sycl_enable_vmm = ggml_sycl_get_env ("GGML_SYCL_ENABLE_VMM" ,1 ); 358g_ggml_sycl_enable_fusion = ggml_sycl_get_env ("GGML_SYCL_ENABLE_FUSION" ,1 ); 359g_ggml_sycl_enable_esimd = ggml_sycl_get_env ("GGML_SYCL_ENABLE_ESIMD" ,1 ); 360g_ggml_sycl_prioritize_dmmv = ggml_sycl_get_env ("GGML_SYCL_PRIORITIZE_DMMV" ,0 ); 361 362#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 363g_ggml_sycl_use_level_zero_api = ggml_sycl_get_env ("GGML_SYCL_USE_LEVEL_ZERO_API" ,1 ); 364#else 365g_ggml_sycl_use_level_zero_api = 0 ; 366#endif 367g_ggml_sycl_dev2dev_memcpy = ggml_sycl_get_env ("GGML_SYCL_DEV2DEV_MEMCPY" ,DEV2DEV_MEMCPY_SYCL ); 368g_ggml_sycl_get_mem_api = ggml_sycl_get_env ("GGML_SYCL_GET_MEM_API" ,MEMORY_API_TYPE_LEVEL_ZERO ); 369if (g_ggml_sycl_use_level_zero_api == 0 ) { 370g_ggml_sycl_dev2dev_memcpy = DEV2DEV_MEMCPY_SYCL ; 371g_ggml_sycl_get_mem_api = MEMORY_API_TYPE_SYCL ; 372 } 373 374#ifdef SYCL_FLASH_ATTN 375g_ggml_sycl_enable_flash_attention = ggml_sycl_get_env ("GGML_SYCL_ENABLE_FLASH_ATTN" ,1 ); 376#else 377g_ggml_sycl_enable_flash_attention = 0 ; 378#endif 379 380g_ggml_sycl_usm_system = ggml_sycl_get_env ("GGML_SYCL_USM_SYSTEM" ,0 ); 381g_ggml_sycl_enable_host_pinned_mem = 382ggml_sycl_get_env ("GGML_SYCL_ENABLE_HOST_PINNED_MEM" ,1 ); 383 384g_ggml_sycl_host_pinned_mem_2g = 385ggml_sycl_get_env ("GGML_SYCL_HOST_PINNED_MEM_2G" ,0 )& g_ggml_sycl_enable_host_pinned_mem ; 386 387GGML_SYCL_DEBUG ("[SYCL] call ggml_check_sycl\n" ); 388 389GGML_LOG_INFO ("Build with Macros:\n" ); 390#if defined(GGML_SYCL_DNNL ) 391GGML_LOG_INFO (" GGML_SYCL_DNNL: yes\n" ); 392#else 393GGML_LOG_INFO (" GGML_SYCL_DNNL: no\n" ); 394#endif 395 396#if defined(GGML_SYCL_F16 ) 397GGML_LOG_INFO (" GGML_SYCL_F16: yes\n" ); 398#else 399GGML_LOG_INFO (" GGML_SYCL_F16: no\n" ); 400#endif 401 402#if defined(GGML_SYCL_FORCE_MMQ ) 403GGML_LOG_INFO (" GGML_SYCL_FORCE_MMQ: yes\n" ); 404#else 405GGML_LOG_INFO (" GGML_SYCL_FORCE_MMQ: no\n" ); 406#endif 407 408#if defined(GGML_SYCL_GRAPH ) 409GGML_LOG_INFO (" GGML_SYCL_GRAPH: yes\n" ); 410#else 411GGML_LOG_INFO (" GGML_SYCL_GRAPH: no\n" ); 412#endif 413 414#if defined(GGML_SYCL_SUPPORT_LEVEL_ZERO_API ) 415GGML_LOG_INFO (" GGML_SYCL_SUPPORT_LEVEL_ZERO_API: yes\n" ); 416#else 417GGML_LOG_INFO (" GGML_SYCL_SUPPORT_LEVEL_ZERO_API: no\n" ); 418#endif 419#if defined(GGML_SYCL_SUPPORT_VMM ) 420GGML_LOG_INFO (" GGML_SYCL_SUPPORT_VMM: yes\n" ); 421#else 422GGML_LOG_INFO (" GGML_SYCL_SUPPORT_VMM: no\n" ); 423#endif 424 425GGML_LOG_INFO ("Running with Environment Variables:\n" ); 426GGML_LOG_INFO (" GGML_SYCL_DEBUG: %d\n" ,g_ggml_sycl_debug ); 427GGML_LOG_INFO (" GGML_SYCL_DEV_DEBUG: %d\n" ,g_ggml_sycl_dev_debug ); 428 429#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 430GGML_LOG_INFO (" GGML_SYCL_DEV2DEV_MEMCPY: %d (%s)\n" ,g_ggml_sycl_dev2dev_memcpy ,dev2dev_int2str (g_ggml_sycl_dev2dev_memcpy )); 431GGML_LOG_INFO (" GGML_SYCL_GET_MEM_API: %d (%s)\n" ,g_ggml_sycl_get_mem_api ,mem_api_int2str (g_ggml_sycl_get_mem_api )); 432#else 433GGML_LOG_INFO (" GGML_SYCL_DEV2DEV_MEMCPY: %d (%s), enable to SYCL API since missing GGML_SYCL_SUPPORT_LEVEL_ZERO_API\n" , 434g_ggml_sycl_dev2dev_memcpy ,dev2dev_int2str (g_ggml_sycl_dev2dev_memcpy )); 435GGML_LOG_INFO (" GGML_SYCL_GET_MEM_API: %d (%s), enable to SYCL API since missing GGML_SYCL_SUPPORT_LEVEL_ZERO_API\n" , 436g_ggml_sycl_get_mem_api ,mem_api_int2str (g_ggml_sycl_get_mem_api )); 437#endif 438 439#if defined(GGML_SYCL_DNNL ) 440GGML_LOG_INFO (" GGML_SYCL_ENABLE_DNN: %d\n" ,g_ggml_sycl_enable_dnn ); 441GGML_LOG_INFO (" GGML_SYCL_FA_ONEDNN: %d\n" ,g_ggml_sycl_fa_onednn ); 442#else 443GGML_LOG_INFO (" GGML_SYCL_ENABLE_DNN: DNN disabled by compile flag\n" ); 444GGML_LOG_INFO (" GGML_SYCL_FA_ONEDNN: %d\n" ,g_ggml_sycl_fa_onednn ); 445#endif 446GGML_LOG_INFO (" GGML_SYCL_FA_ONEDNN_MAX_KV: %d\n" ,g_ggml_sycl_fa_onednn_max_kv ); 447GGML_LOG_INFO (" GGML_SYCL_ENABLE_MKL_FA: %d\n" ,g_ggml_sycl_enable_mkl_fa ); 448GGML_LOG_INFO (" GGML_SYCL_MEMTRACE: %d\n" ,g_ggml_sycl_memtrace ); 449GGML_LOG_INFO (" GGML_SYCL_MEMTRACE_STEP: %d\n" ,g_ggml_sycl_memtrace_step ); 450#ifdef SYCL_FLASH_ATTN 451GGML_LOG_INFO (" GGML_SYCL_ENABLE_FLASH_ATTN: %d\n" ,g_ggml_sycl_enable_flash_attention ); 452#else 453GGML_LOG_INFO (" GGML_SYCL_ENABLE_FLASH_ATTN: %d disabled by compile flag\n" , 454g_ggml_sycl_enable_flash_attention ); 455#endif 456 457#ifdef GGML_SYCL_GRAPH 458GGML_LOG_INFO (" GGML_SYCL_ENABLE_GRAPH: %d\n" ,g_ggml_sycl_enable_graph ); 459#else 460GGML_LOG_INFO (" GGML_SYCL_ENABLE_GRAPH: graph disabled by compile flag\n" ); 461#endif 462 463GGML_LOG_INFO (" GGML_SYCL_ENABLE_OPT: %d\n" ,g_ggml_sycl_enable_optimize ); 464 465#if defined(GGML_SYCL_SUPPORT_VMM ) 466GGML_LOG_INFO (" GGML_SYCL_ENABLE_VMM: %d\n" ,g_ggml_sycl_enable_vmm ); 467#else 468GGML_LOG_INFO (" GGML_SYCL_ENABLE_VMM: virtual memory extension is not available\n" ); 469#endif 470 471GGML_LOG_INFO (" GGML_SYCL_ENABLE_FUSION: %d\n" ,g_ggml_sycl_enable_fusion ); 472 473#if defined(__INTEL_LLVM_COMPILER ) 474GGML_LOG_INFO (" GGML_SYCL_ENABLE_ESIMD: %d\n" ,g_ggml_sycl_enable_esimd ); 475#else 476GGML_LOG_INFO (" GGML_SYCL_ENABLE_ESIMD: %d disabled by compile flag\n" ,g_ggml_sycl_enable_esimd ); 477#endif 478 479GGML_LOG_INFO (" GGML_SYCL_PRIORITIZE_DMMV: %d\n" ,g_ggml_sycl_prioritize_dmmv ); 480 481g_ggml_sycl_use_async_mem_op_requested = ggml_sycl_get_env ("GGML_SYCL_USE_ASYNC_MEM_OP" ,1 ); 482GGML_LOG_INFO (" GGML_SYCL_USE_ASYNC_MEM_OP: %d\n" ,g_ggml_sycl_use_async_mem_op_requested ); 483 484#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 485GGML_LOG_INFO (" GGML_SYCL_USE_LEVEL_ZERO_API: %d\n" ,g_ggml_sycl_use_level_zero_api ); 486#else 487GGML_LOG_INFO (" GGML_SYCL_USE_LEVEL_ZERO_API: Disable Level Zero API usage by compile flag\n" ); 488#endif 489 490GGML_LOG_INFO (" GGML_SYCL_USM_SYSTEM: %d\n" ,g_ggml_sycl_usm_system ); 491GGML_LOG_INFO (" GGML_SYCL_ENABLE_HOST_PINNED_MEM: %d\n" ,g_ggml_sycl_enable_host_pinned_mem ); 492GGML_LOG_INFO (" GGML_SYCL_HOST_PINNED_MEM_2G: %d\n" ,g_ggml_sycl_host_pinned_mem_2g ); 493 494/* NOT REMOVE, keep it for next optimize for XMX. 495#if defined(SYCL_USE_XMX) 496fprintf(stderr, "%s: SYCL_USE_XMX: yes\n", __func__); 497#else 498fprintf(stderr, "%s: SYCL_USE_XMX: no\n", __func__); 499#endif 500*/ 501// Async USM allocation/free is also useful outside the graph path: it avoids the host waits in the reorder 502// staging path while preserving queue ordering semantics. Graph support still depends on the extension being 503// available, but it no longer needs to control the non-graph fast path. 504#if defined(GGML_SYCL_GRAPH )&& SYCL_EXT_ONEAPI_ASYNC_MEMORY_ALLOC 505g_ggml_sycl_use_async_mem_op = g_ggml_sycl_use_async_mem_op_requested || g_ggml_sycl_enable_graph ; 506if (g_ggml_sycl_use_async_mem_op ) { 507for (unsigned int i = 0 ;i < dpct::dev_mgr::instance ().device_count ();++ i ) { 508if (!dpct::dev_mgr::instance ().get_device (i ).has (sycl::aspect::ext_oneapi_async_memory_alloc )) { 509g_ggml_sycl_use_async_mem_op = 0 ; 510break ; 511 } 512 } 513 } 514#endif 515if (CHECK_TRY_ERROR (g_all_sycl_device_count = 516 dpct::dev_mgr::instance ().device_count ())!= 0 ) { 517initialized = true; 518g_sycl_loaded = false; 519return ; 520 } 521GGML_ASSERT (g_all_sycl_device_count <=GGML_SYCL_MAX_DEVICES ); 522 523initialized = true; 524g_sycl_loaded = true; 525ggml_backend_sycl_print_sycl_devices (); 526 } 527} 528catch (sycl::exception const & exc ) { 529 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 530 <<", line:" <<__LINE__ << std::endl ; 531 std::exit (1 ); 532} 533 534/* 535device_index: device index from 0 to n (continue numbers). 536It is used for device select/set in SYCL backend internal data structure. 537*/ 538inline void check_allow_gpu_index (const int device_index ) { 539if (device_index >=ggml_sycl_info ().device_count ) { 540char error_buf [256 ]; 541snprintf ( 542error_buf , 543sizeof (error_buf ), 544"%s error: device_index:%d is out of range: [0-%d]" , 545__func__ , 546device_index , 547ggml_sycl_info ().device_count - 1 ); 548GGML_LOG_ERROR ("%s\n" ,error_buf ); 549assert (false); 550 } 551} 552 553GGML_API void ggml_backend_sycl_get_gpu_list (int * id_list ,int max_len )try { 554GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_get_gpu_list\n" ); 555for (int i = 0 ;i < max_len ;i ++ )id_list [i ]= -1 ; 556 557for (int i = 0 ;i < ggml_sycl_info ().device_count ;i ++ ){ 558if (i >=max_len )break ; 559id_list [i ]= i ; 560 } 561return ; 562} 563catch (sycl::exception const & exc ) { 564 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 565 <<", line:" <<__LINE__ << std::endl ; 566 std::exit (1 ); 567} 568 569inline void free_aligned_mem_host (void * memblock ) { 570#ifdef _WIN32 571_aligned_free (memblock ); 572#else 573free (memblock ); 574#endif 575} 576 577// sycl buffer 578 579struct ggml_backend_sycl_buffer_context { 580int device ; 581void * dev_ptr = nullptr ; 582queue_ptr stream ; 583 std::string name ; 584optimize_feature opt_feature ; 585 std::vector < ggml_tensor_extra_gpu *> tensor_extras ; 586bool is_usm_system ; 587 588ggml_backend_sycl_buffer_context (int device ,void * dev_ptr ,queue_ptr stream ,bool is_usm_system ) : 589device (device ),dev_ptr (dev_ptr ),stream (stream ),is_usm_system (is_usm_system ) { 590check_allow_gpu_index (device ); 591name = (GGML_SYCL_NAME + std::to_string (device )); 592opt_feature = ggml_sycl_info ().devices [device ].opt_feature ; 593 } 594 595 ~ggml_backend_sycl_buffer_context () { 596if (dev_ptr != nullptr ) { 597ggml_sycl_set_device (device ); 598if (is_usm_system ) 599free_aligned_mem_host (dev_ptr ); 600else 601SYCL_CHECK (CHECK_TRY_ERROR (ggml_sycl_free_device (dev_ptr ,* stream ))); 602 } 603 604//release extra used by tensors 605for (ggml_tensor_extra_gpu * extra :tensor_extras ) { 606release_extra_gpu (extra ); 607 } 608 609 } 610}; 611 612static const char * ggml_backend_sycl_buffer_type_get_name (ggml_backend_buffer_type_t buft ); 613 614static bool ggml_backend_buffer_is_sycl (ggml_backend_buffer_t buffer ) { 615return buffer -> buft -> iface .get_name == ggml_backend_sycl_buffer_type_get_name ; 616} 617 618static void 619ggml_backend_sycl_buffer_free_buffer (ggml_backend_buffer_t buffer )try { 620ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 621ggml_sycl_set_device (ctx -> device ); 622 623delete ctx ; 624} 625catch (sycl::exception const & exc ) { 626 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 627 <<", line:" <<__LINE__ << std::endl ; 628 std::exit (1 ); 629} 630 631static void * ggml_backend_sycl_buffer_get_base (ggml_backend_buffer_t buffer ) { 632ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 633return ctx -> dev_ptr ; 634} 635 636static enum ggml_status 637ggml_backend_sycl_buffer_init_tensor (ggml_backend_buffer_t buffer , 638ggml_tensor * tensor )try { 639GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 640GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ,"\n" ).c_str ()); 641ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 642 643if (tensor -> view_src != NULL ) { 644assert (tensor -> view_src -> buffer -> buft == buffer -> buft ); 645return GGML_STATUS_SUCCESS ; 646 } 647 648if (g_ggml_sycl_enable_optimize ) { 649// set reorder extra buffer based on supported type 650switch (tensor -> type ) { 651case GGML_TYPE_Q4_0 : 652case GGML_TYPE_Q8_0 : 653case GGML_TYPE_Q2_K : 654case GGML_TYPE_Q3_K : 655case GGML_TYPE_Q4_K : 656case GGML_TYPE_Q5_K : 657case GGML_TYPE_Q6_K :{ 658ggml_tensor_extra_gpu * extra = new ggml_tensor_extra_gpu {}; 659tensor -> extra = extra ; 660ctx -> tensor_extras .push_back (extra ); 661break ; 662 } 663default : 664break ; 665 } 666 } 667 668if (ggml_is_quantized (tensor -> type )) { 669// initialize padding to 0 to avoid possible NaN values 670size_t original_size = ggml_nbytes (tensor ); 671size_t padded_size = ggml_backend_buft_get_alloc_size (buffer -> buft ,tensor ); 672 673if (padded_size > original_size && tensor -> view_src == nullptr ) { 674SYCL_CHECK (CHECK_TRY_ERROR (ctx -> stream -> memset ( 675 (char * )tensor -> data + original_size ,0 , 676padded_size - original_size ).wait ())); 677 } 678 } 679return GGML_STATUS_SUCCESS ; 680} 681catch (sycl::exception const & exc ) { 682 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 683 <<", line:" <<__LINE__ << std::endl ; 684 std::exit (1 ); 685} 686 687static void ggml_backend_sycl_buffer_set_tensor (ggml_backend_buffer_t buffer , 688ggml_tensor * tensor , 689const void * data ,size_t offset , 690size_t size )try { 691GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 692GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 693GGML_SYCL_DEBUG (" size=%zu offset=%zu\n" ,size ,offset ); 694ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 695ggml_sycl_set_device (ctx -> device ); 696auto stream = & (dpct::dev_mgr::instance ().get_device (ctx -> device ).default_queue ()); 697SYCL_CHECK (CHECK_TRY_ERROR (dpct::dev_mgr::instance ().get_device (ctx -> device ).queues_wait_and_throw ())); 698#ifndef _WIN32 699// Note: Use host buffer to save the data from mmap(), then copy to device. It's workaround for mmap() issue on PVC GPU. 700// This function will be called during load model from disk. Use memory buffer replace dynamic won't save more time and brings potential memory leak risk here. 701char * host_buf = (char * )malloc (size ); 702memcpy (host_buf ,data ,size ); 703SYCL_CHECK (CHECK_TRY_ERROR ((* stream ).memcpy ((char * )tensor -> data + offset ,host_buf ,size ).wait ())); 704free (host_buf ); 705#else 706SYCL_CHECK (CHECK_TRY_ERROR ((* stream ).memcpy ((char * )tensor -> data + offset ,data ,size ).wait ())); 707#endif 708} 709catch (sycl::exception const & exc ) { 710 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 711 <<", line:" <<__LINE__ << std::endl ; 712 std::exit (1 ); 713} 714 715static void ggml_backend_sycl_buffer_get_tensor (ggml_backend_buffer_t buffer , 716const ggml_tensor * tensor , 717void * data ,size_t offset , 718size_t size )try { 719GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 720GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 721GGML_SYCL_DEBUG (" size=%zu offset=%zu\n" ,size ,offset ); 722ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 723 724ggml_sycl_set_device (ctx -> device ); 725auto stream = dpct::dev_mgr::instance ().get_device (ctx -> device ).default_queue (); 726 727SYCL_CHECK (CHECK_TRY_ERROR ( 728stream .memcpy (data , (const char * )tensor -> data + offset ,size ) 729 .wait ())); 730} 731catch (sycl::exception const & exc ) { 732 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 733 <<", line:" <<__LINE__ << std::endl ; 734 std::exit (1 ); 735} 736 737#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 738static bool ggml_sycl_is_l0_discrete_gpu (int device ) { 739return ggml_sycl_info ().devices [device ].l0_discrete_gpu ; 740} 741#endif 742 743static void dev2dev_memcpy (int device_dst , sycl::queue & q_dst ,int device_src , sycl::queue & q_src ,void * ptr_dst , 744const void * ptr_src ,size_t size ) { 745 746#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 747if (g_ggml_sycl_dev2dev_memcpy == DEV2DEV_MEMCPY_L0 ) { 748// Use Level Zero direct copy for dGPU-to-dGPU transfers. 749const bool l0_copy_supported = 750ggml_sycl_is_l0_discrete_gpu (device_dst )&& ggml_sycl_is_l0_discrete_gpu (device_src ); 751if (g_ggml_sycl_use_level_zero_api && l0_copy_supported ) { 752auto ze_ctx = sycl::get_native < sycl::backend::ext_oneapi_level_zero > (q_dst .get_context ()); 753auto ze_dev = sycl::get_native < sycl::backend::ext_oneapi_level_zero > (q_dst .get_device ()); 754ze_command_queue_desc_t cq_desc = {ZE_STRUCTURE_TYPE_COMMAND_QUEUE_DESC ,nullptr ,0 ,0 , 7550 ,ZE_COMMAND_QUEUE_MODE_SYNCHRONOUS ,ZE_COMMAND_QUEUE_PRIORITY_NORMAL }; 756ze_command_list_handle_t cl ; 757ze_result_t r = zeCommandListCreateImmediate (ze_ctx ,ze_dev ,& cq_desc ,& cl ); 758if (r == ZE_RESULT_SUCCESS ) { 759GGML_SYCL_DEBUG ("[SYCL] dev2dev memcpy by L0\n" ); 760r = zeCommandListAppendMemoryCopy (cl ,ptr_dst ,ptr_src ,size ,nullptr ,0 ,nullptr ); 761zeCommandListDestroy (cl ); 762if (r == ZE_RESULT_SUCCESS ) { 763return ; 764 } 765 } 766 } 767 } 768#endif 769 770if (g_ggml_sycl_dev2dev_memcpy == DEV2DEV_MEMCPY_SYCL ) { 771if (q_dst .get_device ().ext_oneapi_can_access_peer (q_src .get_device (), 772 sycl::ext::oneapi::peer_access::access_supported )) { 773GGML_SYCL_DEBUG ("[SYCL] dev2dev memcpy by SYCL\n" ); 774q_dst .get_device ().ext_oneapi_enable_peer_access (q_src .get_device ()); 775SYCL_CHECK (CHECK_TRY_ERROR (q_dst .memcpy (ptr_dst ,ptr_src ,size ).wait ())); 776return ; 777 } 778 } 779 780// Host-staged copy 781if (g_ggml_sycl_dev2dev_memcpy == DEV2DEV_MEMCPY_FORWARD ) { 782GGML_SYCL_DEBUG ("[SYCL] dev2dev memcpy by host forward for setting GGML_SYCL_DEV2DEV_MEMCPY=2\n" ); 783 }else { 784GGML_SYCL_DEBUG ("[SYCL] dev2dev memcpy by host forward for SYCL/L0 fallback\n" ); 785 } 786char * host_buf = (char * )malloc (size ); 787q_src .memcpy (host_buf , (const char * )ptr_src ,size ).wait (); 788q_dst .memcpy ((char * )ptr_dst ,host_buf ,size ).wait (); 789free (host_buf ); 790} 791 792static bool 793ggml_backend_sycl_buffer_cpy_tensor (ggml_backend_buffer_t buffer , 794const ggml_tensor * src , 795ggml_tensor * dst )try { 796bool is_cpy_supported = ggml_backend_buffer_is_sycl (src -> buffer ); 797GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 798GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": dst" ,dst ).c_str ()); 799GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (" src" ,src ).c_str ()); 800GGML_SYCL_DEBUG (" is_cpy_supported=%d\n" ,is_cpy_supported ); 801if (is_cpy_supported ) { 802ggml_backend_sycl_buffer_context * src_ctx = (ggml_backend_sycl_buffer_context * )src -> buffer -> context ; 803ggml_backend_sycl_buffer_context * dst_ctx = (ggml_backend_sycl_buffer_context * )dst -> buffer -> context ; 804 805ggml_sycl_set_device (src_ctx -> device ); 806/* 807DPCT1009:198: SYCL uses exceptions to report errors and does not use the 808error codes. The original code was commented out and a warning string 809was inserted. You need to rewrite this code. 810*/ 811SYCL_CHECK (CHECK_TRY_ERROR ( 812 dpct::dev_mgr::instance ().get_device (src_ctx -> device ).queues_wait_and_throw ())); 813ggml_sycl_set_device (dst_ctx -> device ); 814/* 815DPCT1009:199: SYCL uses exceptions to report errors and does not use the 816error codes. The original code was commented out and a warning string 817was inserted. You need to rewrite this code. 818*/ 819SYCL_CHECK (CHECK_TRY_ERROR ( 820 dpct::dev_mgr::instance ().get_device (dst_ctx -> device ).queues_wait_and_throw ())); 821/* 822DPCT1009:200: SYCL uses exceptions to report errors and does not use the 823error codes. The original code was commented out and a warning string 824was inserted. You need to rewrite this code. 825*/ 826 827queue_ptr stream_dst = dst_ctx -> stream ; 828queue_ptr stream_src = src_ctx -> stream ; 829size_t size = ggml_nbytes (src ); 830 831//todo. it's dirty solutino to walkaroud known issue:device2device cross GPUs. 832dev2dev_memcpy (dst_ctx -> device ,* stream_dst ,src_ctx -> device ,* stream_src ,dst -> data ,src -> data ,size ); 833 834//todo, it's known issue:error in device2device cross GPUs. reused when the issue is fixed. DON"T remove 835#if 0 836SYCL_CHECK (CHECK_TRY_ERROR ((* stream ).memcpy ( 837 (char * )dst -> data , (const char * )src -> data ,size ).wait ())); 838 839/* 840DPCT1009:201: SYCL uses exceptions to report errors and does not use the 841error codes. The original code was commented out and a warning string 842was inserted. You need to rewrite this code. 843*/ 844SYCL_CHECK (CHECK_TRY_ERROR ( 845 dpct::dev_mgr::instance ().get_device (dst_ctx -> device ).queues_wait_and_throw ())); 846#endif 847return true; 848 } 849return false; 850GGML_UNUSED (buffer ); 851}catch (const sycl::exception & exc ) { 852 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ <<", line:" <<__LINE__ << std::endl ; 853 std::exit (1 ); 854} 855 856static void ggml_backend_sycl_buffer_clear (ggml_backend_buffer_t buffer , 857uint8_t value )try { 858GGML_SYCL_DEBUG ("[SYCL] call %s: size=%zu\n" ,__func__ ,buffer -> size ); 859ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 860 861ggml_sycl_set_device (ctx -> device ); 862queue_ptr stream = ctx -> stream ; 863SYCL_CHECK ( 864CHECK_TRY_ERROR (dpct::get_current_device ().queues_wait_and_throw ())); 865 866constexpr size_t MAX_CHUNK = 2ULL <<30 ;// 2 GiB 867for (size_t off = 0 ;off < buffer -> size ;off += MAX_CHUNK ) { 868size_t chunk = std::min (buffer -> size - off ,MAX_CHUNK ); 869SYCL_CHECK (CHECK_TRY_ERROR ( 870 (* stream ) 871 .memset (static_cast < char *> (ctx -> dev_ptr )+ off ,value ,chunk ) 872 .wait () 873 )); 874 } 875} 876catch (sycl::exception const & exc ) { 877 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 878 <<", line:" <<__LINE__ << std::endl ; 879 std::exit (1 ); 880} 881 882static void ggml_backend_sycl_buffer_memset_tensor (ggml_backend_buffer_t buffer ,ggml_tensor * tensor ,uint8_t value , 883size_t offset ,size_t size ) { 884GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 885GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 886GGML_SYCL_DEBUG (" size=%zu offset=%zu value=%u\n" ,size ,offset ,value ); 887ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 888SYCL_CHECK (ggml_sycl_set_device (ctx -> device )); 889auto stream = & (dpct::dev_mgr::instance ().get_device (ctx -> device ).default_queue ()); 890if (size == 0 ) { 891return ;// Nothing to do 892 } 893if (tensor -> data == nullptr ) { 894GGML_ABORT ("Error: Tensor data pointer is null.\n" ); 895 } 896void * target_ptr = static_cast < char *> (tensor -> data )+ offset ; 897SYCL_CHECK (CHECK_TRY_ERROR ((* stream ).memset (target_ptr ,value ,size ))); 898SYCL_CHECK (CHECK_TRY_ERROR ((* stream ).wait ())); 899} 900 901static void ggml_backend_sycl_buffer_reset (ggml_backend_buffer_t buffer ) { 902GGML_SYCL_DEBUG ("[SYCL] call %s\n" ,__func__ ); 903if (buffer == nullptr ) { 904return ; 905 } 906 907ggml_backend_sycl_buffer_context * ctx = (ggml_backend_sycl_buffer_context * )buffer -> context ; 908 909if (ctx != nullptr ) { 910for (ggml_tensor_extra_gpu * extra :ctx -> tensor_extras ) { 911release_extra_gpu (extra ); 912 } 913ctx -> tensor_extras .clear ();// reset the tensor_extras vector 914 } 915} 916 917static const ggml_backend_buffer_i ggml_backend_sycl_buffer_interface = { 918/* .free_buffer = */ ggml_backend_sycl_buffer_free_buffer , 919/* .get_base = */ ggml_backend_sycl_buffer_get_base , 920/* .init_tensor = */ ggml_backend_sycl_buffer_init_tensor , 921/* .memset_tensor = */ ggml_backend_sycl_buffer_memset_tensor , 922/* .set_tensor = */ ggml_backend_sycl_buffer_set_tensor , 923/* .get_tensor = */ ggml_backend_sycl_buffer_get_tensor , 924/* .set_tensor_2d = */ NULL , 925/* .get_tensor_2d = */ NULL , 926/* .cpy_tensor = */ ggml_backend_sycl_buffer_cpy_tensor , 927/* .clear = */ ggml_backend_sycl_buffer_clear , 928/* .reset = */ ggml_backend_sycl_buffer_reset , 929}; 930 931// sycl buffer type 932struct ggml_backend_sycl_buffer_type_context { 933int device ; 934 std::string name ; 935 936// each buffer type has its own stream 937queue_ptr stream = nullptr ; 938}; 939 940static const char * ggml_backend_sycl_buffer_type_get_name (ggml_backend_buffer_type_t buft ) { 941ggml_backend_sycl_buffer_type_context * ctx = (ggml_backend_sycl_buffer_type_context * )buft -> context ; 942 943return ctx -> name .c_str (); 944} 945 946static bool check_usm_system (int device ,size_t size ) { 947bool use_usm_system = g_ggml_sycl_usm_system && size >= ((size_t )4 * MEM_SIZE_1G ); 948 949if (use_usm_system && !ggml_sycl_info ().devices [device ].usm_system_support ) { 950GGML_LOG_INFO ("Device does not support USM system allocations\n" ); 951use_usm_system = false; 952 } 953 954return use_usm_system ; 955} 956 957inline void * aligned_malloc_host (size_t alignment ,size_t size ) { 958#ifdef _WIN32 959return _aligned_malloc (size ,alignment ); 960#else 961return aligned_alloc (alignment ,size ); 962#endif 963} 964 965static ggml_backend_buffer_t 966ggml_backend_sycl_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft , 967size_t size )try { 968GGML_SYCL_DEBUG ("[SYCL] call %s: size=%zu\n" ,__func__ ,size ); 969ggml_check_sycl (); 970 971ggml_backend_sycl_buffer_type_context * buft_ctx = (ggml_backend_sycl_buffer_type_context * )buft -> context ; 972ggml_sycl_set_device (buft_ctx -> device ); 973const queue_ptr stream = buft_ctx -> stream ; 974size = std::max (size , (size_t )1 );// syclMalloc returns null for size 0 975/* 976Alignment below ensures best performance. While in theory it could lead to 977wasting memory, this is acceptable because in practice only few buffers are 978allocated and even less exceed the minimum size accepted here for USM system 979allocations. 980*/ 981size_t alignment = MEM_SIZE_2M ; 982size_t aligned_size = ((size + alignment - 1 ) /alignment )* alignment ; 983bool use_usm_system = check_usm_system (buft_ctx -> device ,aligned_size ); 984 985void * dev_ptr ; 986if (use_usm_system ) { 987GGML_SYCL_DEBUG ("[SYCL] allocating %zu Bytes with USM system\n" ,size ); 988dev_ptr = (void * )aligned_malloc_host (alignment ,aligned_size ); 989if (!dev_ptr ) { 990GGML_LOG_ERROR ("%s: can't allocate %zu Bytes of memory on host\n" ,__func__ ,size ); 991return nullptr ; 992 } 993 }else { 994SYCL_CHECK (CHECK_TRY_ERROR (dev_ptr = (void * )ggml_sycl_malloc_device (size ,* stream ,GGML_SYCL_MEM_BUFFER ))); 995if (!dev_ptr ) { 996GGML_LOG_ERROR ("%s: can't allocate %zu Bytes of memory on device\n" ,__func__ ,size ); 997return nullptr ; 998 } 999 } 1000ggml_backend_sycl_buffer_context * ctx = new ggml_backend_sycl_buffer_context (buft_ctx -> device ,dev_ptr ,buft_ctx -> stream ,use_usm_system ); 1001return ggml_backend_buffer_init (buft ,ggml_backend_sycl_buffer_interface ,ctx ,size ); 1002} 1003catch (sycl::exception const & exc ) { 1004 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 1005 <<", line:" <<__LINE__ << std::endl ; 1006 std::exit (1 ); 1007} 1008 1009static size_t ggml_backend_sycl_buffer_type_get_alignment (ggml_backend_buffer_type_t buft ) { 1010return SYCL_BUFFER_ALIGNMENT ; 1011GGML_UNUSED (buft ); 1012} 1013 1014static size_t ggml_backend_sycl_buffer_type_get_max_size (ggml_backend_buffer_type_t buft ) { 1015size_t max_alloc_size = dpct::get_current_device ().get_max_mem_alloc_size (); 1016if (g_ggml_sycl_host_pinned_mem_2g ) { 1017return std::min (max_alloc_size , (size_t )2LL * 1024 * 1024 * 1024 ); 1018 }else { 1019return max_alloc_size ; 1020 } 1021GGML_UNUSED (buft ); 1022} 1023 1024static size_t ggml_backend_sycl_buffer_type_get_alloc_size (ggml_backend_buffer_type_t buft ,const ggml_tensor * tensor ) { 1025// Reserve the additional scratch so it's visible to the graph allocator 1026size_t size = tensor -> op == GGML_OP_FLASH_ATTN_EXT 1027 ?ggml_sycl_flash_attn_ext_get_alloc_size (tensor ) 1028 :ggml_nbytes (tensor ); 1029int64_t ne0 = tensor -> ne [0 ]; 1030 1031if (ggml_is_quantized (tensor -> type )) { 1032if (ne0 %MATRIX_ROW_PADDING != 0 ) { 1033size += ggml_row_size (tensor -> type ,MATRIX_ROW_PADDING - ne0 %MATRIX_ROW_PADDING ); 1034 } 1035 } 1036 1037return size ; 1038 1039GGML_UNUSED (buft ); 1040} 1041 1042static const ggml_backend_buffer_type_i ggml_backend_sycl_buffer_type_interface = { 1043/* .get_name = */ ggml_backend_sycl_buffer_type_get_name , 1044/* .alloc_buffer = */ ggml_backend_sycl_buffer_type_alloc_buffer , 1045/* .get_alignment = */ ggml_backend_sycl_buffer_type_get_alignment , 1046/* .get_max_size = */ ggml_backend_sycl_buffer_type_get_max_size , 1047/* .get_alloc_size = */ ggml_backend_sycl_buffer_type_get_alloc_size , 1048/* .is_host = */ NULL , 1049}; 1050 1051ggml_backend_buffer_type_t ggml_backend_sycl_buffer_type (int device ) { 1052static std::mutex mutex ; 1053 std::lock_guard < std::mutex > lock (mutex ); 1054 1055 1056auto dev_count = ggml_backend_sycl_get_device_count (); 1057 1058if (device >=dev_count ordevice < 0 ) { 1059GGML_LOG_ERROR ("ggml_backend_sycl_buffer_type error: device_index:%d is out of range [0, %d], miss to call ggml_backend_sycl_set_single_device()\n" , 1060device ,dev_count - 1 ); 1061GGML_ASSERT (device < dev_count ); 1062 } 1063static struct ggml_backend_buffer_type ggml_backend_sycl_buffer_types [GGML_SYCL_MAX_DEVICES ]; 1064 1065static bool ggml_backend_sycl_buffer_type_initialized = false; 1066 1067if (!ggml_backend_sycl_buffer_type_initialized ) { 1068for (int i = 0 ;i < dev_count ;i ++ ) { 1069auto & device_i = dpct::dev_mgr::instance ().get_device (i ); 1070queue_ptr stream = & (device_i .default_queue ()); 1071ggml_backend_sycl_buffer_types [i ]= { 1072/* .iface = */ ggml_backend_sycl_buffer_type_interface , 1073/* .device = */ ggml_backend_reg_dev_get (ggml_backend_sycl_reg (),i ), 1074/* .context = */ new ggml_backend_sycl_buffer_type_context {i ,GGML_SYCL_NAME + std::to_string (i ),stream }, 1075 }; 1076 } 1077ggml_backend_sycl_buffer_type_initialized = true; 1078 } 1079return & ggml_backend_sycl_buffer_types [device ]; 1080} 1081 1082static ggml_backend_buffer_type_t ggml_backend_sycl_buffer_type (ggml_backend_sycl_context * ctx ) { 1083GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_buffer_type\n" ); 1084 1085int device = ctx -> device ; 1086if (device >=ggml_sycl_info ().device_count ordevice < 0 ) { 1087GGML_LOG_ERROR ("ggml_backend_sycl_buffer_type error: device_index:%d is out of range [0, %d], miss to call ggml_backend_sycl_set_single_device()\n" , 1088device ,ggml_sycl_info ().device_count - 1 ); 1089GGML_ASSERT (device < ggml_sycl_info ().device_count ); 1090 } 1091static struct ggml_backend_buffer_type ggml_backend_sycl_buffer_types [GGML_SYCL_MAX_DEVICES ]; 1092 1093static bool ggml_backend_sycl_buffer_type_initialized = false; 1094 1095if (!ggml_backend_sycl_buffer_type_initialized ) { 1096for (int i = 0 ;i < ggml_sycl_info ().device_count ;i ++ ) { 1097ggml_backend_sycl_buffer_types [i ]= { 1098/* .iface = */ ggml_backend_sycl_buffer_type_interface , 1099/* .device = */ nullptr , 1100/* .context = */ new ggml_backend_sycl_buffer_type_context {i ,GGML_SYCL_NAME + std::to_string (i ),ctx -> stream (i ,0 )}, 1101 }; 1102 } 1103ggml_backend_sycl_buffer_type_initialized = true; 1104 } 1105return & ggml_backend_sycl_buffer_types [device ]; 1106} 1107 1108// sycl split buffer 1109 1110static int64_t get_row_rounding (ggml_type type ,const std::array < float ,GGML_SYCL_MAX_DEVICES > & tensor_split ) { 1111int64_t min_compute_capability = INT_MAX ; 1112int64_t max_compute_capability = INT_MIN ; 1113for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1114if (tensor_split [i ]< (i + 1 < ggml_sycl_info ().device_count ?tensor_split [i + 1 ] :1.0f )) { 1115if (min_compute_capability > ggml_sycl_info ().devices [i ].cc ) { 1116min_compute_capability = ggml_sycl_info ().devices [i ].cc ; 1117 } 1118if (max_compute_capability < ggml_sycl_info ().devices [i ].cc ) { 1119max_compute_capability = ggml_sycl_info ().devices [i ].cc ; 1120 } 1121 } 1122 } 1123 1124switch (type ) { 1125case GGML_TYPE_Q1_0 : 1126case GGML_TYPE_Q4_0 : 1127case GGML_TYPE_Q4_1 : 1128return max_compute_capability >=VER_GEN9 ?128 :64 ; 1129case GGML_TYPE_Q5_0 : 1130case GGML_TYPE_Q5_1 : 1131case GGML_TYPE_Q8_0 : 1132return 64 ; 1133case GGML_TYPE_F16 : 1134case GGML_TYPE_F32 : 1135return 1 ; 1136case GGML_TYPE_Q2_K : 1137case GGML_TYPE_Q3_K : 1138case GGML_TYPE_Q4_K : 1139case GGML_TYPE_Q5_K : 1140case GGML_TYPE_IQ2_XXS : 1141case GGML_TYPE_IQ2_XS : 1142case GGML_TYPE_IQ2_S : 1143case GGML_TYPE_IQ1_S : 1144case GGML_TYPE_IQ1_M : 1145case GGML_TYPE_IQ3_XXS : 1146case GGML_TYPE_IQ4_XS : 1147case GGML_TYPE_IQ4_NL : 1148return max_compute_capability >=VER_GEN9 ?128 :64 ; 1149case GGML_TYPE_IQ3_S : 1150return max_compute_capability >=VER_GEN9 ?128 :64 ; 1151case GGML_TYPE_Q6_K : 1152return 64 ; 1153default : 1154GGML_ABORT ("fatal error" ); 1155 } 1156} 1157 1158static void get_row_split (int64_t * row_low ,int64_t * row_high ,const ggml_tensor * tensor ,const std::array < float ,GGML_SYCL_MAX_DEVICES > & tensor_split ,int id ) { 1159const int64_t nrows = ggml_nrows (tensor ); 1160const int64_t rounding = get_row_rounding (tensor -> type ,tensor_split ); 1161 1162* row_low = id == 0 ?0 :nrows * tensor_split [id ]; 1163* row_low -= * row_low %rounding ; 1164if (id == ggml_sycl_info ().device_count - 1 ) { 1165* row_high = nrows ; 1166 }else { 1167* row_high = nrows * tensor_split [id + 1 ]; 1168* row_high -= * row_high %rounding ; 1169 } 1170} 1171 1172static size_t ggml_nbytes_split (const struct ggml_tensor * tensor ,int nrows_split ) { 1173 static_assert(GGML_MAX_DIMS == 4 ,"GGML_MAX_DIMS is not 4 - update this function" ); 1174 1175return nrows_split * ggml_row_size (tensor -> type ,tensor -> ne [0 ]); 1176} 1177 1178struct ggml_backend_sycl_split_buffer_type_context { 1179 std::array < float ,GGML_SYCL_MAX_DEVICES > tensor_split ; 1180}; 1181 1182struct ggml_backend_sycl_split_buffer_context { 1183 ~ggml_backend_sycl_split_buffer_context ()try { 1184for (ggml_tensor_extra_gpu * extra :tensor_extras ) { 1185release_extra_gpu (extra ,streams ); 1186 } 1187 } 1188catch (sycl::exception const & exc ) { 1189 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 1190 <<", line:" <<__LINE__ << std::endl ; 1191 std::exit (1 ); 1192 } 1193 1194 std::vector < ggml_tensor_extra_gpu *> tensor_extras ; 1195 std::vector < queue_ptr > streams ; 1196}; 1197 1198static void ggml_backend_sycl_split_buffer_free_buffer (ggml_backend_buffer_t buffer ) { 1199ggml_backend_sycl_split_buffer_context * ctx = (ggml_backend_sycl_split_buffer_context * )buffer -> context ; 1200delete ctx ; 1201} 1202 1203static void * ggml_backend_sycl_split_buffer_get_base (ggml_backend_buffer_t buffer ) { 1204// the pointers are stored in the tensor extras, this is just a dummy address and never dereferenced 1205return (void * )0x1000 ; 1206 1207GGML_UNUSED (buffer ); 1208} 1209 1210static enum ggml_status 1211ggml_backend_sycl_split_buffer_init_tensor (ggml_backend_buffer_t buffer , 1212ggml_tensor * tensor )try { 1213GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 1214GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ,"\n" ).c_str ()); 1215GGML_ASSERT (tensor -> view_src == nullptr );// views of split tensors are not supported 1216 1217ggml_backend_sycl_split_buffer_context * ctx = (ggml_backend_sycl_split_buffer_context * )buffer -> context ; 1218ggml_backend_sycl_split_buffer_type_context * buft_ctx = (ggml_backend_sycl_split_buffer_type_context * )buffer -> buft -> context ; 1219 1220const int64_t ne0 = tensor -> ne [0 ]; 1221 1222ggml_tensor_extra_gpu * extra = new ggml_tensor_extra_gpu {}; 1223 1224ctx -> tensor_extras .push_back (extra ); 1225ctx -> streams .push_back (& (dpct::get_current_device ().default_queue ())); 1226 1227for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1228int64_t row_low ,row_high ; 1229get_row_split (& row_low ,& row_high ,tensor ,buft_ctx -> tensor_split ,i ); 1230 1231int64_t nrows_split = row_high - row_low ; 1232if (nrows_split == 0 ) { 1233continue ; 1234 } 1235 1236size_t size = ggml_nbytes_split (tensor ,nrows_split ); 1237const size_t original_size = size ; 1238 1239// pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses 1240if (ne0 %MATRIX_ROW_PADDING != 0 ) { 1241size += ggml_row_size (tensor -> type ,MATRIX_ROW_PADDING - ne0 %MATRIX_ROW_PADDING ); 1242 } 1243 1244ggml_sycl_set_device (i ); 1245const queue_ptr stream = ctx -> streams [i ]; 1246char * buf ; 1247SYCL_CHECK (CHECK_TRY_ERROR (buf = (char * )ggml_sycl_malloc_device (size ,* stream ,GGML_SYCL_MEM_BUFFER ))); 1248if (!buf ) { 1249char err_buf [1024 ]; 1250snprintf (err_buf ,1023 ,"%s: can't allocate %zu Bytes of memory on device\n" ,__func__ ,size ); 1251throw std::runtime_error (err_buf ); 1252 } 1253// set padding to 0 to avoid possible NaN values 1254if (size > original_size ) { 1255/* 1256DPCT1009:209: SYCL uses exceptions to report errors and does not use 1257the error codes. The original code was commented out and a warning 1258string was inserted. You need to rewrite this code. 1259*/ 1260SYCL_CHECK (CHECK_TRY_ERROR ( 1261 (* stream ) 1262 .memset (buf + original_size ,0 ,size - original_size ) 1263 .wait ())); 1264 } 1265 1266extra -> data_device [i ]= buf ; 1267 1268for (int64_t is = 0 ;is < GGML_SYCL_MAX_STREAMS ;++ is ) { 1269/* 1270DPCT1009:210: SYCL uses exceptions to report errors and does not use 1271the error codes. The original code was commented out and a warning 1272string was inserted. You need to rewrite this code. 1273*/ 1274SYCL_CHECK ( 1275CHECK_TRY_ERROR (extra -> events [i ][is ]= new sycl::event ())); 1276 } 1277 } 1278tensor -> extra = extra ; 1279return GGML_STATUS_SUCCESS ; 1280} 1281catch (sycl::exception const & exc ) { 1282 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 1283 <<", line:" <<__LINE__ << std::endl ; 1284 std::exit (1 ); 1285} 1286 1287static void 1288ggml_backend_sycl_split_buffer_set_tensor (ggml_backend_buffer_t buffer , 1289ggml_tensor * tensor ,const void * data , 1290size_t offset ,size_t size )try { 1291GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 1292GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 1293GGML_SYCL_DEBUG (" size=%zu offset=%zu\n" ,size ,offset ); 1294// split tensors must always be set in their entirety at once 1295GGML_ASSERT (offset == 0 ); 1296GGML_ASSERT (size == ggml_nbytes (tensor )); 1297 1298ggml_backend_sycl_split_buffer_context * ctx = (ggml_backend_sycl_split_buffer_context * )buffer -> context ; 1299ggml_backend_sycl_split_buffer_type_context * buft_ctx = (ggml_backend_sycl_split_buffer_type_context * )buffer -> buft -> context ; 1300 1301const int64_t ne0 = tensor -> ne [0 ]; 1302const size_t nb1 = tensor -> nb [1 ]; 1303ggml_tensor_extra_gpu * extra = (ggml_tensor_extra_gpu * )tensor -> extra ; 1304 1305for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1306int64_t row_low ,row_high ; 1307get_row_split (& row_low ,& row_high ,tensor ,buft_ctx -> tensor_split ,i ); 1308 1309int64_t nrows_split = row_high - row_low ; 1310if (nrows_split == 0 ) { 1311continue ; 1312 } 1313 1314const size_t offset_split = row_low * nb1 ; 1315size_t size = ggml_nbytes_split (tensor ,nrows_split ); 1316const size_t original_size = size ; 1317 1318// pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses 1319if (ne0 %MATRIX_ROW_PADDING != 0 ) { 1320size += ggml_row_size (tensor -> type ,MATRIX_ROW_PADDING - ne0 %MATRIX_ROW_PADDING ); 1321 } 1322 1323const char * buf_host = (const char * )data + offset_split ; 1324/* 1325DPCT1009:211: SYCL uses exceptions to report errors and does not use the 1326error codes. The original code was commented out and a warning string 1327was inserted. You need to rewrite this code. 1328*/ 1329ggml_sycl_set_device (i ); 1330const queue_ptr stream = ctx -> streams [i ]; 1331SYCL_CHECK (CHECK_TRY_ERROR ( 1332 (* stream ) 1333 .memcpy (extra -> data_device [i ],buf_host ,original_size ) 1334 .wait ())); 1335 } 1336} 1337catch (sycl::exception const & exc ) { 1338 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 1339 <<", line:" <<__LINE__ << std::endl ; 1340 std::exit (1 ); 1341} 1342 1343static void 1344ggml_backend_sycl_split_buffer_get_tensor (ggml_backend_buffer_t buffer , 1345const ggml_tensor * tensor ,void * data , 1346size_t offset ,size_t size )try { 1347GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 1348GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 1349GGML_SYCL_DEBUG (" size=%zu offset=%zu\n" ,size ,offset ); 1350// split tensors must always be set in their entirety at once 1351GGML_ASSERT (offset == 0 ); 1352GGML_ASSERT (size == ggml_nbytes (tensor )); 1353 1354ggml_backend_sycl_split_buffer_context * ctx = (ggml_backend_sycl_split_buffer_context * )buffer -> context ; 1355ggml_backend_sycl_split_buffer_type_context * buft_ctx = (ggml_backend_sycl_split_buffer_type_context * )buffer -> buft -> context ; 1356 1357const int64_t ne0 = tensor -> ne [0 ]; 1358const size_t nb1 = tensor -> nb [1 ]; 1359ggml_tensor_extra_gpu * extra = (ggml_tensor_extra_gpu * )tensor -> extra ; 1360 1361for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1362int64_t row_low ,row_high ; 1363get_row_split (& row_low ,& row_high ,tensor ,buft_ctx -> tensor_split ,i ); 1364 1365int64_t nrows_split = row_high - row_low ; 1366if (nrows_split == 0 ) { 1367continue ; 1368 } 1369 1370const size_t offset_split = row_low * nb1 ; 1371size_t size = ggml_nbytes_split (tensor ,nrows_split ); 1372const size_t original_size = size ; 1373 1374// pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses 1375if (ne0 %MATRIX_ROW_PADDING != 0 ) { 1376size += ggml_row_size (tensor -> type ,MATRIX_ROW_PADDING - ne0 %MATRIX_ROW_PADDING ); 1377 } 1378 1379char * buf_host = (char * )data + offset_split ; 1380/* 1381DPCT1009:212: SYCL uses exceptions to report errors and does not use the 1382error codes. The original code was commented out and a warning string 1383was inserted. You need to rewrite this code. 1384*/ 1385ggml_sycl_set_device (i ); 1386const queue_ptr stream = ctx -> streams [i ]; 1387SYCL_CHECK (CHECK_TRY_ERROR ( 1388 (* stream ) 1389 .memcpy (buf_host ,extra -> data_device [i ],original_size ) 1390 .wait ())); 1391 } 1392} 1393catch (sycl::exception const & exc ) { 1394 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 1395 <<", line:" <<__LINE__ << std::endl ; 1396 std::exit (1 ); 1397} 1398 1399static void ggml_backend_sycl_split_buffer_clear (ggml_backend_buffer_t buffer ,uint8_t value ) { 1400GGML_UNUSED (buffer ); 1401GGML_UNUSED (value ); 1402} 1403 1404static struct ggml_backend_buffer_i ggml_backend_sycl_split_buffer_interface = { 1405/* .free_buffer = */ ggml_backend_sycl_split_buffer_free_buffer , 1406/* .get_base = */ ggml_backend_sycl_split_buffer_get_base , 1407/* .init_tensor = */ ggml_backend_sycl_split_buffer_init_tensor , 1408/* .memset_tensor = */ NULL , 1409/* .set_tensor = */ ggml_backend_sycl_split_buffer_set_tensor , 1410/* .get_tensor = */ ggml_backend_sycl_split_buffer_get_tensor , 1411/* .set_tensor_2d = */ NULL , 1412/* .get_tensor_2d = */ NULL , 1413/* .cpy_tensor = */ NULL , 1414/* .clear = */ ggml_backend_sycl_split_buffer_clear , 1415/* .reset = */ NULL , 1416}; 1417 1418// sycl split buffer type 1419 1420static const char * ggml_backend_sycl_split_buffer_type_get_name (ggml_backend_buffer_type_t buft ) { 1421return GGML_SYCL_NAME "_Split" ; 1422 1423GGML_UNUSED (buft ); 1424} 1425 1426static bool ggml_backend_buffer_is_sycl_split (ggml_backend_buffer_t buffer ) { 1427return buffer -> buft -> iface .get_name == ggml_backend_sycl_split_buffer_type_get_name ; 1428} 1429 1430static ggml_backend_buffer_t ggml_backend_sycl_split_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft ,size_t size ) { 1431// since we don't know the exact split after rounding, we cannot allocate the device buffers at this point 1432// instead, we allocate them for each tensor separately in init_tensor 1433// however, the size still represents the maximum cumulative size of all the device buffers after the tensors are allocated, 1434// as returned by get_alloc_size. this limit is enforced during tensor allocation by ggml-alloc, so it must be correct. 1435ggml_backend_sycl_split_buffer_context * ctx = new ggml_backend_sycl_split_buffer_context (); 1436 1437return ggml_backend_buffer_init (buft ,ggml_backend_sycl_split_buffer_interface ,ctx ,size ); 1438} 1439 1440static size_t ggml_backend_sycl_split_buffer_type_get_alignment (ggml_backend_buffer_type_t buft ) { 1441return SYCL_BUFFER_ALIGNMENT ; 1442GGML_UNUSED (buft ); 1443} 1444 1445static size_t ggml_backend_sycl_split_buffer_type_get_alloc_size (ggml_backend_buffer_type_t buft ,const ggml_tensor * tensor ) { 1446ggml_backend_sycl_split_buffer_type_context * ctx = (ggml_backend_sycl_split_buffer_type_context * )buft -> context ; 1447 1448size_t total_size = 0 ; 1449 1450const int64_t ne0 = tensor -> ne [0 ]; 1451 1452for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1453int64_t row_low ,row_high ; 1454get_row_split (& row_low ,& row_high ,tensor ,ctx -> tensor_split ,i ); 1455 1456int64_t nrows_split = row_high - row_low ; 1457if (nrows_split == 0 ) { 1458continue ; 1459 } 1460 1461total_size += ggml_nbytes_split (tensor ,nrows_split ); 1462 1463// pad last row to a multiple of 512 elements to avoid out-of-bounds memory accesses 1464if (ne0 %MATRIX_ROW_PADDING != 0 ) { 1465total_size += ggml_row_size (tensor -> type ,MATRIX_ROW_PADDING - ne0 %MATRIX_ROW_PADDING ); 1466 } 1467 } 1468 1469return total_size ; 1470} 1471 1472static bool ggml_backend_sycl_split_buffer_type_is_host (ggml_backend_buffer_type_t buft ) { 1473return false; 1474 1475GGML_UNUSED (buft ); 1476} 1477 1478static ggml_backend_buffer_type_i ggml_backend_sycl_split_buffer_type_interface = { 1479/* .get_name = */ ggml_backend_sycl_split_buffer_type_get_name , 1480/* .alloc_buffer = */ ggml_backend_sycl_split_buffer_type_alloc_buffer , 1481/* .get_alignment = */ ggml_backend_sycl_split_buffer_type_get_alignment , 1482/* .get_max_size = */ NULL ,// defaults to SIZE_MAX 1483/* .get_alloc_size = */ ggml_backend_sycl_split_buffer_type_get_alloc_size , 1484/* .is_host = */ ggml_backend_sycl_split_buffer_type_is_host , 1485}; 1486 1487ggml_backend_buffer_type_t ggml_backend_sycl_split_buffer_type (const float * tensor_split ) { 1488GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_split_buffer_type\n" ); 1489 1490static std::mutex mutex ; 1491 std::lock_guard < std::mutex > lock (mutex ); 1492 1493ggml_check_sycl (); 1494// FIXME: this is not thread safe 1495static std::map < std::array < float ,GGML_SYCL_MAX_DEVICES > ,struct ggml_backend_buffer_type > buft_map ; 1496 1497 std::array < float ,GGML_SYCL_MAX_DEVICES > tensor_split_arr = {}; 1498 1499bool all_zero = tensor_split == nullptr || std::all_of (tensor_split ,tensor_split + GGML_SYCL_MAX_DEVICES , [](float x ) {return x == 0.0f ; }); 1500if (all_zero ) { 1501tensor_split_arr = ggml_sycl_info ().default_tensor_split ; 1502 }else { 1503float split_sum = 0.0f ; 1504for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1505tensor_split_arr [i ]= split_sum ; 1506split_sum += tensor_split [i ]; 1507 } 1508for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 1509tensor_split_arr [i ] /=split_sum ; 1510 } 1511 } 1512 1513auto it = buft_map .find (tensor_split_arr ); 1514if (it != buft_map .end ()) { 1515return & it -> second ; 1516 } 1517 1518struct ggml_backend_buffer_type buft { 1519/* .iface = */ ggml_backend_sycl_split_buffer_type_interface , 1520/* .device = */ ggml_backend_reg_dev_get (ggml_backend_sycl_reg (),0 ), 1521/* .context = */ new ggml_backend_sycl_split_buffer_type_context {tensor_split_arr }, 1522 }; 1523 1524auto result = buft_map .emplace (tensor_split_arr ,buft ); 1525return & result .first -> second ; 1526} 1527 1528// host buffer type 1529 1530struct ggml_backend_sycl_device_context { 1531int device ; 1532 std::string name ; 1533 std::string description ; 1534int op_offload_min_batch_size ; 1535}; 1536 1537static const char * ggml_backend_sycl_host_buffer_type_name (ggml_backend_buffer_type_t buft ) { 1538return GGML_SYCL_NAME "_Host" ; 1539 1540GGML_UNUSED (buft ); 1541} 1542 1543//host pinned memory 1544static void * ggml_backend_sycl_host_malloc (size_t size ) { 1545GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_host_malloc\n" ); 1546void * ptr = nullptr ; 1547try { 1548ggml_check_sycl (); 1549// USM host memory is page-locked and device-accessible by construction 1550auto & q = dpct::dev_mgr::instance ().get_device (0 ).default_queue (); 1551ptr = sycl::malloc_host (size ,q , sycl::property_list {}); 1552 }catch (...) { 1553ptr = nullptr ; 1554 } 1555if (ptr == nullptr ) { 1556GGML_LOG_WARN ("%s: failed to allocate %.2f MiB of pinned memory\n" ,__func__ , 1557size /1024.0 /1024.0 ); 1558 } 1559 1560return ptr ; 1561} 1562 1563static void ggml_backend_sycl_host_buffer_free_buffer (ggml_backend_buffer_t buffer ) { 1564if (buffer -> context == nullptr ) { 1565return ; 1566 } 1567if (g_ggml_sycl_enable_host_pinned_mem ) { 1568auto & q = dpct::dev_mgr::instance ().get_device (0 ).default_queue (); 1569SYCL_CHECK (CHECK_TRY_ERROR (sycl::free (buffer -> context ,q ))); 1570 }else { 1571free_aligned_mem_host ((void * )buffer -> context ); 1572 } 1573} 1574 1575static ggml_backend_buffer_t ggml_backend_sycl_host_buffer_type_alloc_buffer (ggml_backend_buffer_type_t buft ,size_t size ) { 1576void * ptr = g_ggml_sycl_enable_host_pinned_mem ?ggml_backend_sycl_host_malloc (size ) : 1577aligned_malloc_host (TENSOR_ALIGNMENT ,size ); 1578if (ptr == nullptr ) { 1579// fallback to cpu buffer 1580return ggml_backend_buft_alloc_buffer (ggml_backend_cpu_buffer_type (),size ); 1581 } 1582 1583// FIXME: this is a hack to avoid having to implement a new buffer type 1584ggml_backend_buffer_t buffer = ggml_backend_cpu_buffer_from_ptr (ptr ,size ); 1585buffer -> buft = buft ; 1586buffer -> iface .free_buffer = ggml_backend_sycl_host_buffer_free_buffer ; 1587 1588return buffer ; 1589} 1590 1591static size_t ggml_backend_sycl_host_buffer_type_get_max_size (ggml_backend_buffer_type_t buft ) { 1592 1593if (g_ggml_sycl_enable_host_pinned_mem ) { 1594ggml_backend_sycl_device_context * dev_ctx = (ggml_backend_sycl_device_context * )buft -> device -> context ; 1595size_t max_alloc_size = dpct::dev_mgr::instance ().get_device (dev_ctx -> device ).get_max_mem_alloc_size (); 1596if (g_ggml_sycl_host_pinned_mem_2g ) { 1597return std::min (max_alloc_size , (size_t )2LL * 1024 * 1024 * 1024 ); 1598 }else { 1599return max_alloc_size ; 1600 } 1601 }else { 1602return SIZE_MAX ; 1603 } 1604} 1605 1606ggml_backend_buffer_type_t ggml_backend_sycl_host_buffer_type () { 1607GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_host_buffer_type\n" ); 1608static struct ggml_backend_buffer_type ggml_backend_sycl_buffer_type_host = { 1609/* .iface = */ { 1610/* .get_name = */ ggml_backend_sycl_host_buffer_type_name , 1611/* .alloc_buffer = */ ggml_backend_sycl_host_buffer_type_alloc_buffer , 1612/* .get_alignment = */ ggml_backend_cpu_buffer_type ()-> iface .get_alignment , 1613/* .get_max_size = */ ggml_backend_sycl_host_buffer_type_get_max_size , 1614/* .get_alloc_size = */ ggml_backend_cpu_buffer_type ()-> iface .get_alloc_size , 1615/* .is_host = */ ggml_backend_cpu_buffer_type ()-> iface .is_host , 1616 }, 1617/* .device = */ ggml_backend_reg_dev_get (ggml_backend_sycl_reg (),0 ), 1618/* .context = */ nullptr , 1619 }; 1620 1621return & ggml_backend_sycl_buffer_type_host ; 1622} 1623 1624// buffer pool for sycl (legacy) 1625struct ggml_sycl_pool_leg :public ggml_sycl_pool { 1626static const int MAX_SYCL_BUFFERS = 256 ; 1627 1628int device ; 1629queue_ptr qptr ; 1630struct ggml_sycl_buffer { 1631void * ptr = nullptr ; 1632size_t size = 0 ; 1633 }; 1634 1635ggml_sycl_buffer buffer_pool [MAX_SYCL_BUFFERS ]= {}; 1636size_t pool_size = 0 ; 1637 1638explicit ggml_sycl_pool_leg (queue_ptr qptr_ ,int device_ ) :device (device_ ),qptr (qptr_ ) {} 1639 1640 ~ggml_sycl_pool_leg () { 1641#ifdef DEBUG_SYCL_POOL 1642int n_cached = 0 ; 1643size_t bytes_cached = 0 ; 1644for (int i = 0 ;i < MAX_SYCL_BUFFERS ;++ i ) { 1645if (buffer_pool [i ].ptr != nullptr ) { 1646++ n_cached ; 1647bytes_cached += buffer_pool [i ].size ; 1648 } 1649 } 1650GGML_LOG_INFO ("%s: %d buffers, cached = %.2f MiB\n" ,__func__ , 1651n_cached ,bytes_cached /1024.0 /1024.0 ); 1652const auto slots = format_slots_in_alloc_order (); 1653if (!slots .empty ()) { 1654GGML_LOG_INFO ("%s: slots MiB: %s\n" ,__func__ ,slots .c_str ()); 1655 } 1656#endif 1657 1658for (int i = 0 ;i < MAX_SYCL_BUFFERS ;++ i ) { 1659ggml_sycl_buffer & b = buffer_pool [i ]; 1660if (b .ptr != nullptr ) { 1661SYCL_CHECK (CHECK_TRY_ERROR (ggml_sycl_free_device (b .ptr ,* qptr ))); 1662pool_size -= b .size ; 1663 } 1664 } 1665GGML_ASSERT (pool_size == 0 ); 1666 } 1667 1668#ifdef DEBUG_SYCL_POOL 1669 std::string format_slots_in_alloc_order ()const { 1670 std::string line ; 1671char buf [32 ]; 1672bool first = true; 1673for (int i = 0 ;i < MAX_SYCL_BUFFERS ;++ i ) { 1674if (buffer_pool [i ].ptr == nullptr ) { 1675continue ; 1676 } 1677if (!first ) { 1678line += '/' ; 1679 } 1680first = false; 1681snprintf (buf ,sizeof (buf ),"%.2f" ,buffer_pool [i ].size /1024.0 /1024.0 ); 1682line += buf ; 1683 } 1684return line ; 1685 } 1686#endif 1687 1688void * alloc (size_t size ,size_t * actual_size )override { 1689#ifdef DEBUG_sycl_MALLOC 1690int nnz = 0 ; 1691size_t max_size = 0 ; 1692#endif 1693size_t best_diff = 1ull <<36 ; 1694int ibest = -1 ; 1695for (int i = 0 ;i < MAX_SYCL_BUFFERS ;++ i ) { 1696ggml_sycl_buffer & b = buffer_pool [i ]; 1697if (b .ptr != nullptr ) { 1698#ifdef DEBUG_sycl_MALLOC 1699++ nnz ; 1700if (b .size > max_size )max_size = b .size ; 1701#endif 1702if (b .size >=size ) { 1703size_t diff = b .size - size ; 1704if (diff < best_diff ) { 1705best_diff = diff ; 1706ibest = i ; 1707if (!best_diff ) { 1708void * ptr = b .ptr ; 1709* actual_size = b .size ; 1710b .ptr = nullptr ; 1711b .size = 0 ; 1712return ptr ; 1713 } 1714 } 1715 } 1716 } 1717 } 1718if (ibest >=0 ) { 1719ggml_sycl_buffer & b = buffer_pool [ibest ]; 1720void * ptr = b .ptr ; 1721* actual_size = b .size ; 1722b .ptr = nullptr ; 1723b .size = 0 ; 1724return ptr ; 1725 } 1726void * ptr ; 1727size_t look_ahead_size = (size_t ) (1.05 * size ); 1728 1729SYCL_CHECK (CHECK_TRY_ERROR (ptr = (void * )ggml_sycl_malloc_device (look_ahead_size ,* qptr ,GGML_SYCL_MEM_POOL_LEG ))); 1730if (!ptr ) { 1731GGML_LOG_ERROR ("%s: can't allocate %zu Bytes of memory on device/GPU\n" ,__func__ ,look_ahead_size ); 1732return nullptr ; 1733 } 1734 1735* actual_size = look_ahead_size ; 1736pool_size += look_ahead_size ; 1737 1738#ifdef DEBUG_SYCL_MALLOC 1739GGML_LOG_DEBUG ("%s[%d]: %d buffers, max_size = %u MB, pool_size = %u MB, requested %u MB\n" ,__func__ ,id ,nnz , 1740 (uint32_t )(max_size /1024 /1024 ), (uint32_t )(g_sycl_pool_size [id ]/1024 /1024 ), (uint32_t )(size /1024 /1024 )); 1741#endif 1742 1743// GGML_SYCL_DEBUG("ggml_sycl_pool_malloc_leg look_ahead_size=%zu, return %p\n", look_ahead_size, ptr); 1744return ptr ; 1745 } 1746 1747void free (void * ptr ,size_t size )override { 1748for (int i = 0 ;i < MAX_SYCL_BUFFERS ;++ i ) { 1749ggml_sycl_buffer & b = buffer_pool [i ]; 1750if (b .ptr == nullptr ) { 1751b .ptr = ptr ; 1752b .size = size ; 1753return ; 1754 } 1755 } 1756GGML_LOG_WARN ("WARNING: sycl buffer pool full, increase MAX_sycl_BUFFERS\n" ); 1757SYCL_CHECK (CHECK_TRY_ERROR (ggml_sycl_free_device (ptr ,* qptr ))); 1758pool_size -= size ; 1759 } 1760}; 1761 1762// pool with virtual memory management 1763#if defined(GGML_SYCL_SUPPORT_VMM ) 1764struct ggml_sycl_pool_vmm :public ggml_sycl_pool { 1765static const size_t SYCL_POOL_VMM_MAX_SIZE = 1ull <<35 ;// 32 GB 1766 1767int device ; 1768 sycl::context ctx ; 1769 sycl::device dev ; 1770 1771uintptr_t pool_addr = 0 ; 1772size_t pool_used = 0 ; 1773size_t pool_size = 0 ; 1774size_t granularity ; 1775 1776// physical_mem owns the commits (unlike cuMemMap) 1777struct mapping { 1778 sycl::ext::oneapi::experimental::physical_mem phys ; 1779void * map_ptr ; 1780 }; 1781 std::vector < mapping > mappings ; 1782 1783explicit ggml_sycl_pool_vmm (queue_ptr qptr_ ,int device_ ) : 1784device (device_ ), 1785ctx (qptr_ -> get_context ()), 1786dev (qptr_ -> get_device ()), 1787granularity (ggml_sycl_info ().devices [device_ ].vmm_granularity ) { 1788 } 1789 1790 ~ggml_sycl_pool_vmm () { 1791if (pool_addr == 0 ) { 1792return ; 1793 } 1794 1795// Per spec, unmap must (a) match the exact (ptr, size) of an earlier 1796// physical_mem::map() call and (b) precede destruction of the 1797// physical_mem objects (their dtors won't unmap). 1798for (auto & m :mappings ) { 1799SYCL_CHECK (CHECK_TRY_ERROR (sycl::ext::oneapi::experimental::unmap ( 1800m .map_ptr ,m .phys .size (),ctx ))); 1801 } 1802SYCL_CHECK (CHECK_TRY_ERROR (sycl::ext::oneapi::experimental::free_virtual_mem ( 1803pool_addr ,SYCL_POOL_VMM_MAX_SIZE ,ctx ))); 1804 } 1805 1806void * alloc (size_t size ,size_t * actual_size )override { 1807// round up the allocation size to the alignment to ensure that all allocations are aligned for all data types 1808size = GGML_PAD (size ,SYCL_BUFFER_ALIGNMENT ); 1809 1810size_t avail = pool_size - pool_used ; 1811 1812if (size > avail ) { 1813// round up to the next multiple of the granularity 1814size_t reserve_size = GGML_PAD (size - avail ,granularity ); 1815 1816GGML_ASSERT (pool_size + reserve_size <=SYCL_POOL_VMM_MAX_SIZE ); 1817 1818if (ggml_sycl_memtrace_enabled ()) { 1819GGML_LOG_INFO (GGML_SYCL_MEMTRACE_TAG " pool_vmm[%d] committing %5zu MiB (pool %5zu -> %5zu MiB)\n" , 1820device ,reserve_size / (1024 * 1024 ),pool_size / (1024 * 1024 ), 1821 (pool_size + reserve_size ) / (1024 * 1024 )); 1822ggml_sycl_memtrace_report ("before pool_vmm commit" ); 1823 } 1824 1825// allocate more physical memory 1826 std::optional < sycl::ext::oneapi::experimental::physical_mem > phys ; 1827SYCL_CHECK (CHECK_TRY_ERROR (phys .emplace (dev ,ctx ,reserve_size ))); 1828 1829// reserve virtual address space (if not already reserved) 1830if (pool_addr == 0 ) { 1831SYCL_CHECK (CHECK_TRY_ERROR ( 1832pool_addr = sycl::ext::oneapi::experimental::reserve_virtual_mem ( 1833SYCL_POOL_VMM_MAX_SIZE ,ctx ))); 1834 } 1835 1836// map at the end of the pool 1837void * map_ptr = nullptr ; 1838SYCL_CHECK (CHECK_TRY_ERROR ( 1839map_ptr = phys -> map (pool_addr + pool_size ,reserve_size , 1840 sycl::ext::oneapi::experimental::address_access_mode::read_write ))); 1841 1842// stash these so we could unmap this exact range in dtor 1843mappings .push_back ({ 1844 std::move (* phys ), 1845map_ptr , 1846 }); 1847 1848// add to the pool 1849pool_size += reserve_size ; 1850ggml_sycl_memtrace_add (GGML_SYCL_MEM_POOL_VMM ,map_ptr ,reserve_size ); 1851 1852#ifdef DEBUG_SYCL_MALLOC 1853GGML_LOG_INFO ("sycl pool[%d]: size increased to %llu MB (reserved %llu MB)\n" , 1854device , (unsigned long long ) (pool_size /1024 /1024 ), 1855 (unsigned long long ) (reserve_size /1024 /1024 )); 1856#endif 1857 } 1858 1859GGML_ASSERT (pool_addr != 0 ); 1860 1861void * ptr = reinterpret_cast < void *> (pool_addr + pool_used ); 1862* actual_size = size ; 1863pool_used += size ; 1864 1865#ifdef DEBUG_SYCL_MALLOC 1866GGML_LOG_INFO ("sycl pool[%d]: allocated %llu bytes at %p\n" ,device , (unsigned long long )size ,ptr ); 1867#endif 1868 1869return ptr ; 1870 } 1871 1872void free (void * ptr ,size_t size )override { 1873#ifdef DEBUG_SYCL_MALLOC 1874GGML_LOG_INFO ("sycl pool[%d]: freed %llu bytes at %p\n" ,device , (unsigned long long )size ,ptr ); 1875#endif 1876 1877pool_used -= size ; 1878 1879// all deallocations must be in reverse order of the allocations 1880GGML_ASSERT (ptr == reinterpret_cast < void *> (pool_addr + pool_used )); 1881 } 1882}; 1883#endif // defined(GGML_SYCL_SUPPORT_VMM) 1884 1885struct ggml_sycl_pool_host :public ggml_sycl_pool { 1886queue_ptr qptr ; 1887int device ; 1888 1889inline static int counter {0 }; 1890 1891struct ggml_sycl_buffer { 1892void * ptr = nullptr ; 1893size_t size = 0 ; 1894 }; 1895 1896// Set arbitrarly to 64 1897static constexpr int MAX_POOL_SIZE {64 }; 1898 std::vector < ggml_sycl_buffer > buffer_pool = std::vector < ggml_sycl_buffer > (MAX_POOL_SIZE ); 1899size_t pool_size = 0 ; 1900 1901explicit ggml_sycl_pool_host (queue_ptr qptr_ ,int device_ ) :qptr (qptr_ ),device (device_ ) {} 1902 1903 ~ggml_sycl_pool_host () { 1904for (int i = 0 ;i < MAX_POOL_SIZE ;++ i ) { 1905ggml_sycl_buffer & b = buffer_pool [i ]; 1906if (b .ptr != nullptr ) { 1907SYCL_CHECK (CHECK_TRY_ERROR (sycl::free (b .ptr ,* qptr ))); 1908b .ptr = nullptr ; 1909pool_size -= b .size ; 1910b .size = 0 ; 1911 } 1912 } 1913counter = 0 ; 1914 } 1915 1916void * alloc (size_t size ,size_t * actual_size )override { 1917if (counter == MAX_POOL_SIZE ) { 1918ggml_sycl_buffer b = buffer_pool [0 ]; 1919void * ptr = b .ptr ; 1920* actual_size = b .size ; 1921counter = 1 ; 1922return ptr ; 1923 } 1924ggml_sycl_buffer & b = buffer_pool [counter ]; 1925 1926if (b .ptr == nullptr ) { 1927void * ptr ; 1928 1929SYCL_CHECK (CHECK_TRY_ERROR (ptr = (void * ) sycl::malloc_host (size ,* qptr ))); 1930if (!ptr ) { 1931GGML_LOG_ERROR ("%s: can't allocate %zu Bytes of memory on host\n" ,__func__ ,size ); 1932return nullptr ; 1933 } 1934pool_size += size ; 1935* actual_size = size ; 1936counter = counter + 1 ; 1937return ptr ; 1938 }else { 1939++ counter ; 1940b .size = size ; 1941return b .ptr ; 1942 } 1943 } 1944 1945void free (void * ptr ,size_t size )override { 1946// if the pool is not completed add the pointer to it in place of the first nullptr found. 1947// Otherwise do nothing, pointers will be freed once the pool is deallocated. 1948for (int i = 0 ;i < MAX_POOL_SIZE ;++ i ) { 1949ggml_sycl_buffer & b = buffer_pool [i ]; 1950if (b .ptr == nullptr ) { 1951b .ptr = ptr ; 1952b .size = size ; 1953return ; 1954 } 1955 } 1956 } 1957}; 1958 1959std::unique_ptr < ggml_sycl_pool > ggml_backend_sycl_context::new_pool_for_host (queue_ptr qptr ,int device ) { 1960// return pool for the host to speed up memory management 1961return std::unique_ptr < ggml_sycl_pool > (new ggml_sycl_pool_host (qptr ,device )); 1962} 1963 1964std::unique_ptr < ggml_sycl_pool > ggml_backend_sycl_context::new_pool_for_device (queue_ptr qptr ,int device ) { 1965#if defined(GGML_SYCL_SUPPORT_VMM ) 1966if (g_ggml_sycl_enable_vmm && ggml_sycl_info ().devices [device ].vmm ) { 1967return std::unique_ptr < ggml_sycl_pool > (new ggml_sycl_pool_vmm (qptr ,device )); 1968 } 1969#endif // defined(GGML_SYCL_SUPPORT_VMM) 1970return std::unique_ptr < ggml_sycl_pool > (new ggml_sycl_pool_leg (qptr ,device )); 1971} 1972 1973 1974std::unique_ptr < ggml_sycl_fattn_kv_buffers > ggml_backend_sycl_context::new_fattn_kv_buffers (queue_ptr qptr ,int device ) { 1975return std::unique_ptr < ggml_sycl_fattn_kv_buffers > (new ggml_sycl_fattn_kv_buffers (qptr ,device )); 1976} 1977 1978/// kernels 1979typedef void (* ggml_sycl_op_mul_mat_t )( 1980ggml_backend_sycl_context & ctx , 1981const ggml_tensor * src0 ,const ggml_tensor * src1 ,ggml_tensor * dst , 1982const char * src0_dd_i ,const float * src1_ddf_i ,const char * src1_ddq_i , 1983float * dst_dd_i ,const int64_t row_low ,const int64_t row_high , 1984const int64_t src1_ncols ,const int64_t src1_padded_row_size , 1985const queue_ptr & stream ); 1986 1987 1988 1989static void mul_mat_p021_f16_f32 ( 1990const void * __restrict__vx ,const float * __restrict__y ,float * __restrict__dst , 1991const int ncols_x ,const int nrows_x ,const int nchannels_x ,const int nchannels_y , 1992const sycl::nd_item < 3 > & item_ct1 ) { 1993 1994const sycl::half * x = (const sycl::half * )vx ; 1995 1996const int row_x = item_ct1 .get_local_range (1 )* item_ct1 .get_group (1 )+ 1997item_ct1 .get_local_id (1 ); 1998const int channel = item_ct1 .get_local_range (0 )* item_ct1 .get_group (0 )+ 1999item_ct1 .get_local_id (0 ); 2000const int channel_x = channel / (nchannels_y /nchannels_x ); 2001 2002const int nrows_y = ncols_x ; 2003const int nrows_dst = nrows_x ; 2004const int row_dst = row_x ; 2005 2006float tmp = 0.0f ; 2007 2008for (int col_x0 = 0 ;col_x0 < ncols_x ; 2009col_x0 += item_ct1 .get_local_range (2 )) { 2010const int col_x = col_x0 + item_ct1 .get_local_id (2 ); 2011 2012if (col_x >=ncols_x ) { 2013break ; 2014 } 2015 2016// x is transposed and permuted 2017const int ix = row_x * nchannels_x * ncols_x + channel_x * ncols_x + col_x ; 2018const float xi = 2019 sycl::vec < sycl::half ,1 > (x [ix ]) 2020 .convert < float , sycl::rounding_mode::automatic > ()[0 ]; 2021 2022const int row_y = col_x ; 2023 2024 2025// y is not transposed but permuted 2026const int iy = channel * nrows_y + row_y ; 2027 2028tmp += xi * y [iy ]; 2029 } 2030 2031// dst is not transposed and not permuted 2032const int idst = channel * nrows_dst + row_dst ; 2033 2034// sum up partial sums and write back result 2035#pragma unroll 2036for (int mask = WARP_SIZE /2 ;mask > 0 ;mask >>=1 ) { 2037tmp += 2038 dpct::permute_sub_group_by_xor (item_ct1 .get_sub_group (),tmp ,mask ); 2039 } 2040 2041if (item_ct1 .get_local_id (2 )== 0 ) { 2042dst [idst ]= tmp ; 2043 } 2044} 2045 2046static void mul_mat_vec_nc_f16_f32 (// nc == non-contiguous 2047const void * __restrict__vx ,const float * __restrict__y ,float * __restrict__dst ,const int ncols_x ,const int nrows_x , 2048const int row_stride_x ,const int channel_stride_x ,const int channel_stride_y ,const int channel_x_divisor , 2049const sycl::nd_item < 3 > & item_ct1 ) { 2050 2051const sycl::half * x = (const sycl::half * )vx ; 2052 2053const int row_x = item_ct1 .get_local_range (1 )* item_ct1 .get_group (1 )+ 2054item_ct1 .get_local_id (1 ); 2055const int channel = item_ct1 .get_local_range (0 )* item_ct1 .get_group (0 )+ 2056item_ct1 .get_local_id (0 ); 2057const int channel_x = channel /channel_x_divisor ; 2058 2059const int nrows_dst = nrows_x ; 2060const int row_dst = row_x ; 2061 2062const int idst = channel * nrows_dst + row_dst ; 2063 2064float tmp = 0.0f ; 2065 2066for (int col_x0 = 0 ;col_x0 < ncols_x ; 2067col_x0 += item_ct1 .get_local_range (2 )) { 2068const int col_x = col_x0 + item_ct1 .get_local_id (2 ); 2069 2070if (col_x >=ncols_x ) { 2071break ; 2072 } 2073 2074const int row_y = col_x ; 2075 2076const int ix = channel_x * channel_stride_x + row_x * row_stride_x + col_x ; 2077const int iy = channel * channel_stride_y + row_y ; 2078 2079const float xi = 2080 sycl::vec < sycl::half ,1 > (x [ix ]) 2081 .convert < float , sycl::rounding_mode::automatic > ()[0 ]; 2082 2083tmp += xi * y [iy ]; 2084 } 2085 2086// sum up partial sums and write back result 2087#pragma unroll 2088for (int mask = WARP_SIZE /2 ;mask > 0 ;mask >>=1 ) { 2089tmp += 2090 dpct::permute_sub_group_by_xor (item_ct1 .get_sub_group (),tmp ,mask ); 2091 } 2092 2093if (item_ct1 .get_local_id (2 )== 0 ) { 2094dst [idst ]= tmp ; 2095 } 2096} 2097 2098static void k_sum_rows_f32 (const float * x ,float * dst ,const int ncols , 2099const sycl::nd_item < 3 > & item_ct1 ) { 2100const int row = item_ct1 .get_group (1 ); 2101const int col = item_ct1 .get_local_id (2 ); 2102 2103float sum = 0.0f ; 2104for (int i = col ;i < ncols ;i += item_ct1 .get_local_range (2 )) { 2105sum += x [row * ncols + i ]; 2106 } 2107 2108sum = warp_reduce_sum (sum ,item_ct1 ); 2109 2110if (col == 0 ) { 2111dst [row ]= sum ; 2112 } 2113} 2114 2115 2116template < typename T > 2117static inline void ggml_sycl_swap (T & a ,T & b ) { 2118T tmp = a ; 2119a = b ; 2120b = tmp ; 2121} 2122 2123template < ggml_sort_order order > 2124__dpct_inline__ static void 2125k_argsort_f32_i32 (const float * x ,int * dst ,const int ncols ,int ncols_pad , 2126const int tasks_per_thread ,const sycl::nd_item < 3 > & item_ct1 , 2127uint8_t * dpct_local ) { 2128// bitonic sort 2129int col_index = item_ct1 .get_local_id (2 ); 2130int row = item_ct1 .get_group (1 ); 2131 2132for (int i = 0 ;i < tasks_per_thread ;i ++ ) { 2133int col = col_index * tasks_per_thread + i ; 2134if (col >=ncols_pad ) { 2135return ; 2136 } 2137 } 2138 2139const float * x_row = x + row * ncols ; 2140auto dst_row = (int * )dpct_local ; 2141 2142// initialize indices 2143for (int i = 0 ;i < tasks_per_thread ;i ++ ){ 2144int col = col_index * tasks_per_thread + i ; 2145dst_row [col ]= col ; 2146 } 2147 2148item_ct1 .barrier (sycl::access::fence_space::local_space ); 2149 2150for (int k = 2 ;k <=ncols_pad ;k *=2 ) { 2151for (int j = k /2 ;j > 0 ;j /=2 ) { 2152for (int i = 0 ;i < tasks_per_thread ;i ++ ) { 2153int col = col_index * tasks_per_thread + i ; 2154int ixj = col ^j ; 2155if (ixj > col ) { 2156if ((col & k )== 0 ) { 2157if (dst_row [col ] >=ncols || 2158 (dst_row [ixj ]< ncols && 2159 (order == GGML_SORT_ORDER_ASC 2160 ?x_row [dst_row [col ]]> x_row [dst_row [ixj ]] 2161 :x_row [dst_row [col ]]< 2162x_row [dst_row [ixj ]]))) { 2163ggml_sycl_swap (dst_row [col ],dst_row [ixj ]); 2164 } 2165 }else { 2166if (dst_row [ixj ] >=ncols || 2167 (dst_row [col ]< ncols && 2168 (order == GGML_SORT_ORDER_ASC 2169 ?x_row [dst_row [col ]]< x_row [dst_row [ixj ]] 2170 :x_row [dst_row [col ]]> 2171x_row [dst_row [ixj ]]))) { 2172ggml_sycl_swap (dst_row [col ],dst_row [ixj ]); 2173 } 2174 } 2175 } 2176item_ct1 .barrier (sycl::access::fence_space::local_space ); 2177 } 2178 } 2179 } 2180 2181// copy the result to dst without the padding 2182for (int i = 0 ;i < tasks_per_thread ;i ++ ) { 2183int col = col_index * tasks_per_thread + i ; 2184if (col < ncols ) { 2185dst [row * ncols + col ]= dst_row [col ]; 2186 } 2187 } 2188} 2189 2190static void diag_mask_inf_f32 (const float * x ,float * dst ,const int ncols ,const int rows_per_channel ,const int n_past , 2191const sycl::nd_item < 3 > & item_ct1 ) { 2192const int col = item_ct1 .get_local_range (1 )* item_ct1 .get_group (1 )+ 2193item_ct1 .get_local_id (1 ); 2194const int row = item_ct1 .get_local_range (2 )* item_ct1 .get_group (2 )+ 2195item_ct1 .get_local_id (2 ); 2196 2197if (col >=ncols ) { 2198return ; 2199 } 2200 2201const int i = row * ncols + col ; 2202//dst[i] = col > (n_past + row % rows_per_channel) ? -INFINITY : x[i]; 2203//dst[i] = x[i] - (col > n_past + row % rows_per_channel) * INT_MAX; // equivalent within rounding error but slightly faster on GPU 2204dst [i ]= x [i ]- (col > n_past + row %rows_per_channel )* FLT_MAX ; 2205} 2206 2207static void scale_f32 (const float * x ,float * dst ,const float scale ,const float bias ,const int k , 2208const sycl::nd_item < 3 > & item_ct1 ) { 2209const int i = item_ct1 .get_local_range (2 )* item_ct1 .get_group (2 )+ 2210item_ct1 .get_local_id (2 ); 2211 2212if (i >=k ) { 2213return ; 2214 } 2215 2216dst [i ]= scale * x [i ]+ bias ; 2217} 2218 2219 2220static void ggml_mul_mat_p021_f16_f32_sycl (const void * vx ,const float * y , 2221float * dst ,const int ncols_x , 2222const int nrows_x , 2223const int nchannels_x , 2224const int nchannels_y , 2225queue_ptr stream ) { 2226 2227const sycl::range < 3 > block_nums (nchannels_y ,nrows_x ,1 ); 2228const sycl::range < 3 > block_dims (1 ,1 ,WARP_SIZE ); 2229 { 2230 dpct::has_capability_or_fail (stream -> get_device (), 2231 {sycl::aspect::fp16 }); 2232 2233stream -> parallel_for ( 2234 sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2235 [= ](sycl::nd_item < 3 > item_ct1 ) [[sycl ::reqd_sub_group_size (WARP_SIZE )]] { 2236mul_mat_p021_f16_f32 (vx ,y ,dst ,ncols_x ,nrows_x ,nchannels_x , 2237nchannels_y ,item_ct1 ); 2238 }); 2239 } 2240} 2241 2242static void ggml_mul_mat_vec_nc_f16_f32_sycl ( 2243const void * vx ,const float * y ,float * dst ,const int ncols_x , 2244const int nrows_x ,const int row_stride_x ,const int nchannels_x , 2245const int nchannels_y ,const int channel_stride_x ,const int channel_stride_y ,queue_ptr stream ) { 2246 2247const sycl::range < 3 > block_nums (nchannels_y ,nrows_x ,1 ); 2248const sycl::range < 3 > block_dims (1 ,1 ,WARP_SIZE ); 2249 { 2250 dpct::has_capability_or_fail (stream -> get_device (), 2251 {sycl::aspect::fp16 }); 2252 2253stream -> parallel_for ( 2254 sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2255 [= ](sycl::nd_item < 3 > item_ct1 ) [[sycl ::reqd_sub_group_size (WARP_SIZE )]] { 2256mul_mat_vec_nc_f16_f32 (vx ,y ,dst ,ncols_x ,nrows_x , 2257row_stride_x ,channel_stride_x ,channel_stride_y , 2258nchannels_y /nchannels_x ,item_ct1 ); 2259 }); 2260 } 2261} 2262 2263 2264 2265static void scale_f32_sycl (const float * x ,float * dst ,const float scale ,const float bias , 2266const int k ,queue_ptr stream ) { 2267const int num_blocks = (k + SYCL_SCALE_BLOCK_SIZE - 1 ) /SYCL_SCALE_BLOCK_SIZE ; 2268stream -> parallel_for ( 2269 sycl::nd_range < 3 > (sycl::range < 3 > (1 ,1 ,num_blocks )* 2270 sycl::range < 3 > (1 ,1 ,SYCL_SCALE_BLOCK_SIZE ), 2271 sycl::range < 3 > (1 ,1 ,SYCL_SCALE_BLOCK_SIZE )), 2272 [= ](sycl::nd_item < 3 > item_ct1 ) { 2273scale_f32 (x ,dst ,scale ,bias ,k ,item_ct1 ); 2274 }); 2275} 2276 2277 2278static void sum_rows_f32_sycl (const float * x ,float * dst ,const int ncols , 2279const int nrows ,queue_ptr stream ) { 2280const sycl::range < 3 > block_dims (1 ,1 ,WARP_SIZE ); 2281const sycl::range < 3 > block_nums (1 ,nrows ,1 ); 2282stream -> parallel_for (sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2283 [= ](sycl::nd_item < 3 > item_ct1 ) 2284 [[sycl ::reqd_sub_group_size (WARP_SIZE )]] { 2285k_sum_rows_f32 (x ,dst ,ncols ,item_ct1 ); 2286 }); 2287} 2288 2289static int next_power_of_2 (int x ) { 2290int n = 1 ; 2291while (n < x ) { 2292n *=2 ; 2293 } 2294return n ; 2295} 2296 2297static void init_argsort_indices_padded ( 2298int * idx , 2299const int nrows , 2300const int ncols_pad , 2301const sycl::nd_item < 1 > & item_ct1 ) { 2302const size_t gid = item_ct1 .get_local_range (0 )* item_ct1 .get_group (0 )+ item_ct1 .get_local_id (0 ); 2303const size_t total = (size_t )nrows * (size_t )ncols_pad ; 2304 2305if (gid >=total ) { 2306return ; 2307 } 2308 2309idx [gid ]= (int ) (gid % (size_t )ncols_pad ); 2310} 2311 2312template < ggml_sort_order order > 2313static void argsort_f32_i32_global_pass (const float * x , 2314int * idx , 2315const int ncols , 2316const int nrows , 2317const int ncols_pad , 2318const int j , 2319const int k , 2320const sycl::nd_item < 1 > & item_ct1 ) { 2321const size_t gid = item_ct1 .get_local_range (0 )* item_ct1 .get_group (0 )+ item_ct1 .get_local_id (0 ); 2322const size_t total = (size_t )nrows * (size_t )ncols_pad ; 2323 2324if (gid >=total ) { 2325return ; 2326 } 2327 2328const int row = (int ) (gid / (size_t )ncols_pad ); 2329const int col = (int ) (gid % (size_t )ncols_pad ); 2330const int ixj = col ^j ; 2331 2332if (ixj <=col || ixj >=ncols_pad ) { 2333return ; 2334 } 2335 2336const size_t base = (size_t )row * (size_t )ncols_pad ; 2337const size_t pos_a = base + (size_t )col ; 2338const size_t pos_b = base + (size_t )ixj ; 2339 2340const int a = idx [pos_a ]; 2341const int b = idx [pos_b ]; 2342 2343bool do_swap = false; 2344 2345if ((col & k )== 0 ) { 2346if (a >=ncols || 2347 (b < ncols && 2348 (order == GGML_SORT_ORDER_ASC ? 2349x [(size_t )row * (size_t )ncols + (size_t )a ]> x [(size_t )row * (size_t )ncols + (size_t )b ] : 2350x [(size_t )row * (size_t )ncols + (size_t )a ]< x [(size_t )row * (size_t )ncols + (size_t )b ]))) { 2351do_swap = true; 2352 } 2353 }else { 2354if (b >=ncols || 2355 (a < ncols && 2356 (order == GGML_SORT_ORDER_ASC ? 2357x [(size_t )row * (size_t )ncols + (size_t )a ]< x [(size_t )row * (size_t )ncols + (size_t )b ] : 2358x [(size_t )row * (size_t )ncols + (size_t )a ]> x [(size_t )row * (size_t )ncols + (size_t )b ]))) { 2359do_swap = true; 2360 } 2361 } 2362 2363if (do_swap ) { 2364idx [pos_a ]= b ; 2365idx [pos_b ]= a ; 2366 } 2367} 2368 2369static void copy_argsort_indices_unpadded (const int * idx_padded , 2370int * dst , 2371const int nrows , 2372const int ncols , 2373const int ncols_pad , 2374const sycl::nd_item < 1 > & item_ct1 ) { 2375const size_t gid = item_ct1 .get_local_range (0 )* item_ct1 .get_group (0 )+ item_ct1 .get_local_id (0 ); 2376const size_t total = (size_t )nrows * (size_t )ncols ; 2377 2378if (gid >=total ) { 2379return ; 2380 } 2381 2382const int row = (int ) (gid / (size_t )ncols ); 2383const int col = (int ) (gid % (size_t )ncols ); 2384 2385dst [(size_t )row * (size_t )ncols + (size_t )col ]= idx_padded [(size_t )row * (size_t )ncols_pad + (size_t )col ]; 2386} 2387 2388static void argsort_f32_i32_sycl (const float * x ,int * dst ,const int ncols , 2389const int nrows ,ggml_sort_order order , 2390queue_ptr stream ,int device ,ggml_sycl_pool & pool ) { 2391// bitonic sort requires ncols to be power of 2 2392const int ncols_pad = next_power_of_2 (ncols ); 2393const size_t shared_mem = (size_t )ncols_pad * sizeof (int ); 2394const size_t smpbo = ggml_sycl_info ().devices [device ].smpbo ; 2395 2396if (shared_mem > smpbo ) { 2397ggml_sycl_pool_alloc < int > idx_padded_alloc (pool , (size_t )nrows * (size_t )ncols_pad ); 2398int * idx_padded = idx_padded_alloc .get (); 2399 2400constexpr size_t block_size = 256 ; 2401const size_t total_padded = (size_t )nrows * (size_t )ncols_pad ; 2402const size_t nblocks_padded = (total_padded + block_size - 1 ) /block_size ; 2403 2404stream -> parallel_for ( 2405 sycl::nd_range < 1 > (sycl::range < 1 > (nblocks_padded * block_size ), sycl::range < 1 > (block_size )), 2406 [= ](sycl::nd_item < 1 > item_ct1 ) {init_argsort_indices_padded (idx_padded ,nrows ,ncols_pad ,item_ct1 ); }); 2407 2408for (int k = 2 ;k <=ncols_pad ;k *=2 ) { 2409for (int j = k /2 ;j > 0 ;j /=2 ) { 2410if (order == GGML_SORT_ORDER_ASC ) { 2411stream -> parallel_for ( 2412 sycl::nd_range < 1 > (sycl::range < 1 > (nblocks_padded * block_size ), sycl::range < 1 > (block_size )), 2413 [= ](sycl::nd_item < 1 > item_ct1 ) { 2414argsort_f32_i32_global_pass < GGML_SORT_ORDER_ASC > (x ,idx_padded ,ncols ,nrows ,ncols_pad ,j , 2415k ,item_ct1 ); 2416 }); 2417 }else if (order == GGML_SORT_ORDER_DESC ) { 2418stream -> parallel_for ( 2419 sycl::nd_range < 1 > (sycl::range < 1 > (nblocks_padded * block_size ), sycl::range < 1 > (block_size )), 2420 [= ](sycl::nd_item < 1 > item_ct1 ) { 2421argsort_f32_i32_global_pass < GGML_SORT_ORDER_DESC > (x ,idx_padded ,ncols ,nrows ,ncols_pad ,j , 2422k ,item_ct1 ); 2423 }); 2424 }else { 2425GGML_ABORT ("invalid sort order" ); 2426 } 2427 } 2428 } 2429 2430const size_t total = (size_t )nrows * (size_t )ncols ; 2431const size_t nblocks = (total + block_size - 1 ) /block_size ; 2432stream -> parallel_for (sycl::nd_range < 1 > (sycl::range < 1 > (nblocks * block_size ), sycl::range < 1 > (block_size )), 2433 [= ](sycl::nd_item < 1 > item_ct1 ) { 2434copy_argsort_indices_unpadded (idx_padded ,dst ,nrows ,ncols ,ncols_pad ,item_ct1 ); 2435 }); 2436 2437return ; 2438 } 2439 2440int nth = 1 ; 2441int max_block_size = ggml_sycl_info ().max_work_group_sizes [device ]; 2442while (nth < ncols_pad && nth < max_block_size ) 2443nth *=2 ; 2444if (nth > max_block_size ) 2445nth = max_block_size ; 2446 2447const int tasks_per_thread = ncols_pad /nth ; 2448 2449const sycl::range < 3 > block_dims (1 ,1 ,nth ); 2450const sycl::range < 3 > block_nums (1 ,nrows ,1 ); 2451 2452if (order == GGML_SORT_ORDER_ASC ) { 2453stream -> submit ([& ](sycl::handler & cgh ) { 2454 sycl::local_accessor < uint8_t ,1 > dpct_local_acc_ct1 ( 2455 sycl::range < 1 > (shared_mem ),cgh ); 2456 2457cgh .parallel_for ( 2458 sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2459 [= ](sycl::nd_item < 3 > item_ct1 ) { 2460k_argsort_f32_i32 < GGML_SORT_ORDER_ASC > ( 2461x ,dst ,ncols ,ncols_pad ,tasks_per_thread ,item_ct1 , 2462dpct_local_acc_ct1 2463 .get_multi_ptr < sycl::access::decorated::no > () 2464 .get ()); 2465 }); 2466 }); 2467 }else if (order == GGML_SORT_ORDER_DESC ) { 2468stream -> submit ([& ](sycl::handler & cgh ) { 2469 sycl::local_accessor < uint8_t ,1 > dpct_local_acc_ct1 ( 2470 sycl::range < 1 > (shared_mem ),cgh ); 2471 2472cgh .parallel_for ( 2473 sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2474 [= ](sycl::nd_item < 3 > item_ct1 ) { 2475k_argsort_f32_i32 < GGML_SORT_ORDER_DESC > ( 2476x ,dst ,ncols ,ncols_pad ,tasks_per_thread ,item_ct1 , 2477dpct_local_acc_ct1 2478 .get_multi_ptr < sycl::access::decorated::no > () 2479 .get ()); 2480 }); 2481 }); 2482 }else { 2483GGML_ABORT ("fatal error" ); 2484 } 2485} 2486 2487// Scan and block merge, shared by every launch shape below so a partitioned row uses the 2488// same insertion order as an unpartitioned one. 2489// 2490// src_map != nullptr: report src_map[col] instead of col, so a merge pass can carry the 2491// original column index through. 2492// out_vals != nullptr: also emit the k winning values, for a later merge pass. 2493// swap01: emit in the output order the single-pass path uses. 2494static void top_k_scan_merge_f32 ( 2495const float * src_vals , 2496const int32_t * src_map , 2497const int begin , 2498const int end , 2499const int k , 2500const int block_size , 2501float * shared_vals , 2502int * shared_idx , 2503float * out_vals , 2504int32_t * out_idx , 2505const bool swap01 , 2506const sycl::nd_item < 1 > & item_ct1 2507) { 2508const int tid = item_ct1 .get_local_id (0 ); 2509 2510// The running top-k lives in SLM (shared local memory) rather than a private array: 2511// an array indexed by a runtime position cannot be register-allocated, so a private 2512// one lands in scratch, i.e. device memory, and insertion is this kernel's dominant 2513// cost. 2514// 2515// Lane-strided (lv[i * block_size]) rather than lane-blocked (lv[i]) so a given i is 2516// contiguous across lanes; a k-strided layout would put every lane of a shift step in 2517// the same SLM bank. 2518float * lv = shared_vals + tid ; 2519int * li = shared_idx + tid ; 2520 2521for (int i = 0 ;i < k ;i ++ ) { 2522lv [i * block_size ]= - FLT_MAX ; 2523li [i * block_size ]= -1 ; 2524 } 2525 2526// The k-th best, cached in a register. The reject test is taken for the large 2527// majority of elements scanned, and in that case touches no memory. 2528float kth = - FLT_MAX ; 2529 2530for (int col = begin + tid ;col < end ;col += block_size ) { 2531float val = src_vals [col ]; 2532 2533if (val > kth ) { 2534int pos = k - 1 ; 2535while (pos > 0 && val > lv [(pos - 1 )* block_size ]) { 2536pos -- ; 2537 } 2538 2539for (int i = k - 1 ;i > pos ;i -- ) { 2540lv [i * block_size ]= lv [(i - 1 )* block_size ]; 2541li [i * block_size ]= li [(i - 1 )* block_size ]; 2542 } 2543lv [pos * block_size ]= val ; 2544li [pos * block_size ]= src_map ?src_map [col ] :col ; 2545 2546kth = lv [(k - 1 )* block_size ]; 2547 } 2548 } 2549 2550item_ct1 .barrier (sycl::access::fence_space::local_space ); 2551 2552if (tid != 0 ) { 2553return ; 2554 } 2555 2556// Same treatment for the merge accumulator, past the per-lane region. 2557float * fv = shared_vals + (size_t )k * block_size ; 2558int * fi = shared_idx + (size_t )k * block_size ; 2559 2560for (int i = 0 ;i < k ;i ++ ) { 2561fv [i ]= - FLT_MAX ; 2562fi [i ]= -1 ; 2563 } 2564 2565float fkth = - FLT_MAX ; 2566 2567// Candidates are visited in the same (t, i) order as before, so tie-breaking is 2568// unchanged. 2569for (int t = 0 ;t < block_size ;t ++ ) { 2570for (int i = 0 ;i < k ;i ++ ) { 2571float val = shared_vals [i * block_size + t ]; 2572 2573if (val <=fkth ) { 2574// Lane t's list is sorted descending, so once one of its entries loses 2575// to the k-th best, every later entry loses too. fkth only rises, so 2576// that stays true for the rest of the merge. This turns the merge from 2577// block_size*k steps into roughly block_size plus the candidates 2578// accepted. 2579break ; 2580 } 2581 2582int idx = shared_idx [i * block_size + t ]; 2583 2584int pos = k - 1 ; 2585while (pos > 0 && val > fv [pos - 1 ]) { 2586pos -- ; 2587 } 2588 2589for (int j = k - 1 ;j > pos ;j -- ) { 2590fv [j ]= fv [j - 1 ]; 2591fi [j ]= fi [j - 1 ]; 2592 } 2593fv [pos ]= val ; 2594fi [pos ]= idx ; 2595 2596fkth = fv [k - 1 ]; 2597 } 2598 } 2599 2600if (out_vals ) { 2601for (int i = 0 ;i < k ;i ++ ) { 2602out_vals [i ]= fv [i ]; 2603 } 2604 } 2605 2606for (int i = 0 ;i < k ;i ++ ) { 2607out_idx [i ]= fi [i ]; 2608 } 2609 2610if (swap01 && k > 1 ) { 2611int32_t temp = out_idx [0 ]; 2612out_idx [0 ]= out_idx [1 ]; 2613out_idx [1 ]= temp ; 2614 } 2615} 2616 2617static void top_k_f32_sycl ( 2618ggml_backend_sycl_context & ctx , 2619const float * src , 2620int32_t * dst_indices , 2621const int64_t ncols , 2622const int64_t nrows , 2623const int k , 2624 dpct::queue_ptr main_stream 2625) { 2626// A row is scanned by exactly one work-group, so a vocabulary-sized row leaves the 2627// rest of the device idle. What the scan is short of is memory requests in flight, 2628// not bandwidth or per-request latency, so lanes in flight is the lever: split the 2629// row across independent work-groups, have each emit its partition's top-k, and 2630// merge those nsplit*k candidates in a second launch. 2631// 2632// split_block trades parallelism against SLM residency. Its cost is 2633// (split_block + 1) * k * 8 bytes of SLM per group, so at the k <= 32 ceiling 128 2634// lanes need about 33 KB, which leaves a single resident group per Xe-core. Revisit 2635// if the supported k ever grows. 2636constexpr int split_block = 128 ; 2637constexpr int max_splits = 128 ; 2638constexpr int min_cols = 8192 ; 2639 2640int nsplit = 1 ; 2641if (ncols >=min_cols ) { 2642// A partition is then always >= split_block = 128 columns, hence always more than 2643// the k <= 32 ceiling, so no pass is ever padded with -FLT_MAX sentinels. 2644const int64_t want = ncols /split_block ; 2645nsplit = (int ) (want > max_splits ?max_splits :want ); 2646 } 2647 2648if (nsplit > 1 ) { 2649const int nchunk = (int ) ((ncols + nsplit - 1 ) /nsplit ); 2650const size_t ncand = (size_t )nrows * nsplit * k ; 2651 2652ggml_sycl_pool_alloc < float > part_vals (ctx .pool (),ncand ); 2653ggml_sycl_pool_alloc < int32_t > part_idx (ctx .pool (),ncand ); 2654 2655float * pv = part_vals .get (); 2656int32_t * pi = part_idx .get (); 2657 2658const sycl::range < 1 > block_dims (split_block ); 2659 2660main_stream -> submit ([& ](sycl::handler & cgh ) { 2661 sycl::local_accessor < float ,1 > shared_vals (sycl::range < 1 > ((split_block + 1 )* k ),cgh ); 2662 sycl::local_accessor < int ,1 > shared_idx (sycl::range < 1 > ((split_block + 1 )* k ),cgh ); 2663 2664cgh .parallel_for ( 2665 sycl::nd_range < 1 > (sycl::range < 1 > (nrows * nsplit )* block_dims ,block_dims ), 2666 [= ](sycl::nd_item < 1 > item_ct1 ) { 2667const int grp = item_ct1 .get_group (0 ); 2668const int row = grp /nsplit ; 2669const int part = grp %nsplit ; 2670 2671const int begin = part * nchunk ; 2672int end = begin + nchunk ; 2673if (end > (int )ncols ) { 2674end = (int )ncols ; 2675 } 2676 2677top_k_scan_merge_f32 ( 2678src + (int64_t )row * ncols ,nullptr ,begin ,end ,k ,split_block , 2679shared_vals .get_multi_ptr < sycl::access::decorated::no > ().get (), 2680shared_idx .get_multi_ptr < sycl::access::decorated::no > ().get (), 2681pv + (size_t )grp * k ,pi + (size_t )grp * k , false,item_ct1 ); 2682 }); 2683 }); 2684 2685main_stream -> submit ([& ](sycl::handler & cgh ) { 2686 sycl::local_accessor < float ,1 > shared_vals (sycl::range < 1 > ((split_block + 1 )* k ),cgh ); 2687 sycl::local_accessor < int ,1 > shared_idx (sycl::range < 1 > ((split_block + 1 )* k ),cgh ); 2688 2689cgh .parallel_for ( 2690 sycl::nd_range < 1 > (sycl::range < 1 > (nrows )* block_dims ,block_dims ), 2691 [= ](sycl::nd_item < 1 > item_ct1 ) { 2692const int row = item_ct1 .get_group (0 ); 2693const size_t off = (size_t )row * nsplit * k ; 2694 2695top_k_scan_merge_f32 ( 2696pv + off ,pi + off ,0 ,nsplit * k ,k ,split_block , 2697shared_vals .get_multi_ptr < sycl::access::decorated::no > ().get (), 2698shared_idx .get_multi_ptr < sycl::access::decorated::no > ().get (), 2699nullptr ,dst_indices + (int64_t )row * k , true,item_ct1 ); 2700 }); 2701 }); 2702 2703return ; 2704 } 2705 2706const int block_size = 128 ; 2707 2708const sycl::range < 1 > block_dims (block_size ); 2709const sycl::range < 1 > grid_dims (nrows ); 2710 2711main_stream -> submit ([& ](sycl::handler & cgh ) { 2712 sycl::local_accessor < float ,1 > shared_vals (sycl::range < 1 > ((block_size + 1 )* k ),cgh ); 2713 sycl::local_accessor < int ,1 > shared_idx (sycl::range < 1 > ((block_size + 1 )* k ),cgh ); 2714 2715cgh .parallel_for ( 2716 sycl::nd_range < 1 > (grid_dims * block_dims ,block_dims ), 2717 [= ](sycl::nd_item < 1 > item_ct1 ) { 2718const int row = item_ct1 .get_group (0 ); 2719 2720if (row >=nrows )return ; 2721 2722top_k_scan_merge_f32 ( 2723src + (int64_t )row * ncols ,nullptr ,0 , (int )ncols ,k ,block_size , 2724shared_vals .get_multi_ptr < sycl::access::decorated::no > ().get (), 2725shared_idx .get_multi_ptr < sycl::access::decorated::no > ().get (), 2726nullptr ,dst_indices + (int64_t )row * k , true,item_ct1 ); 2727 }); 2728 }); 2729} 2730 2731static void argmax_f32_i32_sycl (const float * x ,int * dst ,const int ncols , 2732const int nrows ,queue_ptr stream ) { 2733const sycl::range < 3 > block_dims (1 ,1 ,SYCL_ARGMAX_BLOCK_SIZE ); 2734const sycl::range < 3 > block_nums (1 ,nrows ,1 ); 2735const size_t shared_mem = 256 * sizeof (float ); 2736 2737stream -> submit ([& ](sycl::handler & cgh ) { 2738 sycl::local_accessor < float ,1 > shared_data ( 2739 sycl::range < 1 > (shared_mem /sizeof (float )),cgh ); 2740 sycl::local_accessor < int ,1 > shared_indices ( 2741 sycl::range < 1 > (shared_mem /sizeof (float )),cgh ); 2742 2743cgh .parallel_for ( 2744 sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2745 [= ](sycl::nd_item < 3 > item_ct1 ) { 2746const int tid = item_ct1 .get_local_id (2 ); 2747const int row = item_ct1 .get_global_id (1 ); 2748 2749float max_val = - INFINITY ; 2750int max_idx = -1 ; 2751 2752for (int col = tid ;col < ncols ;col += 256 ) { 2753float val = x [row * ncols + col ]; 2754if (val > max_val ) { 2755max_val = val ; 2756max_idx = col ; 2757 } 2758 } 2759 2760shared_data [tid ]= max_val ; 2761shared_indices [tid ]= max_idx ; 2762item_ct1 .barrier (sycl::access::fence_space::local_space ); 2763 2764for (int stride = 256 /2 ;stride > 0 ;stride >>=1 ) { 2765if (tid < stride ) { 2766float val1 = shared_data [tid ]; 2767float val2 = shared_data [tid + stride ]; 2768if (val2 > val1 ) { 2769shared_data [tid ]= val2 ; 2770shared_indices [tid ]= shared_indices [tid + stride ]; 2771 } 2772 } 2773item_ct1 .barrier (sycl::access::fence_space::local_space ); 2774 } 2775 2776 2777if (tid == 0 ) { 2778dst [row ]= shared_indices [0 ]; 2779 } 2780 }); 2781 }); 2782} 2783static void diag_mask_inf_f32_sycl (const float * x ,float * dst , 2784const int ncols_x ,const int nrows_x , 2785const int rows_per_channel ,const int n_past , 2786queue_ptr stream ) { 2787const sycl::range < 3 > block_dims (1 ,SYCL_DIAG_MASK_INF_BLOCK_SIZE ,1 ); 2788const int block_num_x = (ncols_x + SYCL_DIAG_MASK_INF_BLOCK_SIZE - 1 ) /SYCL_DIAG_MASK_INF_BLOCK_SIZE ; 2789const sycl::range < 3 > block_nums (1 ,block_num_x ,nrows_x ); 2790stream -> parallel_for (sycl::nd_range < 3 > (block_nums * block_dims ,block_dims ), 2791 [= ](sycl::nd_item < 3 > item_ct1 ) { 2792diag_mask_inf_f32 (x ,dst ,ncols_x , 2793rows_per_channel ,n_past , 2794item_ct1 ); 2795 }); 2796} 2797 2798static dpct::err0 ggml_sycl_cpy_tensor_2d (void * dst , 2799const struct ggml_tensor * src , 2800int64_t i3 ,int64_t i2 , 2801int64_t i1_low ,int64_t i1_high , 2802queue_ptr stream )try { 2803 2804 dpct::memcpy_direction kind ; 2805char * src_ptr ; 2806if (ggml_backend_buffer_is_host (src -> buffer )) { 2807kind = dpct::host_to_device ; 2808//GGML_SYCL_DEBUG("%s: Host buffer type src tensor\n", __func__); 2809src_ptr = (char * )src -> data ; 2810// GGML_SYCL_DEBUG("ggml_sycl_cpy_tensor_2d GGML_BACKEND_TYPE_CPU src_ptr %p\n", src_ptr); 2811 }else if (ggml_backend_buffer_is_sycl (src -> buffer )) { 2812// If buffer is a SYCL buffer 2813//GGML_SYCL_DEBUG("%s: SYCL buffer type src tensor\n", __func__); 2814kind = dpct::device_to_device ; 2815src_ptr = (char * )src -> data ; 2816 }else if (ggml_backend_buffer_is_sycl_split (src -> buffer )) { 2817/* 2818If buffer is a SYCL split buffer 2819*/ 2820//GGML_SYCL_DEBUG("%s: Split buffer type src tensor\n", __func__); 2821GGML_ASSERT (i1_low == 0 && i1_high == src -> ne [1 ]); 2822kind = dpct::device_to_device ; 2823ggml_tensor_extra_gpu * extra = (ggml_tensor_extra_gpu * )src -> extra ; 2824int id ; 2825SYCL_CHECK (CHECK_TRY_ERROR ( 2826id = get_current_device_id ())); 2827// GGML_SYCL_DEBUG("current device index %d\n", id); 2828src_ptr = (char * )extra -> data_device [id ]; 2829 }else { 2830// GGML_SYCL_DEBUG("GGML_ABORT("fatal error")\n"); 2831GGML_ABORT ("fatal error" ); 2832 } 2833char * dst_ptr = (char * )dst ; 2834 2835GGML_TENSOR_LOCALS_1 (int64_t ,ne ,src ,ne ); 2836GGML_TENSOR_LOCALS (int64_t ,nb ,src ,nb ); 2837const enum ggml_type type = src -> type ; 2838const int64_t ts = ggml_type_size (type ); 2839const int64_t bs = ggml_blck_size (type ); 2840int64_t i1_diff = i1_high - i1_low ; 2841 2842const char * x = src_ptr + i1_low * nb1 + i2 * nb2 + i3 * nb3 ; 2843if (nb0 == ts && nb1 == ts * ne0 /bs ) { 2844// GGML_SYCL_DEBUG("stream->memcpy: dst_ptr=%p, x=%p, size=%lu\n", dst_ptr, x, i1_diff * nb1); 2845// return CHECK_TRY_ERROR(stream->memcpy(dst_ptr, x, i1_diff * nb1)); 2846return CHECK_TRY_ERROR (dpct::async_dpct_memcpy (dst_ptr ,x ,i1_diff * nb1 , 2847kind ,* stream )); 2848 2849 }else if (nb0 == ts ) { 2850return CHECK_TRY_ERROR ( 2851 dpct::async_dpct_memcpy (dst_ptr ,ts * ne0 /bs ,x ,nb1 , 2852ts * ne0 /bs ,i1_diff ,kind ,* stream )); 2853 }else { 2854for (int64_t i1 = 0 ;i1 < i1_diff ;i1 ++ ) { 2855const void * rx = (const void * ) ((const char * )x + i1 * nb1 ); 2856void * rd = (void * ) (dst_ptr + i1 * ts * ne0 /bs ); 2857// pretend the row is a matrix with cols=1 2858 dpct::err0 r = CHECK_TRY_ERROR (dpct::async_dpct_memcpy ( 2859rd ,ts /bs ,rx ,nb0 ,ts /bs ,ne0 ,kind ,* stream )); 2860/* 2861DPCT1001:85: The statement could not be removed. 2862*/ 2863/* 2864DPCT1000:86: Error handling if-stmt was detected but could not be 2865rewritten. 2866*/ 2867if (r != 0 )return r ; 2868 } 2869return 0 ; 2870 } 2871} 2872catch (sycl::exception const & exc ) { 2873 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 2874 <<", line:" <<__LINE__ << std::endl ; 2875 std::exit (1 ); 2876} 2877 2878inline void ggml_sycl_op_mul_mat_sycl ( 2879ggml_backend_sycl_context & ctx , 2880const ggml_tensor * src0 ,const ggml_tensor * src1 ,ggml_tensor * dst , 2881const char * src0_dd_i ,const float * src1_ddf_i ,const char * src1_ddq_i , 2882float * dst_dd_i ,const int64_t row_low ,const int64_t row_high , 2883const int64_t src1_ncols ,const int64_t src1_padded_row_size , 2884const queue_ptr & stream )try { 2885 2886GGML_ASSERT (src0_dd_i != nullptr ); 2887GGML_ASSERT (src1_ddf_i != nullptr ); 2888GGML_ASSERT (dst_dd_i != nullptr ); 2889 2890const int64_t ne00 = src0 -> ne [0 ]; 2891const int64_t ne10 = src1 -> ne [0 ]; 2892GGML_ASSERT (ne00 == ne10 ); 2893 2894const int64_t row_diff = row_high - row_low ; 2895 2896int id ; 2897SYCL_CHECK ( 2898CHECK_TRY_ERROR (id = get_current_device_id ())); 2899 2900const int64_t ne0 = dst -> ne [0 ];// used by MKL only 2901// the main device has a larger memory buffer to hold the results from all GPUs 2902// ldc == nrows of the matrix that cuBLAS writes into 2903int ldc = id == ctx .device ?ne0 :row_diff ;// used by MKL only 2904 2905#ifdef GGML_SYCL_F16 2906bool use_fp16 = true;// TODO(Yu) SYCL capability check 2907#else 2908bool use_fp16 = false; 2909#endif 2910 2911#if GGML_SYCL_DNNL && defined(GGML_SYCL_HAS_BF16 ) 2912// Fast path for bf16 src0 2913if (src0 -> type == GGML_TYPE_BF16 && g_ggml_sycl_enable_dnn && ggml_is_contiguous (src0 )&& 2914row_diff == src0 -> ne [1 ]) { 2915using bf16_t = sycl::ext::oneapi::bfloat16 ; 2916ggml_sycl_pool_alloc < bf16_t > src1_as_bf16 (ctx .pool (),src1_ncols * ne10 ); 2917if (src1 -> type != GGML_TYPE_BF16 ) { 2918const to_bf16_sycl_t to_bf16_sycl = ggml_get_to_bf16_sycl (src1 -> type ,dst ); 2919GGML_ASSERT (to_bf16_sycl != nullptr ); 2920to_bf16_sycl (src1_ddf_i ,src1_as_bf16 .get (),src1_ncols * ne10 ,stream ); 2921 }else { 2922stream -> memcpy (src1_as_bf16 .get (),src1_ddf_i ,src1_ncols * ne10 * sizeof (bf16_t )); 2923 } 2924DnnlGemmWrapper ::row_gemm (ctx ,row_diff ,src1_ncols ,ne10 , 2925src0_dd_i ,DnnlGemmWrapper ::to_dt < bf16_t > (), 2926src1_as_bf16 .get (),DnnlGemmWrapper ::to_dt < bf16_t > (), 2927dst_dd_i ,DnnlGemmWrapper ::to_dt < float > (),stream ); 2928GGML_UNUSED (dst ); 2929GGML_UNUSED (src1_ddq_i ); 2930GGML_UNUSED (src1_padded_row_size ); 2931return ; 2932 } 2933#endif 2934 2935if ((src0 -> type == GGML_TYPE_F16 || ggml_is_quantized (src0 -> type ))&& use_fp16 && ggml_is_contiguous (src0 )&& 2936row_diff == src0 -> ne [1 ]&& dst -> op_params [0 ]== GGML_PREC_DEFAULT ) { 2937ggml_sycl_pool_alloc < sycl::half > src0_as_f16 (ctx .pool ()); 2938if (src0 -> type != GGML_TYPE_F16 ) { 2939scope_op_debug_print scope_dbg_print (__func__ ,"/to_fp16_sycl" ,dst ,/*num_src=*/ 2 , 2940" : converting src0 to fp16" ); 2941const to_fp16_sycl_t to_fp16_sycl = ggml_get_to_fp16_sycl (src0 -> type ,dst ); 2942GGML_ASSERT (to_fp16_sycl != nullptr ); 2943size_t ne = row_diff * ne00 ; 2944src0_as_f16 .alloc (ne ); 2945to_fp16_sycl (src0_dd_i ,src0_as_f16 .get (),ne ,stream ); 2946 } 2947const sycl::half * src0_ptr = src0 -> type == GGML_TYPE_F16 2948 ? (const sycl::half * )src0_dd_i 2949 :src0_as_f16 .get (); 2950 2951ggml_sycl_pool_alloc < sycl::half > src1_as_f16 (ctx .pool ()); 2952if (src1 -> type != GGML_TYPE_F16 ) { 2953scope_op_debug_print scope_dbg_print (__func__ ,"/to_fp16_sycl" ,dst ,/*num_src=*/ 2 , 2954" : converting src1 to fp16" ); 2955const to_fp16_sycl_t to_fp16_sycl = ggml_get_to_fp16_sycl (src1 -> type ,dst ); 2956GGML_ASSERT (to_fp16_sycl != nullptr ); 2957size_t ne = src1_ncols * ne10 ; 2958src1_as_f16 .alloc (ne ); 2959to_fp16_sycl (src1_ddf_i ,src1_as_f16 .get (),ne ,stream ); 2960 } 2961const sycl::half * src1_ptr = src1 -> type == GGML_TYPE_F16 2962 ? (const sycl::half * )src1 -> data + src1_padded_row_size 2963 :src1_as_f16 .get (); 2964 2965#if GGML_SYCL_DNNL 2966if (g_ggml_sycl_enable_dnn ) { 2967DnnlGemmWrapper ::row_gemm (ctx ,row_diff ,src1_ncols ,ne10 ,src0_ptr , 2968DnnlGemmWrapper ::to_dt < sycl::half > (),src1_ptr ,DnnlGemmWrapper ::to_dt < sycl::half > (), 2969dst_dd_i ,DnnlGemmWrapper ::to_dt < float > (),stream ); 2970 } 2971else 2972#endif 2973 { 2974const float alpha = 1.0f ; 2975const float beta = 0.0f ; 2976SYCL_CHECK (CHECK_TRY_ERROR (dpct::gemm ( 2977* stream , oneapi::mkl::transpose::trans , 2978 oneapi::mkl::transpose::nontrans ,row_diff ,src1_ncols ,ne10 , 2979& alpha ,src0_ptr , dpct::library_data_t::real_half ,ne00 , 2980src1_ptr , dpct::library_data_t::real_half ,ne10 ,& beta , 2981dst_dd_i , dpct::library_data_t::real_float ,ldc , 2982 dpct::library_data_t::real_float ))); 2983 } 2984 }else { 2985ggml_sycl_pool_alloc < float > src0_ddq_as_f32 (ctx .pool ()); 2986ggml_sycl_pool_alloc < float > src1_ddq_as_f32 (ctx .pool ()); 2987if (src0 -> type != GGML_TYPE_F32 ) { 2988scope_op_debug_print scope_dbg_print (__func__ ,"/to_fp32_sycl" ,dst ,/*num_src=*/ 2 , 2989" : converting src0 to fp32" ); 2990const to_fp32_sycl_t to_fp32_sycl = ggml_get_to_fp32_sycl (src0 -> type ,dst ); 2991GGML_ASSERT (to_fp32_sycl != nullptr ); 2992src0_ddq_as_f32 .alloc (row_diff * ne00 ); 2993to_fp32_sycl (src0_dd_i ,src0_ddq_as_f32 .get (),row_diff * ne00 ,stream ); 2994 } 2995if (src1 -> type != GGML_TYPE_F32 ) { 2996scope_op_debug_print scope_dbg_print (__func__ ,"/to_fp32_sycl" ,dst ,/*num_src=*/ 2 , 2997" : converting src1 to fp32" ); 2998const to_fp32_sycl_t to_fp32_sycl = ggml_get_to_fp32_sycl (src1 -> type ,dst ); 2999GGML_ASSERT (to_fp32_sycl != nullptr ); 3000src1_ddq_as_f32 .alloc (src1_ncols * ne10 ); 3001to_fp32_sycl (src1_ddf_i ,src1_ddq_as_f32 .get (),src1_ncols * ne10 ,stream ); 3002 } 3003const float * src0_ddf_i = src0 -> type == GGML_TYPE_F32 ? (const float * )src0_dd_i :src0_ddq_as_f32 .get (); 3004const float * src1_ddf1_i = src1 -> type == GGML_TYPE_F32 ? (const float * )src1_ddf_i :src1_ddq_as_f32 .get (); 3005 3006 { 3007#if GGML_SYCL_DNNL 3008const int64_t gemm_flops = (int64_t )row_diff * src1_ncols * ne10 ; 3009const bool use_mkl_direct = gemm_flops < 256 * 256 * 256 ; 3010if (g_ggml_sycl_enable_dnn && !use_mkl_direct ) { 3011DnnlGemmWrapper ::row_gemm (ctx ,row_diff ,src1_ncols ,ne10 ,src0_ddf_i , 3012DnnlGemmWrapper ::to_dt < float > (),src1_ddf1_i ,DnnlGemmWrapper ::to_dt < float > (), 3013dst_dd_i ,DnnlGemmWrapper ::to_dt < float > (),stream ); 3014 } 3015else 3016#endif 3017 { 3018const float alpha = 1.0f ; 3019const float beta = 0.0f ; 3020SYCL_CHECK (CHECK_TRY_ERROR (oneapi::mkl::blas::column_major::gemm ( 3021* stream , oneapi::mkl::transpose::trans , oneapi::mkl::transpose::nontrans ,row_diff , 3022src1_ncols ,ne10 , dpct::get_value (& alpha ,* stream ),src0_ddf_i ,ne00 ,src1_ddf1_i ,ne10 , 3023 dpct::get_value (& beta ,* stream ),dst_dd_i ,ldc ))); 3024 } 3025 } 3026 } 3027GGML_UNUSED (dst ); 3028GGML_UNUSED (src1_ddq_i ); 3029GGML_UNUSED (src1_padded_row_size ); 3030} 3031catch (sycl::exception const & exc ) { 3032 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 3033 <<", line:" <<__LINE__ << std::endl ; 3034 std::exit (1 ); 3035} 3036 3037inline void ggml_sycl_op_sum (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3038GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3039GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3040 dpct::queue_ptr main_stream = ctx .stream (); 3041SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3042const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3043float * dst_dd = static_cast < float *> (dst -> data ); 3044 3045const int64_t ne = ggml_nelements (dst -> src [0 ]); 3046 3047sum_rows_f32_sycl (src0_dd ,dst_dd ,ne ,1 ,main_stream ); 3048} 3049 3050inline void ggml_sycl_op_sum_rows (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3051GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3052GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3053 dpct::queue_ptr main_stream = ctx .stream (); 3054SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3055const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3056float * dst_dd = static_cast < float *> (dst -> data ); 3057 3058const int64_t ncols = dst -> src [0 ]-> ne [0 ]; 3059const int64_t nrows = ggml_nrows (dst -> src [0 ]); 3060 3061sum_rows_f32_sycl (src0_dd ,dst_dd ,ncols ,nrows ,main_stream ); 3062} 3063 3064inline void ggml_sycl_op_mean (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3065GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3066GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3067 3068 dpct::queue_ptr main_stream = ctx .stream (); 3069SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3070 3071const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3072float * dst_dd = static_cast < float *> (dst -> data ); 3073 3074const int64_t ncols = dst -> src [0 ]-> ne [0 ]; 3075const int64_t nrows = ggml_nrows (dst -> src [0 ]); 3076 3077sum_rows_f32_sycl (src0_dd ,dst_dd ,ncols ,nrows ,main_stream ); 3078 3079main_stream -> parallel_for ( 3080 sycl::range < 1 > (nrows ), 3081 [= ](sycl::id < 1 > row ) { 3082dst_dd [row ] /=ncols ; 3083 } 3084 ); 3085} 3086 3087 3088inline void ggml_sycl_op_argsort (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3089GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3090GGML_ASSERT (dst -> type == GGML_TYPE_I32 ); 3091 dpct::queue_ptr main_stream = ctx .stream (); 3092SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3093const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3094int32_t * dst_dd = static_cast < int32_t *> (dst -> data ); 3095 3096 3097const int64_t ncols = dst -> src [0 ]-> ne [0 ]; 3098const int64_t nrows = ggml_nrows (dst -> src [0 ]); 3099 3100enum ggml_sort_order order = (enum ggml_sort_order )dst -> op_params [0 ]; 3101 3102argsort_f32_i32_sycl (src0_dd , (int * )dst_dd ,ncols ,nrows ,order , 3103main_stream ,ctx .device ,ctx .pool ()); 3104} 3105 3106static void ggml_sycl_op_top_k (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3107const ggml_tensor * src0 = dst -> src [0 ]; 3108 3109GGML_ASSERT (src0 ); 3110GGML_ASSERT (src0 -> type == GGML_TYPE_F32 ); 3111GGML_ASSERT (dst -> type == GGML_TYPE_I32 ); 3112GGML_ASSERT (ggml_is_contiguous (src0 )); 3113 3114 dpct::queue_ptr main_stream = ctx .stream (); 3115SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3116 3117const float * src0_dd = static_cast < const float *> (src0 -> data ); 3118int32_t * dst_dd = static_cast < int32_t *> (dst -> data ); 3119 3120const int k = dst -> ne [0 ]; 3121const int64_t ncols = src0 -> ne [0 ]; 3122const int64_t nrows = ggml_nrows (src0 ); 3123 3124GGML_ASSERT (k > 0 ); 3125GGML_ASSERT (k <=ncols ); 3126 3127if (k <=SYCL_TOP_K_SCAN_MERGE_MAX_K ) { 3128top_k_f32_sycl (ctx ,src0_dd ,dst_dd ,ncols ,nrows ,k ,main_stream ); 3129 }else { 3130ggml_sycl_top_k_radix (ctx ,src0_dd ,dst_dd ,ncols ,nrows ,k ,main_stream ); 3131 } 3132} 3133 3134inline void ggml_sycl_op_argmax (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3135GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3136GGML_ASSERT (dst -> type == GGML_TYPE_I32 ); 3137 3138 dpct::queue_ptr main_stream = ctx .stream (); 3139SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3140const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3141int32_t * dst_dd = static_cast < int32_t *> (dst -> data ); 3142 3143const int64_t ncols = dst -> src [0 ]-> ne [0 ]; 3144const int64_t nrows = ggml_nrows (dst -> src [0 ]); 3145 3146argmax_f32_i32_sycl (src0_dd ,dst_dd ,ncols ,nrows ,main_stream ); 3147} 3148 3149inline void ggml_sycl_op_diag_mask_inf (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3150GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3151GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3152 dpct::queue_ptr main_stream = ctx .stream (); 3153SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3154const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3155float * dst_dd = static_cast < float *> (dst -> data ); 3156 3157const int64_t ne00 = dst -> src [0 ]-> ne [0 ]; 3158const int64_t ne01 = dst -> src [0 ]-> ne [1 ]; 3159const int nrows0 = ggml_nrows (dst -> src [0 ]); 3160 3161const int n_past = ((int32_t * )dst -> op_params )[0 ]; 3162 3163diag_mask_inf_f32_sycl (src0_dd ,dst_dd ,ne00 ,nrows0 ,ne01 ,n_past ,main_stream ); 3164} 3165 3166static void tri_f32_sycl ( 3167const float * src , 3168float * dst , 3169const int64_t ne0 , 3170const int64_t ne1 , 3171const int64_t ne2 , 3172const int64_t ne3 , 3173const ggml_tri_type ttype , 3174 dpct::queue_ptr main_stream 3175) { 3176const size_t total = (size_t )ne0 * (size_t )ne1 * (size_t )ne2 * (size_t )ne3 ; 3177 3178main_stream -> parallel_for (sycl::range < 1 > (total ), [= ](sycl::id < 1 > tid ) { 3179const int64_t idx = (int64_t )tid [0 ]; 3180 3181const int64_t i0 = idx %ne0 ; 3182const int64_t t1 = idx /ne0 ; 3183const int64_t i1 = t1 %ne1 ; 3184 3185bool keep = false; 3186switch (ttype ) { 3187case GGML_TRI_TYPE_LOWER :keep = (i0 < i1 );break ; 3188case GGML_TRI_TYPE_LOWER_DIAG :keep = (i0 <=i1 );break ; 3189case GGML_TRI_TYPE_UPPER :keep = (i0 > i1 );break ; 3190case GGML_TRI_TYPE_UPPER_DIAG :keep = (i0 >=i1 );break ; 3191default :keep = false;break ; 3192 } 3193 3194dst [idx ]= keep ?src [idx ] :0.0f ; 3195 }); 3196} 3197 3198static void ggml_sycl_op_tri (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3199const ggml_tensor * src0 = dst -> src [0 ]; 3200GGML_ASSERT (src0 ); 3201 3202GGML_ASSERT (src0 -> type == GGML_TYPE_F32 ); 3203GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3204GGML_ASSERT (ggml_is_contiguous (src0 )); 3205GGML_ASSERT (ggml_is_contiguous (dst )); 3206GGML_ASSERT (ggml_are_same_shape (src0 ,dst )); 3207 3208 dpct::queue_ptr main_stream = ctx .stream (); 3209SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3210 3211const float * src0_dd = static_cast < const float *> (src0 -> data ); 3212float * dst_dd = static_cast < float *> (dst -> data ); 3213 3214const ggml_tri_type ttype = (ggml_tri_type )ggml_get_op_params_i32 (dst ,0 ); 3215 3216const int64_t ne0 = src0 -> ne [0 ]; 3217const int64_t ne1 = src0 -> ne [1 ]; 3218const int64_t ne2 = src0 -> ne [2 ]; 3219const int64_t ne3 = src0 -> ne [3 ]; 3220 3221tri_f32_sycl (src0_dd ,dst_dd ,ne0 ,ne1 ,ne2 ,ne3 ,ttype ,main_stream ); 3222} 3223 3224 3225inline void ggml_sycl_op_scale (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3226GGML_ASSERT (dst -> src [0 ]-> type == GGML_TYPE_F32 ); 3227GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3228 dpct::queue_ptr main_stream = ctx .stream (); 3229SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3230const float * src0_dd = static_cast < const float *> (dst -> src [0 ]-> data ); 3231float * dst_dd = static_cast < float *> (dst -> data ); 3232 3233float scale ; 3234float bias ; 3235memcpy (& scale , (float * )dst -> op_params + 0 ,sizeof (float )); 3236memcpy (& bias , (float * )dst -> op_params + 1 ,sizeof (float )); 3237 3238scale_f32_sycl (src0_dd ,dst_dd ,scale ,bias ,ggml_nelements (dst -> src [0 ]),main_stream ); 3239/* 3240DPCT1010:87: SYCL uses exceptions to report errors and does not use the 3241error codes. The call was replaced with 0. You need to rewrite this code. 3242*/ 3243SYCL_CHECK (0 ); 3244} 3245 3246static void ggml_sycl_set_peer_access (const int n_tokens ,int main_device ) { 3247static bool peer_access_enabled = false; 3248 3249const bool enable_peer_access = n_tokens <=GGML_SYCL_PEER_MAX_BATCH_SIZE ; 3250 3251if (peer_access_enabled == enable_peer_access ) { 3252return ; 3253 } 3254 3255#ifdef NDEBUG 3256for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 3257SYCL_CHECK (ggml_sycl_set_device (i )); 3258 } 3259 3260for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 3261SYCL_CHECK (ggml_sycl_set_device (i )); 3262 3263for (int id_other = 0 ;id_other < ggml_sycl_info ().device_count ;++ id_other ) { 3264if (i == id_other ) { 3265continue ; 3266 } 3267if (i != main_device && id_other != main_device ) { 3268continue ; 3269 } 3270 3271// int can_access_peer; 3272// SYCL_CHECK(syclDeviceCanAccessPeer(&can_access_peer, id, id_other)); 3273// if (can_access_peer) { 3274// if (enable_peer_access) { 3275// SYCL_CHECK(syclDeviceEnablePeerAccess(id_other, 0)); 3276// } else { 3277// SYCL_CHECK(syclDeviceDisablePeerAccess(id_other)); 3278// } 3279// } 3280 } 3281 } 3282#endif // NDEBUG 3283 3284peer_access_enabled = enable_peer_access ; 3285} 3286 3287template < template < int > typename quantize_f > 3288static void ggml_sycl_op_mul_mat (ggml_backend_sycl_context & ctx ,const ggml_tensor * src0 , 3289const ggml_tensor * src1 ,ggml_tensor * dst , 3290ggml_sycl_op_mul_mat_t op )try { 3291 3292GGML_TENSOR_LOCALS (int64_t ,ne0 ,src0 ,ne ); 3293 3294GGML_TENSOR_LOCALS (int64_t ,ne1 ,src1 ,ne ); 3295const int64_t nrows1 = ggml_nrows (src1 ); 3296 3297GGML_ASSERT (ne03 == ne13 ); 3298 3299const int64_t ne0 = dst -> ne [0 ]; 3300const int64_t ne1 = dst -> ne [1 ]; 3301 3302const int nb2 = dst -> nb [2 ]; 3303const int nb3 = dst -> nb [3 ]; 3304 3305GGML_ASSERT (!ggml_backend_buffer_is_sycl_split (dst -> buffer )); 3306GGML_ASSERT (!ggml_backend_buffer_is_sycl_split (src1 -> buffer )); 3307GGML_ASSERT (src1 -> type == GGML_TYPE_F32 || (src1 -> ne [2 ]== 1 && src1 -> ne [3 ]== 1 )); 3308 3309GGML_ASSERT (ne12 >=ne02 && ne12 %ne02 == 0 ); 3310 3311const int64_t i02_divisor = ne12 /ne02 ; 3312 3313const size_t src0_ts = ggml_type_size (src0 -> type ); 3314const size_t src0_bs = ggml_blck_size (src0 -> type ); 3315const size_t q8_1_ts = sizeof (block_q8_1 ); 3316const size_t q8_1_bs = QK8_1 ; 3317 3318ggml_tensor_extra_gpu * src0_extra = (ggml_tensor_extra_gpu * )src0 -> extra ; 3319ggml_tensor_extra_gpu * src1_extra = (ggml_tensor_extra_gpu * )src1 -> extra ; 3320 3321const bool src0_is_contiguous = ggml_is_contiguous (src0 ); 3322const bool src1_is_contiguous = ggml_is_contiguous (src1 ); 3323 3324int64_t src1_padded_col_size = GGML_PAD (ne10 ,MATRIX_ROW_PADDING ); 3325 3326const bool split = ggml_backend_buffer_is_sycl_split (src0 -> buffer ); 3327GGML_ASSERT (!(split && ne02 > 1 )); 3328GGML_ASSERT (!(split && ne03 > 1 )); 3329GGML_ASSERT (!(split && ne02 < ne12 )); 3330 3331 std::array < float ,GGML_SYCL_MAX_DEVICES > tensor_split ; 3332if (split ) { 3333// TODO: check that src0->buffer->buft is a split buffer type, replace GGML_BACKEND_TYPE_GPU_SPLIT check 3334// GGML_ASSERT(src0->buffer != nullptr && src0->buffer->buft == ...); 3335ggml_backend_sycl_split_buffer_type_context * buft_ctx = (ggml_backend_sycl_split_buffer_type_context * )src0 -> buffer -> buft -> context ; 3336tensor_split = buft_ctx -> tensor_split ; 3337 } 3338 3339struct dev_data { 3340ggml_sycl_pool_alloc < char > src0_dd_alloc ; 3341ggml_sycl_pool_alloc < float > src1_ddf_alloc ; 3342ggml_sycl_pool_alloc < char > src1_ddq_alloc ; 3343ggml_sycl_pool_alloc < float > dst_dd_alloc ; 3344 3345char * src0_dd = nullptr ; 3346float * src1_ddf = nullptr ;// float 3347char * src1_ddq = nullptr ;// q8_1 3348float * dst_dd = nullptr ; 3349 3350int64_t row_low ; 3351int64_t row_high ; 3352 }; 3353 3354dev_data dev [GGML_SYCL_MAX_DEVICES ]; 3355 3356int used_devices = 0 ; 3357queue_ptr main_stream = ctx .stream (); 3358 3359for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 3360// by default, use all rows 3361dev [i ].row_low = 0 ; 3362dev [i ].row_high = ne01 ; 3363 3364// for multi GPU, get the row boundaries from tensor split 3365// and round to mul_mat_q tile sizes 3366if (split ) { 3367const int64_t rounding = get_row_rounding (src0 -> type ,tensor_split ); 3368 3369if (i != 0 ) { 3370dev [i ].row_low = ne01 * tensor_split [i ]; 3371if (dev [i ].row_low < ne01 ) { 3372dev [i ].row_low -= dev [i ].row_low %rounding ; 3373 } 3374 } 3375 3376if (i != ggml_sycl_info ().device_count - 1 ) { 3377dev [i ].row_high = ne01 * tensor_split [i + 1 ]; 3378if (dev [i ].row_high < ne01 ) { 3379dev [i ].row_high -= dev [i ].row_high %rounding ; 3380 } 3381 } 3382 } 3383 } 3384 3385constexpr bool quantize_enabled = !std::is_same_v < quantize_f < QK8_1 /WARP_SIZE > , 3386no_quantize_q8_1 < QK8_1 /WARP_SIZE >> ; 3387for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 3388if ((!split && i != ctx .device )|| dev [i ].row_low == dev [i ].row_high ) { 3389continue ; 3390 } 3391 3392used_devices ++ ; 3393 3394const bool src1_on_device = i == ctx .device ; 3395const bool dst_on_device = i == ctx .device ; 3396 3397ggml_sycl_set_device (i ); 3398queue_ptr stream = ctx .stream (i ,0 ); 3399 3400if (src0_is_contiguous ) { 3401dev [i ].src0_dd = (char * )src0 -> data ; 3402 }else { 3403dev [i ].src0_dd = dev [i ].src0_dd_alloc .alloc (ctx .pool (i ),ggml_nbytes (src0 )); 3404 } 3405 3406if (src1_on_device && src1_is_contiguous ) { 3407dev [i ].src1_ddf = (float * )src1 -> data ; 3408 }else { 3409dev [i ].src1_ddf = dev [i ].src1_ddf_alloc .alloc (ctx .pool (i ),ggml_nelements (src1 )); 3410 } 3411 3412if constexpr (quantize_enabled ) { 3413dev [i ].src1_ddq = dev [i ].src1_ddq_alloc .alloc (ctx .pool (i ),nrows1 * src1_padded_col_size * q8_1_ts /q8_1_bs ); 3414 3415if (src1_on_device && src1_is_contiguous ) { 3416scope_op_debug_print scope_dbg_print (__func__ ,"/quantize_row_q8_1_sycl" ,dst , 3417/*num_src=*/ 2 ," : converting src1 to Q8_1" ); 3418try { 3419quantize_row_q8_1_sycl < quantize_f > (dev [i ].src1_ddf ,dev [i ].src1_ddq ,ne10 ,nrows1 ,src1_padded_col_size ,stream ); 3420 }catch (sycl::exception const & exc ) { 3421 std::cerr <<"Quantize_row_q8_1_sycl error" <<exc .what () <<"Exception caught at file:" <<__FILE__ 3422 <<", line:" <<__LINE__ << std::endl ; 3423 std::exit (1 ); 3424 } 3425 } 3426 } 3427 3428if (dst_on_device ) { 3429dev [i ].dst_dd = (float * )dst -> data ; 3430 }else { 3431const size_t size_dst_ddf = split ? (dev [i ].row_high - dev [i ].row_low )* ne1 :ggml_nelements (dst ); 3432dev [i ].dst_dd = dev [i ].dst_dd_alloc .alloc (ctx .pool (i ),size_dst_ddf ); 3433 } 3434 } 3435 3436// if multiple devices are used they need to wait for the main device 3437// here an event is recorded that signals that the main device has finished calculating the input data 3438if (split && used_devices > 1 ) { 3439ggml_sycl_set_device (ctx .device ); 3440SYCL_CHECK (CHECK_TRY_ERROR ( 3441* src0_extra -> events [ctx .device ][0 ]= 3442ctx .stream ()-> ext_oneapi_submit_barrier ())); 3443 } 3444 3445const int64_t src1_col_stride = split && used_devices > 1 ?MUL_MAT_SRC1_COL_STRIDE :ne11 ; 3446for (int64_t src1_col_0 = 0 ;src1_col_0 < ne11 ;src1_col_0 += src1_col_stride ) { 3447const int64_t is = split ? (src1_col_0 /src1_col_stride ) %GGML_SYCL_MAX_STREAMS :0 ; 3448const int64_t src1_ncols = src1_col_0 + src1_col_stride > ne11 ?ne11 - src1_col_0 :src1_col_stride ; 3449for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 3450if ((!split && i != ctx .device )|| dev [i ].row_low == dev [i ].row_high ) { 3451continue ; 3452 } 3453 3454const bool src1_on_device = i == ctx .device ; 3455const bool dst_on_device = i == ctx .device ; 3456const int64_t row_diff = dev [i ].row_high - dev [i ].row_low ; 3457 3458ggml_sycl_set_device (i ); 3459queue_ptr stream = ctx .stream (i ,is ); 3460 3461// wait for main GPU data if necessary 3462if (split && (i != ctx .device || is != 0 )) { 3463SYCL_CHECK (CHECK_TRY_ERROR (stream -> ext_oneapi_submit_barrier ( 3464 {* src0_extra -> events [ctx .device ][0 ]}))); 3465 } 3466 3467for (int64_t i0 = 0 ;i0 < ne13 * ne12 ;++ i0 ) { 3468const int64_t i03 = i0 /ne12 ; 3469const int64_t i02 = i0 %ne12 ; 3470 3471const size_t src1_ddq_i_offset = (i0 * ne11 + src1_col_0 )* src1_padded_col_size * q8_1_ts /q8_1_bs ; 3472 3473// for split tensors the data begins at i0 == i0_offset_low 3474char * src0_dd_i = dev [i ].src0_dd + (i0 /i02_divisor )* (ne01 * ne00 * src0_ts )/src0_bs ; 3475float * src1_ddf_i = dev [i ].src1_ddf + (i0 * ne11 + src1_col_0 )* ne10 ; 3476char * src1_ddq_i = dev [i ].src1_ddq + src1_ddq_i_offset ; 3477float * dst_dd_i = dev [i ].dst_dd + (i0 * ne1 + src1_col_0 )* (dst_on_device ?ne0 :row_diff ); 3478 3479// the main device memory buffer can be on VRAM scratch, with space for all partial results 3480// in that case an offset on dst_ddf_i is needed 3481if (i == ctx .device ) { 3482dst_dd_i += dev [i ].row_low ;// offset is 0 if no tensor split 3483 } 3484 3485// copy src0, src1 to device if necessary 3486if (src1_is_contiguous ) { 3487if (i != ctx .device ) { 3488if constexpr (quantize_enabled ) { 3489char * src1_ddq_i_source = dev [ctx .device ].src1_ddq + src1_ddq_i_offset ; 3490SYCL_CHECK ( 3491CHECK_TRY_ERROR (stream 3492-> memcpy (src1_ddq_i ,src1_ddq_i_source , 3493src1_ncols * src1_padded_col_size * q8_1_ts /q8_1_bs ) 3494 .wait ())); 3495 }else { 3496float * src1_ddf_i_source = (float * )src1_extra -> data_device [ctx .device ]; 3497src1_ddf_i_source += (i0 * ne11 + src1_col_0 )* ne10 ; 3498 3499SYCL_CHECK ( 3500CHECK_TRY_ERROR (dev2dev_memcpy (i ,* stream ,ctx .device ,* main_stream ,src1_ddf_i ,src1_ddf_i_source , 3501src1_ncols * ne10 * sizeof (float )))); 3502 } 3503 } 3504 }else { 3505if (src1_on_device ) { 3506SYCL_CHECK (ggml_sycl_cpy_tensor_2d (src1_ddf_i ,src1 ,i03 ,i02 ,src1_col_0 , 3507src1_col_0 + src1_ncols ,stream )); 3508 }else { 3509GGML_ABORT ("src1 is non-contiguous and not on device" ); 3510 } 3511 3512if constexpr (quantize_enabled ) { 3513scope_op_debug_print scope_dbg_print (__func__ ,"/quantize_row_q8_1_sycl" ,dst , 3514/*num_src=*/ 2 ," : converting src1 to Q8_1" ); 3515try { 3516quantize_row_q8_1_sycl < quantize_q8_1 > (src1_ddf_i ,src1_ddq_i ,ne10 ,src1_ncols , 3517src1_padded_col_size ,stream ); 3518 }catch (const sycl::exception & exc ) { 3519 std::cerr <<"Quantize_row_q8_1_sycl error" <<exc .what () 3520 <<"Exception caught at file:" <<__FILE__ <<", line:" <<__LINE__ << std::endl ; 3521 std::exit (1 ); 3522 } 3523 } 3524 } 3525 3526if (src1_col_0 == 0 && !src0_is_contiguous && i02 %i02_divisor == 0 ) { 3527SYCL_CHECK (ggml_sycl_cpy_tensor_2d (src0_dd_i ,src0 ,i03 ,i02 /i02_divisor ,dev [i ].row_low ,dev [i ].row_high ,stream )); 3528 } 3529if (src1 -> type == GGML_TYPE_F16 ) { 3530src1_padded_col_size = (i0 * ne11 + src1_col_0 )* ne10 ; 3531 } 3532// do the computation 3533SYCL_CHECK (CHECK_TRY_ERROR (op (ctx ,src0 ,src1 ,dst ,src0_dd_i ,src1_ddf_i ,src1_ddq_i ,dst_dd_i , 3534dev [i ].row_low ,dev [i ].row_high ,src1_ncols ,src1_padded_col_size ,stream ))); 3535 3536// copy dst to host or other device if necessary 3537if (!dst_on_device ) { 3538void * dst_off_device = dst -> data ; 3539if (split ) { 3540// src0 = weight matrix is saved as a transposed matrix for better memory layout. 3541// dst is NOT transposed. 3542// The outputs of matrix matrix multiplications can therefore NOT simply be concatenated for >1 GPU. 3543// Instead they need to be copied to the correct slice in ne0 = dst row index. 3544// If dst is a vector with ne0 == 1 then you don't have to do this but it still produces correct results. 3545float * dhf_dst_i = (float * ) ((char * )dst_off_device + i02 * nb2 + i03 * nb3 ); 3546GGML_ASSERT (dst -> nb [1 ]== ne0 * sizeof (float )); 3547dhf_dst_i += src1_col_0 * ne0 + dev [i ].row_low ; 3548 3549SYCL_CHECK (CHECK_TRY_ERROR (dpct::async_dpct_memcpy ( 3550dhf_dst_i ,ne0 * sizeof (float ),dst_dd_i , 3551row_diff * sizeof (float ),row_diff * sizeof (float ), 3552src1_ncols , dpct::device_to_device ,* stream ))); 3553 }else { 3554float * dhf_dst_i = (float * ) ((char * )dst_off_device + i02 * nb2 + i03 * nb3 ); 3555GGML_ASSERT (dst -> nb [1 ]== ne0 * sizeof (float )); 3556dhf_dst_i += src1_col_0 * ne0 ; 3557SYCL_CHECK (CHECK_TRY_ERROR ( 3558stream -> memcpy (dhf_dst_i ,dst_dd_i , 3559src1_ncols * ne0 * sizeof (float )).wait ())); 3560 } 3561 } 3562 3563// add event for the main device to wait on until other device is done 3564if (split && (i != ctx .device || is != 0 )) { 3565SYCL_CHECK (CHECK_TRY_ERROR ( 3566* src0_extra -> events [i ][is ]= 3567stream -> ext_oneapi_submit_barrier ())); 3568 } 3569 } 3570 } 3571 } 3572 3573// main device waits for all other devices to be finished 3574if (split && ggml_sycl_info ().device_count > 1 ) { 3575int64_t is_max = (ne11 + MUL_MAT_SRC1_COL_STRIDE - 1 ) /MUL_MAT_SRC1_COL_STRIDE ; 3576is_max = is_max <=GGML_SYCL_MAX_STREAMS ?is_max :GGML_SYCL_MAX_STREAMS ; 3577 3578ggml_sycl_set_device (ctx .device ); 3579for (int i = 0 ;i < ggml_sycl_info ().device_count ;++ i ) { 3580if (dev [i ].row_low == dev [i ].row_high ) { 3581continue ; 3582 } 3583for (int64_t is = 0 ;is < is_max ;++ is ) { 3584SYCL_CHECK (CHECK_TRY_ERROR ( 3585ctx .stream ()-> ext_oneapi_submit_barrier ( 3586 {* src0_extra -> events [i ][is ]}))); 3587 } 3588 } 3589 } 3590} 3591catch (sycl::exception const & exc ) { 3592 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 3593 <<", line:" <<__LINE__ << std::endl ; 3594 std::exit (1 ); 3595} 3596 3597static void ggml_sycl_repeat_back (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3598scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 3599ggml_sycl_op_repeat_back (ctx ,dst ); 3600} 3601 3602static void ggml_sycl_get_rows (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3603scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 2 ); 3604ggml_sycl_op_get_rows (ctx ,dst ); 3605} 3606 3607static void ggml_sycl_norm (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3608scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 3609ggml_sycl_op_norm (ctx ,dst ); 3610} 3611 3612static void ggml_sycl_rms_norm (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3613scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 3614ggml_sycl_op_rms_norm (ctx ,dst ); 3615} 3616 3617static void ggml_sycl_rms_norm_back (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3618scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 2 ); 3619ggml_sycl_op_rms_norm_back (ctx ,dst ); 3620} 3621 3622static void ggml_sycl_l2_norm (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3623scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 3624ggml_sycl_op_l2_norm (ctx ,dst ); 3625} 3626 3627static void ggml_sycl_group_norm (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 3628scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 3629ggml_sycl_op_group_norm (ctx ,dst ); 3630} 3631 3632static void ggml_sycl_mul_mat_vec_p021 (ggml_backend_sycl_context & ctx ,const ggml_tensor * src0 , 3633const ggml_tensor * src1 , 3634ggml_tensor * dst )try { 3635GGML_ASSERT (ggml_is_permuted (src0 )&& ggml_is_permuted (src1 )); 3636GGML_ASSERT (!ggml_backend_buffer_is_sycl_split (src0 -> buffer )); 3637GGML_ASSERT (src0 -> nb [0 ] <=src0 -> nb [1 ]&& src0 -> nb [2 ] <=src0 -> nb [3 ]);// 0213 permutation 3638GGML_ASSERT (src1 -> nb [0 ] <=src1 -> nb [1 ]&& src1 -> nb [2 ] <=src1 -> nb [3 ]);// 0213 permutation 3639GGML_ASSERT (src0 -> type == GGML_TYPE_F16 ); 3640GGML_ASSERT (src1 -> type == GGML_TYPE_F32 ); 3641 3642const int64_t ne00 = src0 -> ne [0 ]; 3643const int64_t ne01 = src0 -> ne [1 ]; 3644const int64_t ne02 = src0 -> ne [2 ]; 3645 3646const int64_t ne12 = src1 -> ne [2 ]; 3647 3648SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3649queue_ptr main_stream = ctx .stream (); 3650 3651void * src0_ddq = src0 -> data ; 3652float * src1_ddf = (float * )src1 -> data ; 3653float * dst_ddf = (float * )dst -> data ; 3654 3655ggml_mul_mat_p021_f16_f32_sycl (src0_ddq ,src1_ddf ,dst_ddf ,ne00 ,ne01 ,ne02 ,ne12 ,main_stream ); 3656} 3657catch (sycl::exception const & exc ) { 3658 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 3659 <<", line:" <<__LINE__ << std::endl ; 3660 std::exit (1 ); 3661} 3662 3663static void ggml_sycl_mul_mat_vec_nc (ggml_backend_sycl_context & ctx ,const ggml_tensor * src0 , 3664const ggml_tensor * src1 , 3665ggml_tensor * dst )try { 3666GGML_ASSERT (!ggml_is_transposed (src0 )); 3667GGML_ASSERT (!ggml_is_transposed (src1 )); 3668GGML_ASSERT (!ggml_is_permuted (src0 )); 3669GGML_ASSERT (!ggml_backend_buffer_is_sycl_split (src0 -> buffer )); 3670GGML_ASSERT (src0 -> type == GGML_TYPE_F16 ); 3671GGML_ASSERT (src1 -> type == GGML_TYPE_F32 ); 3672GGML_ASSERT (src1 -> ne [1 ]== 1 ); 3673GGML_ASSERT (src1 -> ne [3 ]== 1 ); 3674 3675const int64_t ne00 = src0 -> ne [0 ]; 3676const int64_t ne01 = src0 -> ne [1 ]; 3677const int64_t ne02 = src0 -> ne [2 ]; 3678 3679const int64_t nb01 = src0 -> nb [1 ]; 3680const int64_t nb02 = src0 -> nb [2 ]; 3681 3682const int64_t ne12 = src1 -> ne [2 ]; 3683const int64_t nb11 = src1 -> nb [1 ]; 3684 3685SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3686queue_ptr main_stream = ctx .stream (); 3687 3688void * src0_ddq = src0 -> data ; 3689float * src1_ddf = (float * )src1 -> data ; 3690float * dst_ddf = (float * )dst -> data ; 3691 3692const int64_t row_stride_x = nb01 /sizeof (sycl::half ); 3693const int64_t channel_stride_x = nb02 /sizeof (sycl::half ); 3694const int64_t channel_stride_y = nb11 /sizeof (float ); 3695 3696ggml_mul_mat_vec_nc_f16_f32_sycl (src0_ddq ,src1_ddf ,dst_ddf ,ne00 ,ne01 ,row_stride_x ,ne02 ,ne12 ,channel_stride_x ,channel_stride_y ,main_stream ); 3697} 3698catch (sycl::exception const & exc ) { 3699 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 3700 <<", line:" <<__LINE__ << std::endl ; 3701 std::exit (1 ); 3702} 3703 3704static void k_compute_batched_ptrs (const sycl::half * src0_as_f16 ,const sycl::half * src1_as_f16 ,void * dst , 3705const void ** ptrs_src ,void ** ptrs_dst ,int64_t ne12 ,int64_t ne13 ,int64_t ne23 , 3706size_t nb02 ,size_t nb03 ,size_t nb12 ,size_t nb13 ,size_t nbd2 ,size_t nbd3 , 3707int64_t r2 ,int64_t r3 ,const sycl::nd_item < 3 > & item_ct1 ) { 3708const int64_t i13 = item_ct1 .get_group (2 )* item_ct1 .get_local_range (2 )+ item_ct1 .get_local_id (2 ); 3709const int64_t i12 = item_ct1 .get_group (1 )* item_ct1 .get_local_range (1 )+ item_ct1 .get_local_id (1 ); 3710 3711if (i13 >=ne13 || i12 >=ne12 ) { 3712return ; 3713 } 3714 3715const int64_t i03 = i13 /r3 ; 3716const int64_t i02 = i12 /r2 ; 3717 3718const uint8_t * src0_bytes = reinterpret_cast < const uint8_t *> (src0_as_f16 ); 3719const uint8_t * src1_bytes = reinterpret_cast < const uint8_t *> (src1_as_f16 ); 3720uint8_t * dst_bytes = static_cast < uint8_t *> (dst ); 3721 3722ptrs_src [0 * ne23 + i12 + i13 * ne12 ]= src0_bytes + i02 * nb02 + i03 * nb03 ; 3723ptrs_src [1 * ne23 + i12 + i13 * ne12 ]= src1_bytes + i12 * nb12 + i13 * nb13 ; 3724ptrs_dst [0 * ne23 + i12 + i13 * ne12 ]= dst_bytes + i12 * nbd2 + i13 * nbd3 ; 3725} 3726 3727static void ggml_sycl_mul_mat_batched_sycl (ggml_backend_sycl_context & ctx ,const ggml_tensor * src0 , 3728const ggml_tensor * src1 ,ggml_tensor * dst )try { 3729GGML_ASSERT (!ggml_is_transposed (src0 )); 3730GGML_ASSERT (!ggml_is_transposed (src1 )); 3731GGML_ASSERT (!ggml_backend_buffer_is_sycl_split (src0 -> buffer )); 3732GGML_ASSERT (src0 -> type == GGML_TYPE_F16 ); 3733GGML_ASSERT (dst -> type == GGML_TYPE_F32 ); 3734 3735GGML_TENSOR_BINARY_OP_LOCALS 3736 3737// TODO: see https://github.com/ggml-org/llama.cpp/pull/13155 3738// Batched mul_mat requires a rewrite to support both oneDNN and non-contiguous dst 3739GGML_ASSERT (ggml_is_contiguous (dst )); 3740 3741SYCL_CHECK (ggml_sycl_set_device (ctx .device )); 3742queue_ptr queue = ctx .stream (); 3743 3744 dpct::has_capability_or_fail (queue -> get_device (), { sycl::aspect::fp16 }); 3745 3746const sycl::half * src0_f16 = static_cast < const sycl::half *> (src0 -> data ); 3747float * dst_ddf = static_cast < float *> (dst -> data ); 3748 3749const sycl::half * src1_f16 = static_cast < const sycl::half *> (src1 -> data ); 3750#if GGML_SYCL_DNNL 3751const size_t type_size_src0 = ggml_type_size (src0 -> type ); 3752#endif 3753const size_t type_size_src1 = ggml_type_size (src1 -> type ); 3754 3755bool is_src0_cont_2 = ggml_is_contiguous_2 (src0 ); 3756bool is_src1_cont_2 = ggml_is_contiguous_2 (src1 ); 3757 3758// SRC1 strides 3759int64_t s11 = nb11 /type_size_src1 ; 3760int64_t s12 = nb12 /type_size_src1 ; 3761int64_t s13 = nb13 /type_size_src1 ; 3762ggml_sycl_pool_alloc < sycl::half > src1_f16_alloc (ctx .pool ()); 3763 3764// convert src1 to fp16 3765if (src1 -> type != GGML_TYPE_F16 ) { 3766scope_op_debug_print scope_dbg_print (__func__ ,"/to_fp16_nc_sycl" ,dst ,/*num_src=*/ 2 , 3767" : converting src1 to fp16" ); 3768 3769#if GGML_SYCL_DNNL 3770// iterate tensor dims and find the slowest moving dim and stride 3771int last_dim = 0 ; 3772int last_str = 0 ; 3773size_t largest_str = 0 ; 3774for (int i = 0 ;i < 4 ;i ++ ){ 3775// last stride is always the largest 3776if (src1 -> nb [i ]== largest_str ){ 3777if (src1 -> ne [last_dim ]== 1 ){ 3778last_str = i ; 3779last_dim = i ; 3780 } 3781 } 3782if (src1 -> nb [i ]> largest_str ){ 3783largest_str = src1 -> nb [i ]; 3784last_str = i ; 3785last_dim = i ; 3786 } 3787 3788 } 3789// oneDNN handles strided data and does not need overhead of ggml_get_to_fp16_nc_sycl 3790const int64_t ne_src1 = src1 -> nb [last_str ]* src1 -> ne [last_dim ] /type_size_src1 ; 3791src1_f16_alloc .alloc (ne_src1 ); 3792const to_fp16_sycl_t to_fp16_sycl = ggml_get_to_fp16_sycl (src1 -> type ,dst ); 3793GGML_ASSERT (to_fp16_sycl != nullptr ); 3794to_fp16_sycl (src1_f16 ,src1_f16_alloc .get (),ne_src1 ,queue ); 3795# else 3796const int64_t ne_src1 = ggml_nelements (src1 ); 3797src1_f16_alloc .alloc (ne_src1 ); 3798const to_fp16_nc_sycl_t to_fp16_nc_sycl = ggml_get_to_fp16_nc_sycl (src1 -> type ); 3799GGML_ASSERT (to_fp16_nc_sycl != nullptr ); 3800to_fp16_nc_sycl (src1_f16 ,src1_f16_alloc .get (),ne10 ,ne11 ,ne12 ,ne13 ,s11 ,s12 ,s13 ,queue ); 3801#endif 3802 3803src1_f16 = src1_f16_alloc .get (); 3804s11 = ne10 ; 3805s12 = ne11 * s11 ; 3806s13 = ne12 * s12 ; 3807 3808is_src1_cont_2 = true; 3809 } 3810 3811ggml_sycl_pool_alloc < sycl::half > dst_f16 (ctx .pool ()); 3812 3813 dpct::library_data_t mkl_compute_type = dpct::library_data_t::real_float ; 3814 dpct::library_data_t mkl_data_type = dpct::library_data_t::real_float ; 3815 3816// dst strides 3817size_t nbd2 = dst -> nb [2 ]; 3818size_t nbd3 = dst -> nb [3 ]; 3819 3820const float alpha_f32 = 1.0f ; 3821const float beta_f32 = 0.0f ; 3822 3823const void * alpha = & alpha_f32 ; 3824const void * beta = & beta_f32 ; 3825 3826GGML_ASSERT (ne12 %ne02 == 0 ); 3827GGML_ASSERT (ne13 %ne03 == 0 ); 3828GGML_ASSERT (ne01 == static_cast < int64_t > (nb1 /nb0 )); 3829GGML_ASSERT (ne10 == ne00 ); 3830 3831// broadcast factors 3832const int64_t r2 = ne12 /ne02 ; 3833const int64_t r3 = ne13 /ne03 ; 3834 3835#if GGML_SYCL_DNNL 3836if (g_ggml_sycl_enable_dnn ) { 3837int64_t str_a0 = nb00 /type_size_src0 ; 3838int64_t str_a1 = nb01 /type_size_src0 ; 3839int64_t str_a2 = nb02 /type_size_src0 ; 3840 3841int64_t str_b0 = nb10 /type_size_src1 ; 3842int64_t str_b1 = nb11 /type_size_src1 ; 3843int64_t str_b2 = nb12 /type_size_src1 ; 3844 3845auto launch_gemm_for_batches = [& ctx ,queue ](const sycl::half * src0 , 3846const sycl::half * src1 ,float * dst , 3847int64_t a0 ,int64_t a1 ,int64_t batcha , 3848int64_t /*b0*/ ,int64_t b1 ,int64_t batchb , 3849int64_t sa0 ,int64_t sa1 ,int64_t sa2 , 3850int64_t sb0 ,int64_t sb1 ,int64_t sb2 , 3851int64_t sd2 ) { 3852bool supported_broadcast = batchb == batcha ? true 3853 :batchb == 1 || batcha == 1 ? true 3854 : false; 3855if (supported_broadcast ) { 3856DnnlGemmWrapper ::gemm (ctx ,a1 ,b1 ,a0 ,src0 , 3857DnnlGemmWrapper ::to_dt < sycl::half > (),sa0 ,sa1 ,sa2 ,src1 , 3858DnnlGemmWrapper ::to_dt < sycl::half > (),sb0 ,sb1 ,sb2 ,dst , 3859DnnlGemmWrapper ::to_dt < float > (),queue ,batcha ,batchb ); 3860 }else { 3861// iterate over batches from smaller set of matrices (matrix 0) 3862int64_t batches0 = batcha ; 3863int64_t batches1 = batchb ; 3864 3865if (batches0 > batches1 ) { 3866int64_t num_mul_mats = batches1 ; 3867int64_t sub_batch = batches0 /num_mul_mats ; 3868// src0 is batched and bigger, shift and multiply with src1 3869for (int64_t i0 = 0 ;i0 < num_mul_mats ;i0 ++ ) { 3870const sycl::half * src0_shifted = src0 + (sa2 * i0 * sub_batch ); 3871const sycl::half * src1_shifted = src1 + (sb2 * i0 ); 3872float * dst_shifted = dst + (sd2 * i0 * sub_batch ); 3873DnnlGemmWrapper ::gemm (ctx ,a1 ,b1 ,a0 ,src0_shifted , 3874DnnlGemmWrapper ::to_dt < sycl::half > (),sa0 ,sa1 ,sa2 , 3875src1_shifted ,DnnlGemmWrapper ::to_dt < sycl::half > (),sb0 , 3876sb1 ,sb2 ,dst_shifted ,DnnlGemmWrapper ::to_dt < float > (), 3877queue ,sub_batch ,1 ); 3878 } 3879 }else { 3880int64_t num_mul_mats = batches0 ; 3881int64_t sub_batch = batches1 /num_mul_mats ; 3882// src1 is batched and bigger, shift and multiply with src0 3883for (int64_t i1 = 0 ;i1 < num_mul_mats ;i1 ++ ) { 3884const sycl::half * src0_shifted = src0 + (sa2 * i1 ); 3885const sycl::half * src1_shifted = src1 + (sb2 * i1 * sub_batch ); 3886float * dst_shifted = dst + (sd2 * i1 * sub_batch ); 3887DnnlGemmWrapper ::gemm (ctx ,a1 ,b1 ,a0 ,src0_shifted , 3888DnnlGemmWrapper ::to_dt < sycl::half > (),sa0 ,sa1 ,sa2 , 3889src1_shifted ,DnnlGemmWrapper ::to_dt < sycl::half > (),sb0 , 3890sb1 ,sb2 ,dst_shifted ,DnnlGemmWrapper ::to_dt < float > (), 3891queue ,1 ,sub_batch ); 3892 } 3893 } 3894 } 3895 }; 3896 3897const bool cont_batches_dim2_a = nb02 * ne02 == nb03 ; 3898const bool cont_batches_dim2_b = nb12 * ne12 == nb13 ; 3899const bool cont_batches_dim3_a = ne02 == 1 && nb02 * ne01 == nb03 ; 3900const bool cont_batches_dim3_b = ne12 == 1 && nb12 * ne11 == nb13 ; 3901if (cont_batches_dim2_a && cont_batches_dim2_b ) { 3902// A batch is considered contiguous if the dimension 2 is not strided 3903int64_t batches0 = ne02 * ne03 ; 3904int64_t batches1 = ne12 * ne13 ; 3905launch_gemm_for_batches (src0_f16 ,src1_f16 ,dst_ddf ,ne00 ,ne01 ,batches0 , 3906ne10 ,ne11 ,batches1 ,str_a0 ,str_a1 ,str_a2 ,str_b0 ,str_b1 , 3907str_b2 ,nb2 /sizeof (float )); 3908 }else if (cont_batches_dim3_a && cont_batches_dim3_b ) { 3909// This case is similar to the one above with the difference that only the batch in dimension 3 is used and the dimension 2 is of size 1. 3910int64_t batches0 = ne02 * ne03 ; 3911int64_t batches1 = ne12 * ne13 ; 3912int64_t str_a3 = nb03 /type_size_src0 ; 3913int64_t str_b3 = nb13 /type_size_src1 ; 3914launch_gemm_for_batches (src0_f16 ,src1_f16 ,dst_ddf ,ne00 ,ne01 ,batches0 , 3915ne10 ,ne11 ,batches1 ,str_a0 ,str_a1 ,str_a3 ,str_b0 ,str_b1 , 3916str_b3 ,nb2 /sizeof (float )); 3917 }else { 3918for (int64_t b_a = 0 ;b_a < ne03 ;b_a ++ ) { 3919const sycl::half * src0_f16_shifted 3920= src0_f16 + (nb03 * b_a /type_size_src0 ); 3921const sycl::half * src1_f16_shifted 3922= src1_f16 + (nb13 * b_a /type_size_src1 ); 3923float * dst_shifted = dst_ddf + (nb3 * b_a /sizeof (float )); 3924int64_t batches0 = ne02 ; 3925int64_t batches1 = ne12 ; 3926launch_gemm_for_batches (src0_f16_shifted ,src1_f16_shifted ,dst_shifted , 3927ne00 ,ne01 ,batches0 ,ne10 ,ne11 ,batches1 ,str_a0 ,str_a1 , 3928str_a2 ,str_b0 ,str_b1 ,str_b2 ,nb2 /sizeof (float )); 3929 } 3930 } 3931 3932 } 3933else 3934#endif 3935 { 3936if (r2 == 1 && r3 == 1 && is_src0_cont_2 && is_src1_cont_2 ) { 3937// with a [0, 2, 1, 3] perm. and ne02==1 the matrix strides need to be determined from dim 3: 3938const int64_t sma = ne02 == 1 ?nb03 /nb00 :nb02 /nb00 ; 3939const int64_t smb = ne12 == 1 ?s13 :s12 ; 3940 3941// there is no broadcast and src0, src1 are contiguous across dims 2, 3 3942SYCL_CHECK (CHECK_TRY_ERROR (dpct::gemm_batch (* queue , oneapi::mkl::transpose::trans , 3943 oneapi::mkl::transpose::nontrans ,ne01 ,ne11 ,ne10 ,alpha , 3944src0_f16 , dpct::library_data_t::real_half ,nb01 /nb00 ,sma , 3945src1_f16 , dpct::library_data_t::real_half ,s11 ,smb ,beta ,dst_ddf , 3946mkl_data_type ,ne0 ,ne1 * ne0 ,ne12 * ne13 ,mkl_compute_type ))); 3947 }else { 3948const int ne23 = ne12 * ne13 ; 3949 3950ggml_sycl_pool_alloc < const void *> ptrs_src (ctx .pool (),2 * ne23 ); 3951ggml_sycl_pool_alloc < void *> ptrs_dst (ctx .pool (),1 * ne23 ); 3952ggml_sycl_pool_alloc < matrix_info_t < float >> matrix_info (ctx .host_pool (),1 ); 3953 3954 sycl::range < 3 > block_dims (1 ,ne12 ,ne13 ); 3955queue -> submit ([& ](sycl::handler & cgh ) { 3956const void ** ptrs_src_get = ptrs_src .get (); 3957void ** ptrs_dst_get = ptrs_dst .get (); 3958size_t nb12_scaled = src1 -> type == GGML_TYPE_F16 ?nb12 :s12 * sizeof (sycl::half ); 3959size_t nb13_scaled = src1 -> type == GGML_TYPE_F16 ?nb13 :s13 * sizeof (sycl::half ); 3960cgh .parallel_for (sycl::nd_range < 3 > (block_dims ,block_dims ), [= ](sycl::nd_item < 3 > item_ct1 ) { 3961k_compute_batched_ptrs (src0_f16 ,src1_f16 ,dst_ddf ,ptrs_src_get ,ptrs_dst_get ,ne12 ,ne13 ,ne23 ,nb02 , 3962nb03 ,nb12_scaled ,nb13_scaled ,nbd2 ,nbd3 ,r2 ,r3 ,item_ct1 ); 3963 }); 3964 }); 3965 3966SYCL_CHECK (CHECK_TRY_ERROR (dpct::gemm_batch ( 3967* queue , oneapi::mkl::transpose::trans , oneapi::mkl::transpose::nontrans ,ne01 ,ne11 ,ne10 ,alpha , 3968 (const void ** ) (ptrs_src .get ()+ 0 * ne23 ), dpct::library_data_t::real_half ,nb01 /nb00 , 3969 (const void ** ) (ptrs_src .get ()+ 1 * ne23 ), dpct::library_data_t::real_half ,s11 ,beta , 3970 (void ** ) (ptrs_dst .get ()+ 0 * ne23 ),mkl_data_type ,ne0 ,ne23 ,mkl_compute_type ,matrix_info .get ()))); 3971 } 3972 } 3973}catch (const sycl::exception & exc ) { 3974 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ <<", line:" <<__LINE__ << std::endl ; 3975 std::exit (1 ); 3976} 3977 3978enum class mul_mat_algo { 3979DMMV = 0 , 3980MMVQ = 1 , 3981MUL_MAT_SYCL = 2 , 3982}; 3983 3984inline bool ggml_sycl_supports_mmq (enum ggml_type type ) { 3985// TODO: accuracy issues in MMQ 3986GGML_UNUSED (type ); 3987return false; 3988} 3989 3990inline bool ggml_sycl_supports_reorder_mul_mat_sycl (enum ggml_type type ) { 3991switch (type ) { 3992case GGML_TYPE_Q1_0 : 3993case GGML_TYPE_Q4_0 : 3994case GGML_TYPE_Q8_0 : 3995return true; 3996case GGML_TYPE_Q2_K : 3997case GGML_TYPE_Q3_K : 3998case GGML_TYPE_Q4_K : 3999case GGML_TYPE_Q5_K : 4000case GGML_TYPE_Q6_K : 4001return !g_ggml_sycl_prioritize_dmmv ; 4002default : 4003return false; 4004 } 4005} 4006 4007inline bool ggml_sycl_supports_reorder_dmmv (enum ggml_type type ) { 4008switch (type ) { 4009case GGML_TYPE_Q1_0 : 4010case GGML_TYPE_Q4_0 : 4011case GGML_TYPE_Q8_0 : 4012case GGML_TYPE_Q2_K : 4013case GGML_TYPE_Q3_K : 4014case GGML_TYPE_Q4_K : 4015case GGML_TYPE_Q5_K : 4016case GGML_TYPE_Q6_K : 4017return true; 4018default : 4019return false; 4020 } 4021} 4022 4023inline bool ggml_sycl_supports_reorder_mmvq (enum ggml_type type ) { 4024switch (type ) { 4025case GGML_TYPE_Q1_0 : 4026case GGML_TYPE_Q4_0 : 4027case GGML_TYPE_Q8_0 : 4028case GGML_TYPE_Q2_K : 4029case GGML_TYPE_Q3_K : 4030case GGML_TYPE_Q4_K : 4031case GGML_TYPE_Q5_K : 4032case GGML_TYPE_Q6_K : 4033return true; 4034default : 4035return false; 4036 } 4037} 4038 4039static bool ggml_sycl_supports_reorder_esimd (enum ggml_type type ) { 4040#ifdef GGML_SYCL_DMMV_HAS_ESIMD 4041switch (type ) { 4042case GGML_TYPE_Q2_K : 4043case GGML_TYPE_Q3_K : 4044case GGML_TYPE_Q4_K : 4045case GGML_TYPE_Q5_K : 4046case GGML_TYPE_Q6_K : 4047return true; 4048default : 4049return false; 4050 } 4051#else 4052GGML_UNUSED (type ); 4053return false; 4054#endif 4055} 4056 4057static bool ggml_sycl_supports_dmmv (enum ggml_type type ) { 4058switch (type ) { 4059case GGML_TYPE_Q1_0 : 4060case GGML_TYPE_Q4_0 : 4061case GGML_TYPE_Q4_1 : 4062case GGML_TYPE_Q5_0 : 4063case GGML_TYPE_Q5_1 : 4064case GGML_TYPE_Q8_0 : 4065case GGML_TYPE_Q2_K : 4066case GGML_TYPE_Q3_K : 4067case GGML_TYPE_Q4_K : 4068case GGML_TYPE_Q5_K : 4069case GGML_TYPE_Q6_K : 4070case GGML_TYPE_F16 : 4071case GGML_TYPE_BF16 : 4072return true; 4073default : 4074return false; 4075 } 4076} 4077 4078// Helper functions to unify device memory allocation for both async and sync paths 4079static inline void * sycl_ext_malloc_device (dpct::queue_ptr stream ,size_t size ) { 4080bool use_async = g_ggml_sycl_use_async_mem_op ; 4081#if defined(GGML_SYCL_GRAPH )&& SYCL_EXT_ONEAPI_ASYNC_MEMORY_ALLOC 4082if (use_async ) { 4083void * ptr = syclex::async_malloc (* stream , sycl::usm::alloc::device ,size ); 4084ggml_sycl_memtrace_add (GGML_SYCL_MEM_ASYNC ,ptr ,size ); 4085return ptr ; 4086 } 4087#else 4088// If async allocation extension is not available, use_async should always be false. 4089GGML_ASSERT (!use_async ); 4090#endif 4091return ggml_sycl_malloc_device (size ,* stream ); 4092} 4093 4094static inline void sycl_ext_free (dpct::queue_ptr stream ,void * ptr ) { 4095bool use_async = g_ggml_sycl_use_async_mem_op ; 4096#if defined(GGML_SYCL_GRAPH )&& SYCL_EXT_ONEAPI_ASYNC_MEMORY_ALLOC 4097if (use_async ) { 4098ggml_sycl_memtrace_del (ptr ); 4099 syclex::async_free (* stream ,ptr ); 4100return ; 4101 } 4102#else 4103// If async allocation extension is not available, use_async should always be false. 4104GGML_ASSERT (!use_async ); 4105#endif 4106ggml_sycl_free_device (ptr ,* stream ); 4107} 4108 4109// RAII wrapper for temporary reorder buffers with optional host memory fallback. 4110// When device allocation fails and GGML_SYCL_HOST_MEM_FALLBACK is enabled, 4111// falls back to host memory so the reorder kernel can still run (over PCIe). 4112// Device access to host memory requires Linux kernel 6.8+ (Ubuntu 26.04+). 4113struct sycl_reorder_temp_buffer { 4114void * ptr = nullptr ; 4115 dpct::queue_ptr stream ; 4116 4117sycl_reorder_temp_buffer (dpct::queue_ptr stream ,size_t size ) :stream (stream ) { 4118ptr = sycl_ext_malloc_device (stream ,size ); 4119#ifdef GGML_SYCL_HOST_MEM_FALLBACK 4120if (!ptr ) { 4121ptr = sycl::malloc_host (size ,* stream ); 4122if (ptr ) { 4123host_fallback = true; 4124GGML_LOG_WARN ("%s: device alloc of %zu bytes failed, using host memory fallback\n" ,__func__ ,size ); 4125 } 4126 } 4127#endif 4128 } 4129 4130 ~sycl_reorder_temp_buffer () { 4131if (!ptr ) { 4132return ; 4133 } 4134if (host_fallback ) { 4135 sycl::free (ptr ,* stream ); 4136 }else { 4137sycl_ext_free (stream ,ptr ); 4138 } 4139 } 4140 4141explicit operatorbool ()const {return ptr != nullptr ; } 4142 4143sycl_reorder_temp_buffer (const sycl_reorder_temp_buffer & )= delete ; 4144sycl_reorder_temp_buffer & operator= (const sycl_reorder_temp_buffer & )= delete ; 4145 4146private : 4147bool host_fallback = false; 4148}; 4149 4150static bool reorder_qw_q4_0 (uint8_t * data_device ,const int ncols ,const int nrows ,size_t size ,size_t offset , 4151 dpct::queue_ptr stream ) { 4152sycl_reorder_temp_buffer tmp (stream ,size ); 4153if (!tmp ) { 4154GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4155return false; 4156 } 4157uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4158 4159 sycl::event copy_event ; 4160SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4161if (!g_ggml_sycl_use_async_mem_op ) { 4162copy_event .wait (); 4163 } 4164 4165GGML_ASSERT ((size %sizeof (block_q4_0 )== 0 )); 4166GGML_ASSERT ((offset %sizeof (block_q4_0 )== 0 )); 4167int offset_blks = offset /sizeof (block_q4_0 ); 4168auto qs_ptr = data_device + offset_blks * QK4_0 /2 ; 4169auto d_ptr = (sycl::half * )(qs_ptr + ncols * nrows /2 )+ offset_blks ; 4170 4171auto reorder_event = stream -> parallel_for ( 4172size /sizeof (block_q4_0 ), 4173 [= ](auto i ) [[sycl ::reqd_sub_group_size (WARP_SIZE )]] { 4174const block_q4_0 * x = (const block_q4_0 * )tmp_buf ; 4175const int ib = i ; 4176 4177for (int j = 0 ;j < QK4_0 /2 ;j ++ ) 4178 { 4179* (qs_ptr + ib * QK4_0 /2 + j )= x [ib ].qs [j ]; 4180 } 4181* (d_ptr + ib )= x [ib ].d ; 4182 }); 4183if (!g_ggml_sycl_use_async_mem_op ) { 4184reorder_event .wait_and_throw (); 4185 } 4186return true; 4187} 4188 4189static bool reorder_qw_q8_0 (uint8_t * data_device ,const int ncols ,const int nrows ,size_t size ,size_t offset , 4190 dpct::queue_ptr stream ) { 4191sycl_reorder_temp_buffer tmp (stream ,size ); 4192if (!tmp ) { 4193GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4194return false; 4195 } 4196uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4197 4198 sycl::event copy_event ; 4199SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4200if (!g_ggml_sycl_use_async_mem_op ) { 4201copy_event .wait (); 4202 } 4203 4204GGML_ASSERT ((size %sizeof (block_q8_0 )== 0 )); 4205GGML_ASSERT ((offset %sizeof (block_q8_0 )== 0 )); 4206int offset_blks = offset /sizeof (block_q8_0 ); 4207auto qs_ptr = data_device + offset_blks * QK8_0 ; 4208auto d_ptr = (sycl::half * )(qs_ptr + ncols * nrows )+ offset_blks ; 4209 4210auto reorder_event = stream -> parallel_for ( 4211size /sizeof (block_q8_0 ), 4212 [= ](auto i ) [[sycl ::reqd_sub_group_size (WARP_SIZE )]] { 4213const block_q8_0 * x = (const block_q8_0 * )tmp_buf ; 4214const int ib = i ; 4215 4216for (int j = 0 ;j < QK8_0 ;j ++ ) 4217 { 4218* ((int8_t * )qs_ptr + ib * QK8_0 + j )= x [ib ].qs [j ]; 4219 } 4220* (d_ptr + ib )= x [ib ].d ; 4221 }); 4222if (!g_ggml_sycl_use_async_mem_op ) { 4223reorder_event .wait_and_throw (); 4224 } 4225return true; 4226} 4227 4228static bool reorder_qw_q4_k (uint8_t * data_device ,size_t size ,size_t offset , dpct::queue_ptr stream ) { 4229GGML_ASSERT (size %sizeof (block_q4_K )== 0 ); 4230GGML_ASSERT (offset %sizeof (block_q4_K )== 0 ); 4231 4232const int nblocks = size /sizeof (block_q4_K ); 4233 4234sycl_reorder_temp_buffer tmp (stream ,size ); 4235if (!tmp ) { 4236GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4237return false; 4238 } 4239uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4240 4241 sycl::event copy_event ; 4242SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4243if (!g_ggml_sycl_use_async_mem_op ) { 4244copy_event .wait (); 4245 } 4246 4247auto * qs_ptr = data_device ; 4248auto * scales_ptr = qs_ptr + QK_K /2 * nblocks ; 4249auto * dm_ptr = (sycl::half2 * ) (scales_ptr + K_SCALE_SIZE * nblocks ); 4250 4251auto reorder_event = stream -> parallel_for (nblocks , [= ](auto i ) { 4252const block_q4_K * x = (const block_q4_K * )tmp_buf ; 4253const int ib = i ; 4254 4255for (int j = 0 ;j < QK_K /2 ;++ j ) { 4256qs_ptr [ib * (QK_K /2 )+ j ]= x [ib ].qs [j ]; 4257 } 4258 4259for (int j = 0 ;j < K_SCALE_SIZE ;++ j ) { 4260scales_ptr [ib * K_SCALE_SIZE + j ]= x [ib ].scales [j ]; 4261 } 4262 4263dm_ptr [ib ]= x [ib ].dm ; 4264 }); 4265if (!g_ggml_sycl_use_async_mem_op ) { 4266reorder_event .wait_and_throw (); 4267 } 4268return true; 4269} 4270 4271// Reorder each expert slice into a self-contained SoA layout. 4272static bool reorder_qw_q4_k_moe (uint8_t * data_device ,size_t expert_bytes ,int64_t n_expert , dpct::queue_ptr stream ) { 4273GGML_ASSERT (expert_bytes %sizeof (block_q4_K )== 0 ); 4274const int blocks_per_expert = (int ) (expert_bytes /sizeof (block_q4_K )); 4275const size_t total_bytes = expert_bytes * (size_t )n_expert ; 4276 4277sycl_reorder_temp_buffer tmp (stream ,total_bytes ); 4278if (!tmp ) { 4279GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,total_bytes ); 4280return false; 4281 } 4282uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4283 4284 sycl::event copy_event ; 4285SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,total_bytes ))); 4286if (!g_ggml_sycl_use_async_mem_op ) { 4287copy_event .wait (); 4288 } 4289 4290const int total_blocks = blocks_per_expert * (int )n_expert ; 4291auto reorder_event = stream -> parallel_for (total_blocks , [= ](auto gb_ ) { 4292const int gb = gb_ ; 4293const int e = gb /blocks_per_expert ; 4294const int ib = gb %blocks_per_expert ; 4295const block_q4_K * x = (const block_q4_K * ) (tmp_buf + (size_t )e * expert_bytes ); 4296uint8_t * base = data_device + (size_t )e * expert_bytes ; 4297 4298auto * qs_ptr = base ; 4299auto * scales_ptr = qs_ptr + QK_K /2 * blocks_per_expert ; 4300auto * dm_ptr = (sycl::half2 * ) (scales_ptr + K_SCALE_SIZE * blocks_per_expert ); 4301 4302for (int j = 0 ;j < QK_K /2 ;++ j ) { 4303qs_ptr [ib * (QK_K /2 )+ j ]= x [ib ].qs [j ]; 4304 } 4305for (int j = 0 ;j < K_SCALE_SIZE ;++ j ) { 4306scales_ptr [ib * K_SCALE_SIZE + j ]= x [ib ].scales [j ]; 4307 } 4308dm_ptr [ib ]= x [ib ].dm ; 4309 }); 4310if (!g_ggml_sycl_use_async_mem_op ) { 4311reorder_event .wait_and_throw (); 4312 } 4313return true; 4314} 4315 4316// Reorder each Q5_K expert slice into [qs][qh][scales][dm]. 4317static bool reorder_qw_q5_k_moe (uint8_t * data_device ,size_t expert_bytes ,int64_t n_expert , dpct::queue_ptr stream ) { 4318GGML_ASSERT (expert_bytes %sizeof (block_q5_K )== 0 ); 4319const int blocks_per_expert = (int ) (expert_bytes /sizeof (block_q5_K )); 4320const size_t total_bytes = expert_bytes * (size_t )n_expert ; 4321 4322sycl_reorder_temp_buffer tmp (stream ,total_bytes ); 4323if (!tmp ) { 4324GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,total_bytes ); 4325return false; 4326 } 4327uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4328 4329 sycl::event copy_event ; 4330SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,total_bytes ))); 4331if (!g_ggml_sycl_use_async_mem_op ) { 4332copy_event .wait (); 4333 } 4334 4335const int total_blocks = blocks_per_expert * (int )n_expert ; 4336auto reorder_event = stream -> parallel_for (total_blocks , [= ](auto gb_ ) { 4337const int gb = gb_ ; 4338const int e = gb /blocks_per_expert ; 4339const int ib = gb %blocks_per_expert ; 4340const block_q5_K * x = (const block_q5_K * ) (tmp_buf + (size_t )e * expert_bytes ); 4341uint8_t * base = data_device + (size_t )e * expert_bytes ; 4342 4343auto * qs_ptr = base ; 4344auto * qh_ptr = qs_ptr + (QK_K /2 )* blocks_per_expert ; 4345auto * scales_ptr = qh_ptr + (QK_K /8 )* blocks_per_expert ; 4346auto * dm_ptr = (sycl::half2 * ) (scales_ptr + K_SCALE_SIZE * blocks_per_expert ); 4347 4348for (int j = 0 ;j < QK_K /2 ;++ j ) { 4349qs_ptr [ib * (QK_K /2 )+ j ]= x [ib ].qs [j ]; 4350 } 4351for (int j = 0 ;j < QK_K /8 ;++ j ) { 4352qh_ptr [ib * (QK_K /8 )+ j ]= x [ib ].qh [j ]; 4353 } 4354for (int j = 0 ;j < K_SCALE_SIZE ;++ j ) { 4355scales_ptr [ib * K_SCALE_SIZE + j ]= x [ib ].scales [j ]; 4356 } 4357dm_ptr [ib ]= x [ib ].dm ; 4358 }); 4359if (!g_ggml_sycl_use_async_mem_op ) { 4360reorder_event .wait_and_throw (); 4361 } 4362return true; 4363} 4364 4365// Reorder each Q6_K expert slice into [ql][qh][scales][d]. 4366static bool reorder_qw_q6_k_moe (uint8_t * data_device ,size_t expert_bytes ,int64_t n_expert , dpct::queue_ptr stream ) { 4367GGML_ASSERT (expert_bytes %sizeof (block_q6_K )== 0 ); 4368const int blocks_per_expert = (int ) (expert_bytes /sizeof (block_q6_K )); 4369const size_t total_bytes = expert_bytes * (size_t )n_expert ; 4370 4371sycl_reorder_temp_buffer tmp (stream ,total_bytes ); 4372if (!tmp ) { 4373GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,total_bytes ); 4374return false; 4375 } 4376uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4377 4378 sycl::event copy_event ; 4379SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,total_bytes ))); 4380if (!g_ggml_sycl_use_async_mem_op ) { 4381copy_event .wait (); 4382 } 4383 4384const int total_blocks = blocks_per_expert * (int )n_expert ; 4385auto reorder_event = stream -> parallel_for (total_blocks , [= ](auto gb_ ) { 4386const int gb = gb_ ; 4387const int e = gb /blocks_per_expert ; 4388const int ib = gb %blocks_per_expert ; 4389const block_q6_K * x = (const block_q6_K * ) (tmp_buf + (size_t )e * expert_bytes ); 4390uint8_t * base = data_device + (size_t )e * expert_bytes ; 4391 4392auto * ql_ptr = base ; 4393auto * qh_ptr = ql_ptr + (QK_K /2 )* blocks_per_expert ; 4394auto * scales_ptr = qh_ptr + (QK_K /4 )* blocks_per_expert ; 4395auto * d_ptr = (sycl::half * ) (scales_ptr + (QK_K /16 )* blocks_per_expert ); 4396 4397for (int j = 0 ;j < QK_K /2 ;++ j ) { 4398ql_ptr [ib * (QK_K /2 )+ j ]= x [ib ].ql [j ]; 4399 } 4400for (int j = 0 ;j < QK_K /4 ;++ j ) { 4401qh_ptr [ib * (QK_K /4 )+ j ]= x [ib ].qh [j ]; 4402 } 4403for (int j = 0 ;j < QK_K /16 ;++ j ) { 4404scales_ptr [ib * (QK_K /16 )+ j ]= x [ib ].scales [j ]; 4405 } 4406d_ptr [ib ]= x [ib ].d ; 4407 }); 4408if (!g_ggml_sycl_use_async_mem_op ) { 4409reorder_event .wait_and_throw (); 4410 } 4411return true; 4412} 4413 4414static bool reorder_qw_q2_k (uint8_t * data_device ,size_t size ,size_t offset , dpct::queue_ptr stream ) { 4415GGML_ASSERT (size %sizeof (block_q2_K )== 0 ); 4416GGML_ASSERT (offset %sizeof (block_q2_K )== 0 ); 4417 4418const int nblocks = size /sizeof (block_q2_K ); 4419 4420sycl_reorder_temp_buffer tmp (stream ,size ); 4421if (!tmp ) { 4422GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4423return false; 4424 } 4425uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4426 4427 sycl::event copy_event ; 4428SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4429if (!g_ggml_sycl_use_async_mem_op ) { 4430copy_event .wait (); 4431 } 4432 4433auto * qs_ptr = data_device ; 4434auto * scales_ptr = qs_ptr + (QK_K /4 )* nblocks ; 4435 sycl::half2 * dm_ptr = (sycl::half2 * ) (scales_ptr + (QK_K /16 )* nblocks ); 4436 4437auto reorder_event = stream -> parallel_for (nblocks , [= ](auto i ) { 4438const block_q2_K * x = (const block_q2_K * )tmp_buf ; 4439const int ib = i ; 4440 4441for (int j = 0 ;j < QK_K /4 ;++ j ) { 4442qs_ptr [ib * (QK_K /4 )+ j ]= x [ib ].qs [j ]; 4443 } 4444 4445for (int j = 0 ;j < QK_K /16 ;++ j ) { 4446scales_ptr [ib * (QK_K /16 )+ j ]= x [ib ].scales [j ]; 4447 } 4448 4449dm_ptr [ib ]= x [ib ].dm ; 4450 }); 4451if (!g_ggml_sycl_use_async_mem_op ) { 4452reorder_event .wait_and_throw (); 4453 } 4454return true; 4455} 4456 4457static bool reorder_qw_q3_k (uint8_t * data_device ,size_t size ,size_t offset , dpct::queue_ptr stream ) { 4458GGML_ASSERT (size %sizeof (block_q3_K )== 0 ); 4459GGML_ASSERT (offset %sizeof (block_q3_K )== 0 ); 4460 4461const int nblocks = size /sizeof (block_q3_K ); 4462 4463sycl_reorder_temp_buffer tmp (stream ,size ); 4464if (!tmp ) { 4465GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4466return false; 4467 } 4468uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4469 4470 sycl::event copy_event ; 4471SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4472if (!g_ggml_sycl_use_async_mem_op ) { 4473copy_event .wait (); 4474 } 4475 4476auto * qs_ptr = data_device ; 4477auto * hmask_ptr = qs_ptr + (QK_K /4 )* nblocks ; 4478auto * scales_ptr = hmask_ptr + (QK_K /8 )* nblocks ; 4479 sycl::half * d_ptr = (sycl::half * ) (scales_ptr + 12 * nblocks ); 4480 4481auto reorder_event = stream -> parallel_for (nblocks , [= ](auto i ) { 4482const block_q3_K * x = (const block_q3_K * )tmp_buf ; 4483const int ib = i ; 4484 4485for (int j = 0 ;j < QK_K /4 ;++ j ) { 4486qs_ptr [ib * (QK_K /4 )+ j ]= x [ib ].qs [j ]; 4487 } 4488 4489for (int j = 0 ;j < QK_K /8 ;++ j ) { 4490hmask_ptr [ib * (QK_K /8 )+ j ]= x [ib ].hmask [j ]; 4491 } 4492 4493for (int j = 0 ;j < 12 ;++ j ) { 4494scales_ptr [ib * 12 + j ]= x [ib ].scales [j ]; 4495 } 4496 4497d_ptr [ib ]= x [ib ].d ; 4498 }); 4499if (!g_ggml_sycl_use_async_mem_op ) { 4500reorder_event .wait_and_throw (); 4501 } 4502return true; 4503} 4504 4505static bool reorder_qw_q5_k (uint8_t * data_device ,size_t size ,size_t offset , dpct::queue_ptr stream ) { 4506GGML_ASSERT (size %sizeof (block_q5_K )== 0 ); 4507GGML_ASSERT (offset %sizeof (block_q5_K )== 0 ); 4508 4509const int nblocks = size /sizeof (block_q5_K ); 4510 4511sycl_reorder_temp_buffer tmp (stream ,size ); 4512if (!tmp ) { 4513GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4514return false; 4515 } 4516uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4517 4518 sycl::event copy_event ; 4519SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4520if (!g_ggml_sycl_use_async_mem_op ) { 4521copy_event .wait (); 4522 } 4523 4524auto * qs_ptr = data_device ; 4525auto * qh_ptr = qs_ptr + (QK_K /2 )* nblocks ; 4526auto * scales_ptr = qh_ptr + (QK_K /8 )* nblocks ; 4527auto * dm_ptr = (sycl::half2 * ) (scales_ptr + K_SCALE_SIZE * nblocks ); 4528 4529auto reorder_event = stream -> parallel_for (nblocks , [= ](auto i ) { 4530const block_q5_K * x = (const block_q5_K * )tmp_buf ; 4531const int ib = i ; 4532 4533for (int j = 0 ;j < QK_K /2 ;++ j ) { 4534qs_ptr [ib * (QK_K /2 )+ j ]= x [ib ].qs [j ]; 4535 } 4536 4537for (int j = 0 ;j < QK_K /8 ;++ j ) { 4538qh_ptr [ib * (QK_K /8 )+ j ]= x [ib ].qh [j ]; 4539 } 4540 4541for (int j = 0 ;j < K_SCALE_SIZE ;++ j ) { 4542scales_ptr [ib * K_SCALE_SIZE + j ]= x [ib ].scales [j ]; 4543 } 4544 4545dm_ptr [ib ]= x [ib ].dm ; 4546 }); 4547if (!g_ggml_sycl_use_async_mem_op ) { 4548reorder_event .wait_and_throw (); 4549 } 4550return true; 4551} 4552 4553static bool reorder_qw_q6_k (uint8_t * data_device ,size_t size ,size_t offset , dpct::queue_ptr stream ) { 4554GGML_ASSERT (size %sizeof (block_q6_K )== 0 ); 4555GGML_ASSERT (offset %sizeof (block_q6_K )== 0 ); 4556 4557const int nblocks = size /sizeof (block_q6_K ); 4558 4559sycl_reorder_temp_buffer tmp (stream ,size ); 4560if (!tmp ) { 4561GGML_LOG_WARN ("%s: failed to allocate %zu bytes for reorder temp buffer, skipping reorder\n" ,__func__ ,size ); 4562return false; 4563 } 4564uint8_t * tmp_buf = static_cast < uint8_t *> (tmp .ptr ); 4565 4566 sycl::event copy_event ; 4567SYCL_CHECK (CHECK_TRY_ERROR (copy_event = stream -> memcpy (tmp_buf ,data_device ,size ))); 4568if (!g_ggml_sycl_use_async_mem_op ) { 4569copy_event .wait (); 4570 } 4571 4572auto * ql_ptr = data_device ; 4573auto * qh_ptr = ql_ptr + (QK_K /2 )* nblocks ; 4574auto * scales_ptr = qh_ptr + (QK_K /4 )* nblocks ; 4575 sycl::half * dm_ptr = (sycl::half * ) (scales_ptr + (QK_K /16 )* nblocks ); 4576 4577auto reorder_event = stream -> parallel_for (nblocks , [= ](auto i ) { 4578const block_q6_K * x = (const block_q6_K * )tmp_buf ; 4579const int ib = i ; 4580 4581const uint8_t * ql = x [ib ].ql ; 4582const uint8_t * qh = x [ib ].qh ; 4583uint8_t * base_ql_ptr = ql_ptr + (QK_K /2 )* ib ; 4584uint8_t * base_qh_ptr = qh_ptr + (QK_K /4 )* ib ; 4585uint8_t * base_scales_ptr = scales_ptr + (QK_K /16 )* ib ; 4586 4587for (int j = 0 ;j < QK_K /2 ;++ j ) { 4588base_ql_ptr [j ]= ql [j ]; 4589 } 4590for (int j = 0 ;j < QK_K /4 ;++ j ) { 4591base_qh_ptr [j ]= qh [j ]; 4592 } 4593 4594for (int j = 0 ;j < QK_K /16 ;++ j ) { 4595base_scales_ptr [j ]= x [ib ].scales [j ]; 4596 } 4597 4598dm_ptr [ib ]= x [ib ].d ; 4599 }); 4600if (!g_ggml_sycl_use_async_mem_op ) { 4601reorder_event .wait_and_throw (); 4602 } 4603return true; 4604} 4605 4606static bool reorder_qw (const ggml_tensor * src0 , dpct::queue_ptr stream ) { 4607uint8_t * data_device = (uint8_t * )src0 -> data ; 4608size_t ncols = src0 -> ne [0 ]; 4609size_t nrows = src0 -> ne [1 ]; 4610size_t size = ggml_nbytes (src0 ); 4611 4612// MoE expert weights are addressed per expert via nb[2], so each slice must 4613// remain self-contained after reorder. 4614if (src0 -> ne [2 ]> 1 ) { 4615GGML_ASSERT ((size_t )size == (size_t )src0 -> ne [2 ]* src0 -> nb [2 ]); 4616switch (src0 -> type ) { 4617case GGML_TYPE_Q4_K : 4618return reorder_qw_q4_k_moe (data_device ,src0 -> nb [2 ],src0 -> ne [2 ],stream ); 4619case GGML_TYPE_Q5_K : 4620return reorder_qw_q5_k_moe (data_device ,src0 -> nb [2 ],src0 -> ne [2 ],stream ); 4621case GGML_TYPE_Q6_K : 4622return reorder_qw_q6_k_moe (data_device ,src0 -> nb [2 ],src0 -> ne [2 ],stream ); 4623default : 4624return false; 4625 } 4626 } 4627 4628switch (src0 -> type ) { 4629case GGML_TYPE_Q4_0 : 4630return reorder_qw_q4_0 (data_device ,ncols ,nrows ,size ,0 ,stream ); 4631case GGML_TYPE_Q8_0 : 4632return reorder_qw_q8_0 (data_device ,ncols ,nrows ,size ,0 ,stream ); 4633case GGML_TYPE_Q2_K : 4634return reorder_qw_q2_k (data_device ,size ,0 ,stream ); 4635case GGML_TYPE_Q3_K : 4636return reorder_qw_q3_k (data_device ,size ,0 ,stream ); 4637case GGML_TYPE_Q4_K : 4638return reorder_qw_q4_k (data_device ,size ,0 ,stream ); 4639case GGML_TYPE_Q5_K : 4640return reorder_qw_q5_k (data_device ,size ,0 ,stream ); 4641case GGML_TYPE_Q6_K : 4642return reorder_qw_q6_k (data_device ,size ,0 ,stream ); 4643default : 4644return false; 4645 } 4646} 4647 4648static bool should_reorder_tensor (ggml_backend_sycl_context & ctx ,const ggml_tensor * dst ) { 4649return g_ggml_sycl_enable_optimize && //allow optimize, controlled by $GGML_SYCL_ENABLE_OPT 4650ctx .opt_feature .reorder && //allow this device due to good perf, skip the devices with bad perf. 4651dst -> op == GGML_OP_MUL_MAT && //limit to some supported cases of Q4_0, to do for more cases. 4652// ne[1] <= 8 so multi-column decode (spec / MTP verify) also bootstraps the reorder; 4653// all reorderable types have a _switch_ncols kernel. 4654dst -> src [1 ]-> ne [1 ] <=8 && dst -> src [1 ]-> ne [2 ]== 1 && dst -> src [1 ]-> ne [3 ]== 1 ; 4655} 4656 4657static void opt_for_reorder (ggml_backend_sycl_context * ctx ,const ggml_tensor * src0 ,const ggml_tensor * /* src1 */ , 4658ggml_tensor * dst ,mul_mat_algo mm_algorithm ) { 4659if (!should_reorder_tensor (* ctx ,dst )) { 4660return ; 4661 } 4662 4663ggml_tensor_extra_gpu * extra = static_cast < ggml_tensor_extra_gpu *> (src0 -> extra ); 4664if (!extra || extra -> optimized_feature .reorder ) { 4665return ;// Skip permutations and already reordered tensors 4666 } 4667 4668switch (mm_algorithm ) { 4669case mul_mat_algo::DMMV : 4670if (!ggml_sycl_supports_reorder_dmmv (src0 -> type )) { 4671return ; 4672 } 4673break ; 4674case mul_mat_algo::MMVQ : 4675if (!ggml_sycl_supports_reorder_mmvq (src0 -> type )) { 4676return ; 4677 } 4678break ; 4679case mul_mat_algo::MUL_MAT_SYCL : 4680if (!ggml_sycl_supports_reorder_mul_mat_sycl (src0 -> type )) { 4681return ; 4682 } 4683break ; 4684 } 4685 4686if (reorder_qw (src0 ,ctx -> stream ())) { 4687extra -> optimized_feature .reorder = true;// Used to decode/dequan in next steps and avoid re-reordering 4688 } 4689} 4690 4691// Lazily reorder supported MoE expert weights once their fused path is used. 4692static void opt_for_reorder_id (ggml_backend_sycl_context * ctx ,const ggml_tensor * src0 ) { 4693if (!g_ggml_sycl_enable_optimize || !ctx -> opt_feature .reorder ) { 4694return ; 4695 } 4696if (src0 -> type != GGML_TYPE_Q4_K && src0 -> type != GGML_TYPE_Q5_K && src0 -> type != GGML_TYPE_Q6_K ) { 4697return ; 4698 } 4699ggml_tensor_extra_gpu * extra = static_cast < ggml_tensor_extra_gpu *> (src0 -> extra ); 4700if (!extra || extra -> optimized_feature .reorder ) { 4701return ; 4702 } 4703if (reorder_qw (src0 ,ctx -> stream ())) { 4704extra -> optimized_feature .reorder = true; 4705 } 4706} 4707 4708 4709static bool can_use_dequantize_mul_mat_vec (const ggml_tensor * src0 ,const ggml_tensor * src1 ,ggml_tensor * dst ) { 4710// The F16/BF16 qk=1 kernel iterates with stride 2*DMMV_X, requiring ne[0] to be 4711// a multiple of 2*DMMV_X. Quantized types use block-structured kernels that only 4712// need ne[0] % DMMV_X == 0. 4713const int64_t dmmv_x_required = (src0 -> type == GGML_TYPE_BF16 || src0 -> type == GGML_TYPE_F16 ) ? 47142 * GGML_SYCL_DMMV_X :GGML_SYCL_DMMV_X ; 4715return ggml_sycl_supports_dmmv (src0 -> type )&& src1 -> type == GGML_TYPE_F32 && dst -> type == GGML_TYPE_F32 && 4716src0 -> ne [0 ] %dmmv_x_required == 0 && src1 -> ne [1 ]== 1 ; 4717} 4718 4719static bool can_use_mul_mat_vec_q (const ggml_tensor * src0 ,const ggml_tensor * src1 ,ggml_tensor * dst ) { 4720return ggml_is_quantized (src0 -> type )&& src1 -> type == GGML_TYPE_F32 && dst -> type == GGML_TYPE_F32 && 4721src1 -> ne [1 ] <=MMVQ_MAX_BATCH_SIZE ; 4722} 4723 4724static void ggml_sycl_mul_mat (ggml_backend_sycl_context & ctx ,const ggml_tensor * src0 ,const ggml_tensor * src1 ,ggml_tensor * dst ) { 4725scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 2 ); 4726 4727// Handle HADAMARAD hint given from further up the pipeline and pass it to the correct 4728// kernel. 4729// 4730// The op check is not redundant: this backend also routes MUL_MAT_ID through here with a 4731// stack copy of dst, which carries MUL_MAT_ID's own op_params. ggml_mul_mat_set_hint() 4732// asserts GGML_OP_MUL_MAT for the same reason. 4733if (dst -> op == GGML_OP_MUL_MAT && ggml_get_op_params_i32 (dst ,1 )== GGML_HINT_SRC0_IS_HADAMARD && 4734ggml_sycl_op_fwht (ctx ,src1 ,dst )) { 4735return ; 4736 } 4737 4738const bool split = ggml_backend_buffer_is_sycl_split (src0 -> buffer ); 4739int64_t min_compute_capability = INT_MAX ; 4740 4741if (split ) { 4742ggml_backend_sycl_split_buffer_type_context * buft_ctx = 4743 (ggml_backend_sycl_split_buffer_type_context * )src0 -> buffer -> buft -> context ; 4744auto & tensor_split = buft_ctx -> tensor_split ; 4745for (int id = 0 ;id < ggml_sycl_info ().device_count ;++ id ) { 4746// skip devices that are not going to do any work: 4747if (tensor_split [id ] >= (id + 1 < ggml_sycl_info ().device_count ?tensor_split [id + 1 ] :1.0f )) { 4748continue ; 4749 } 4750 4751if (min_compute_capability > ggml_sycl_info ().devices [id ].cc ) { 4752min_compute_capability = ggml_sycl_info ().devices [id ].cc ; 4753 } 4754 } 4755 }else { 4756min_compute_capability = ggml_sycl_info ().devices [ctx .device ].cc ; 4757 } 4758 4759// check data types and tensor shapes for custom matrix multiplication kernels: 4760bool use_dequantize_mul_mat_vec = can_use_dequantize_mul_mat_vec (src0 ,src1 ,dst ); 4761 4762bool use_mul_mat_vec_q = can_use_mul_mat_vec_q (src0 ,src1 ,dst ); 4763 4764bool use_mul_mat_q = ggml_sycl_supports_mmq (src0 -> type ) 4765&& src1 -> type == GGML_TYPE_F32 && dst -> type == GGML_TYPE_F32 ; 4766 4767 4768// mmvq and mmq need the __dp4a instruction which is available for gen12+ 4769// Workaround in https://github.com/ggml-org/llama.cpp/commit/95f84d5ce8b449a9b16009434aca800df504a02e 4770use_mul_mat_q = use_mul_mat_q && (src0 -> type != GGML_TYPE_IQ2_XXS ); 4771#ifdef SYCL_USE_XMX 4772use_mul_mat_q = use_mul_mat_q && (src1 -> ne [1 ] <=MMQ_MAX_BATCH_SIZE ); 4773#endif // SYCL_USE_XMX 4774 4775// When reorder is enabled, both ESIMD, MMVQ and DMMV kernels may be used. For 4776// best performance use ESIMD when supported, followed by MMVQ, and finally DMMV. 4777// But the reordered ESIMD path cannot be used without reordered MMVQ. A later 4778// multi-token call (ne[1] in 2..8) will take the MMVQ path and it would read the 4779// reordered bytes as if they were still the unreordered layout. 4780 4781if (!g_ggml_sycl_prioritize_dmmv && ((should_reorder_tensor (ctx ,dst )&& 4782ggml_sycl_supports_reorder_mmvq (src0 -> type )))) { 4783bool use = g_ggml_sycl_enable_esimd && ggml_sycl_supports_reorder_esimd (src0 -> type ); 4784// Arc770 get benefit with Q4_0 by skipping MMVQ path 4785if (!(ggml_sycl_info ().devices [ctx .device ].hw_info .arch == 4786 gpu_arch::intel_gpu_acm_g10 && 4787src0 -> type == GGML_TYPE_Q4_0 )) { 4788use = use || !use_mul_mat_vec_q ; 4789 } 4790use_dequantize_mul_mat_vec = use_dequantize_mul_mat_vec && use ; 4791 } 4792 4793if (!split && src0 -> type == GGML_TYPE_F16 && ggml_is_permuted (src0 )&& ggml_is_permuted (src1 )&& src1 -> ne [1 ]== 1 ) { 4794// TODO: Refactor and cleanup of mul mat dispatching. 4795if (src0 -> ne [3 ]== 1 && src1 -> ne [3 ]== 1 ) { 4796// KQ single-batch 4797// mmv p021 was specific for these dimensions 4798ggml_sycl_mul_mat_vec_p021 (ctx ,src0 ,src1 ,dst ); 4799 }else { 4800// The kernel from the if path is faster for that specific case, but does not support all mul mats. 4801ggml_sycl_mul_mat_batched_sycl (ctx ,src0 ,src1 ,dst ); 4802 } 4803 }else if (!split && src0 -> type == GGML_TYPE_F16 && !ggml_is_contiguous (src0 )&& !ggml_is_transposed (src1 )&& src1 -> ne [1 ]== 1 && src1 -> ne [3 ]== 1 ) { 4804// KQV single-batch 4805ggml_sycl_mul_mat_vec_nc (ctx ,src0 ,src1 ,dst ); 4806 }else if (!split && src0 -> type == GGML_TYPE_F16 && !ggml_is_transposed (src0 )&& !ggml_is_transposed (src1 )&& src1 -> ne [2 ]* src1 -> ne [3 ]> 1 ) { 4807// KQ + KQV multi-batch 4808ggml_sycl_mul_mat_batched_sycl (ctx ,src0 ,src1 ,dst ); 4809 }else if (use_dequantize_mul_mat_vec ) { 4810opt_for_reorder (& ctx ,src0 ,src1 ,dst , mul_mat_algo::DMMV ); 4811ggml_sycl_op_mul_mat < no_quantize_q8_1 > (ctx ,src0 ,src1 ,dst ,ggml_sycl_op_dequantize_mul_mat_vec ); 4812 }else if (use_mul_mat_vec_q ) { 4813opt_for_reorder (& ctx ,src0 ,src1 ,dst , mul_mat_algo::MMVQ ); 4814ggml_tensor_extra_gpu * extra = static_cast < ggml_tensor_extra_gpu *> (src0 -> extra ); 4815if (extra && extra -> optimized_feature .reorder ) { 4816ggml_sycl_op_mul_mat < quantize_and_reorder_q8_1_soa > (ctx ,src0 ,src1 ,dst ,ggml_sycl_op_mul_mat_vec_q ); 4817 }else { 4818ggml_sycl_op_mul_mat < quantize_q8_1 > (ctx ,src0 ,src1 ,dst ,ggml_sycl_op_mul_mat_vec_q ); 4819 } 4820 }else if (use_mul_mat_q ) { 4821ggml_sycl_op_mul_mat < quantize_q8_1 > (ctx ,src0 ,src1 ,dst ,ggml_sycl_op_mul_mat_q ); 4822 }else { 4823ggml_sycl_op_mul_mat < no_quantize_q8_1 > (ctx ,src0 ,src1 ,dst ,ggml_sycl_op_mul_mat_sycl ); 4824 } 4825} 4826 4827// Fused dense-FFN mat-vec for the {mul_mat(gate), mul_mat(up), GLU} subgraph at node_idx. 4828// Returns false if it declined, in which case the caller runs the three nodes normally. 4829static bool ggml_sycl_mul_mat_glu_mmvq_fused (ggml_backend_sycl_context & ctx ,ggml_cgraph * cgraph ,int node_idx ) { 4830if (!ggml_sycl_can_fuse (cgraph ,node_idx , {GGML_OP_MUL_MAT ,GGML_OP_MUL_MAT ,GGML_OP_GLU }, {})) { 4831return false; 4832 } 4833 4834ggml_tensor * glu = cgraph -> nodes [node_idx + 2 ]; 4835ggml_tensor * gate = glu -> src [0 ]; 4836ggml_tensor * up = glu -> src [1 ]; 4837const ggml_tensor * wu = up -> src [0 ]; 4838const ggml_tensor * wg = gate -> src [0 ]; 4839const ggml_tensor * act = up -> src [1 ]; 4840 4841// this writes glu->data directly rather than the per-device row slices that 4842// ggml_sycl_op_mul_mat() stitches back together, so it cannot serve split weights 4843if (ggml_backend_buffer_is_sycl_split (wu -> buffer )|| ggml_backend_buffer_is_sycl_split (wg -> buffer )) { 4844return false; 4845 } 4846 4847// with DMMV prioritised the unfused path would not have gone through mmvq at all 4848if (g_ggml_sycl_prioritize_dmmv ) { 4849return false; 4850 } 4851 4852// install the reorder (SoA) layout the fused kernel needs, as the unfused mmvq path would; 4853// a no-op once done. after the bail checks so a declined op does not pay for it. 4854opt_for_reorder (& ctx ,wu ,act ,up , mul_mat_algo::MMVQ ); 4855opt_for_reorder (& ctx ,wg ,act ,gate , mul_mat_algo::MMVQ ); 4856 4857const auto * extra_u = static_cast < const ggml_tensor_extra_gpu *> (wu -> extra ); 4858const auto * extra_g = static_cast < const ggml_tensor_extra_gpu *> (wg -> extra ); 4859if (!extra_u || !extra_g || !extra_u -> optimized_feature .reorder || !extra_g -> optimized_feature .reorder ) { 4860return false; 4861 } 4862 4863// log the up mat-mul: glu's own srcs are the two intermediates the fusion never materialises 4864scope_op_debug_print scope_dbg_print (__func__ ,up ,/*num_src=*/ 2 ," : fused with gate + GLU" ); 4865 4866const int64_t ne00 = wu -> ne [0 ]; 4867const int64_t ne11 = act -> ne [1 ]; 4868 4869const queue_ptr stream = ctx .stream (); 4870const int src1_padded_cols = GGML_PAD ((int )ne00 ,MATRIX_ROW_PADDING ); 4871 4872// one activation, quantized once and fully consumed into src1_ddq before the GEMV on this 4873// in-order queue, so glu->data aliasing the dead activation needs no memory-range check 4874ggml_sycl_pool_alloc < char > src1_q8_alloc (ctx .pool (), 4875 (size_t )ne11 * src1_padded_cols * sizeof (block_q8_1 ) /QK8_1 ); 4876char * src1_ddq = src1_q8_alloc .get (); 4877 4878quantize_row_q8_1_sycl < quantize_and_reorder_q8_1_soa > ((const float * )act -> data ,src1_ddq , (int )ne00 , (int )ne11 , 4879src1_padded_cols ,stream ); 4880 4881return ggml_sycl_mul_mat_vec_q_glu_reorder (wu -> type ,ggml_get_glu_op (glu ),wu -> data ,wg -> data ,src1_ddq , 4882 (float * )glu -> data , (int )ne00 , (int )wu -> ne [1 ], (int )ne11 , 4883/*stride_col_y_bytes=*/ src1_padded_cols * (int )sizeof (block_q8_1 ) / 4884QK8_1 , 4885/*stride_col_dst=*/ (int )glu -> ne [0 ],stream ); 4886} 4887 4888// Batch the run of consecutive L2_NORM siblings starting at node_idx into one launch. 4889// Returns the number of extra graph nodes consumed, or 0 if the run is shorter than two 4890// (the caller then runs the norm through the per-tensor kernel). 4891static int ggml_sycl_l2_norm_batch_fused (ggml_backend_sycl_context & ctx ,ggml_cgraph * cgraph ,int node_idx ) { 4892const ggml_tensor * node = cgraph -> nodes [node_idx ]; 4893if (ggml_sycl_info ().device_count != 1 || node -> type != GGML_TYPE_F32 || 4894node -> src [0 ]-> type != GGML_TYPE_F32 || node -> src [0 ]-> ne [0 ] >=1024 ) { 4895return 0 ; 4896 } 4897 4898ggml_tensor * batch [GGML_SYCL_L2_BATCH_MAX ]; 4899int count = 0 ; 4900int last = node_idx ; 4901float eps0 ; 4902memcpy (& eps0 ,node -> op_params ,sizeof (float )); 4903 4904// Conservative aliasing test: the batched norms run concurrently in one kernel, 4905// so none may read what another writes, and none may write where another writes. 4906auto overlaps = [](const ggml_tensor * a ,const ggml_tensor * b ) { 4907const char * ab = (const char * )a -> data ; 4908const char * bb = (const char * )b -> data ; 4909return ab < bb + ggml_nbytes (b )&& bb < ab + ggml_nbytes (a ); 4910 }; 4911 4912for (int j = node_idx ;j < cgraph -> n_nodes && count < GGML_SYCL_L2_BATCH_MAX ;++ j ) { 4913ggml_tensor * nj = cgraph -> nodes [j ]; 4914if (ggml_is_empty (nj )|| nj -> op == GGML_OP_RESHAPE || nj -> op == GGML_OP_TRANSPOSE || 4915nj -> op == GGML_OP_VIEW || nj -> op == GGML_OP_PERMUTE || nj -> op == GGML_OP_NONE || 4916 (nj -> flags & GGML_TENSOR_FLAG_COMPUTE )== 0 ) { 4917continue ;// not a launch; cannot break a run of adjacent norms 4918 } 4919if (nj -> op != GGML_OP_L2_NORM || nj -> type != GGML_TYPE_F32 || 4920nj -> src [0 ]-> type != GGML_TYPE_F32 || !ggml_are_same_shape (nj ,node )|| 4921 !ggml_are_same_shape (nj -> src [0 ],node -> src [0 ])) { 4922break ;// any other launch ends the run 4923 } 4924bool same_nb = true; 4925for (int d = 0 ;d < GGML_MAX_DIMS ;++ d ) { 4926if (nj -> nb [d ]!= node -> nb [d ]|| nj -> src [0 ]-> nb [d ]!= node -> src [0 ]-> nb [d ]) { 4927same_nb = false; 4928break ; 4929 } 4930 } 4931if (!same_nb ) { 4932break ;// one nb[] stride set is shared by the whole batch 4933 } 4934float epsj ; 4935memcpy (& epsj ,nj -> op_params ,sizeof (float )); 4936if (epsj != eps0 ) { 4937break ;// eps mismatch ends the run 4938 } 4939bool indep = true; 4940for (int k = 0 ;k < count ;++ k ) { 4941if (overlaps (nj -> src [0 ],batch [k ])|| overlaps (nj ,batch [k ])) { 4942indep = false; 4943break ; 4944 } 4945 } 4946if (!indep ) { 4947break ;// an overlapping tensor would race inside one launch 4948 } 4949batch [count ++ ]= nj ; 4950last = j ; 4951 } 4952if (count < 2 ) { 4953return 0 ;// a lone norm falls through to the per-tensor kernel 4954 } 4955ggml_sycl_l2_norm_batch (ctx ,batch ,count ); 4956return last - node_idx ; 4957} 4958 4959 4960__dpct_inline__ static void k_copy_src1_to_contiguous ( 4961const char * __restrict__src1_original ,char * __restrict__src1_contiguous , 4962const mmid_row_mapping * __restrict__row_mapping , 4963int64_t ne11 ,int64_t ne10 ,size_t nb11 ,size_t nb12 , 4964const sycl::nd_item < 3 > & item_ct1 ) { 4965const int32_t src1_row = item_ct1 .get_group (2 ); 4966 4967const int32_t iid1 = row_mapping [src1_row ].i2 ; 4968const int32_t id = row_mapping [src1_row ].i1 ; 4969 4970const int64_t i11 = id %ne11 ; 4971const int64_t i12 = iid1 ; 4972 4973const float * src1_row_original = (const float * )(src1_original + i11 * nb11 + i12 * nb12 ); 4974float * src1_row_contiguous = (float * )(src1_contiguous + src1_row * nb11 ); 4975 4976#pragma unroll 4977for (int i = item_ct1 .get_local_id (2 );i < ne10 ; 4978i += item_ct1 .get_local_range (2 )) { 4979src1_row_contiguous [i ]= src1_row_original [i ]; 4980 } 4981} 4982 4983__dpct_inline__ static void k_copy_dst_from_contiguous ( 4984char * __restrict__dst_original ,const char * __restrict__dst_contiguous , 4985const mmid_row_mapping * __restrict__row_mapping ,int64_t ne0 ,size_t nb1 , 4986size_t nb2 ,const sycl::nd_item < 3 > & item_ct1 ) { 4987int32_t i = item_ct1 .get_group (2 ); 4988 4989const int32_t i1 = row_mapping [i ].i1 ; 4990const int32_t i2 = row_mapping [i ].i2 ; 4991 4992const float * dst_row_contiguous = (const float * )(dst_contiguous + i * nb1 ); 4993float * dst_row_original = (float * )(dst_original + i1 * nb1 + i2 * nb2 ); 4994 4995#pragma unroll 4996for (int j = item_ct1 .get_local_id (2 );j < ne0 ; 4997j += item_ct1 .get_local_range (2 )) { 4998dst_row_original [j ]= dst_row_contiguous [j ]; 4999 } 5000} 5001 5002// Fused MoE TG fast path. Returns false to fall back to the per-expert loop below. 5003static bool ggml_sycl_mul_mat_id_mmvq_fused ( 5004ggml_backend_sycl_context & ctx ,const ggml_tensor * src0 , 5005const ggml_tensor * src1 ,const ggml_tensor * ids ,ggml_tensor * dst ) 5006{ 5007const int64_t ne10 = src1 -> ne [0 ]; 5008const int64_t ne11 = src1 -> ne [1 ]; 5009const int64_t ne12 = src1 -> ne [2 ]; 5010if (ne12 != 1 )return false; 5011if (src1 -> type != GGML_TYPE_F32 || dst -> type != GGML_TYPE_F32 )return false; 5012if (ne10 != src0 -> ne [0 ]|| ne10 %QK8_1 != 0 )return false; 5013if (!ggml_is_contiguous (src1 ))return false; 5014 5015const int64_t n_ids_per_group = ids -> ne [0 ]; 5016if (ids -> ne [1 ]!= 1 )return false; 5017if (ne11 != 1 && ne11 != n_ids_per_group )return false; 5018 5019const queue_ptr stream = ctx .stream (); 5020const int src1_padded_cols = GGML_PAD ((int )ne10 ,MATRIX_ROW_PADDING ); 5021const int n_experts_used = (int )n_ids_per_group ; 5022const int nrows = (int )src0 -> ne [1 ]; 5023 5024// Lazily reorder the (Q4_K) expert weights into a per-expert SoA layout, then run the reorder 5025// GEMV. Placed after the bail checks so a non-dispatchable op does not pay the reorder cost. 5026opt_for_reorder_id (& ctx ,src0 ); 5027const ggml_tensor_extra_gpu * src0_extra = 5028static_cast < const ggml_tensor_extra_gpu *> (src0 -> extra ); 5029const bool use_reorder = src0_extra && src0_extra -> optimized_feature .reorder ; 5030 5031ggml_sycl_pool_alloc < char > src1_q8_alloc (ctx .pool (), 5032 (size_t )ne11 * src1_padded_cols * sizeof (block_q8_1 ) /QK8_1 ); 5033char * src1_ddq = src1_q8_alloc .get (); 5034if (use_reorder ) { 5035quantize_row_q8_1_sycl < quantize_and_reorder_q8_1_soa > ( 5036 (const float * )src1 -> data ,src1_ddq , (int )ne10 , (int )ne11 , 5037src1_padded_cols ,stream ); 5038 }else { 5039quantize_row_q8_1_sycl < quantize_q8_1 > ( 5040 (const float * )src1 -> data ,src1_ddq , (int )ne10 , (int )ne11 , 5041src1_padded_cols ,stream ); 5042 } 5043 5044const size_t bytes_per_qrow = (size_t )src1_padded_cols * sizeof (block_q8_1 ) /QK8_1 ; 5045const size_t src1_row_stride = (ne11 == 1 ) ?0 :bytes_per_qrow ; 5046 5047if (use_reorder ) { 5048return ggml_sycl_mul_mat_vec_q_id_reorder ( 5049src0 -> type ,src0 -> data ,src1_ddq , (const int32_t * )ids -> data , 5050 (float * )dst -> data , (int )ne10 ,nrows ,n_experts_used , 5051/*expert_weight_stride=*/ src0 -> nb [2 ], 5052/*dst_row_stride=*/ dst -> nb [1 ], 5053src1_row_stride ,stream ); 5054 } 5055return ggml_sycl_mul_mat_vec_q_id ( 5056src0 -> type ,src0 -> data ,src1_ddq , (const int32_t * )ids -> data , 5057 (float * )dst -> data , (int )ne10 ,nrows ,n_experts_used , 5058/*expert_weight_stride=*/ src0 -> nb [2 ], 5059/*dst_row_stride=*/ dst -> nb [1 ], 5060src1_row_stride ,stream ); 5061} 5062 5063// counting sort of the routed rows by expert id (row_id_i, as chosen by the router): 5064// builds a projection of a memory layout where each expert's slice is contiguous 5065static void mmid_counting_sort_rows ( 5066const ggml_tensor * ids ,const char * ids_host , 5067int64_t n_ids ,int64_t n_as ,int64_t n_routed_rows , 5068 std::vector < int64_t > & expert_counts , 5069 std::vector < int64_t > & expert_row_offsets , 5070 std::vector < mmid_row_mapping > & routed_row_src ) { 5071 5072// frequencies: how many routed rows each expert "owns" 5073expert_counts .assign (n_as ,0 ); 5074for (int64_t iid1 = 0 ;iid1 < ids -> ne [1 ];iid1 ++ ) { 5075for (int64_t id = 0 ;id < n_ids ;id ++ ) { 5076const int32_t row_id_i = * (const int32_t * ) (ids_host + iid1 * ids -> nb [1 ]+ id * ids -> nb [0 ]); 5077GGML_ASSERT (row_id_i >=0 && row_id_i < n_as ); 5078expert_counts [row_id_i ]++ ; 5079 } 5080 } 5081 5082// where each expert's slice starts (row indices) and the previous ends 5083expert_row_offsets .assign (n_as + 1 ,0 ); 5084for (int64_t i02 = 0 ;i02 < n_as ;i02 ++ ) { 5085expert_row_offsets [i02 + 1 ]= expert_row_offsets [i02 ]+ expert_counts [i02 ]; 5086 } 5087 5088 std::vector < int64_t > expert_row_next = expert_row_offsets ; 5089routed_row_src .resize (n_routed_rows ); 5090for (int64_t iid1 = 0 ;iid1 < ids -> ne [1 ];iid1 ++ ) { 5091for (int64_t id = 0 ;id < n_ids ;id ++ ) { 5092const int32_t row_id_i = * (const int32_t * ) (ids_host + iid1 * ids -> nb [1 ]+ id * ids -> nb [0 ]); 5093GGML_ASSERT (row_id_i >=0 && row_id_i < n_as ); 5094 5095// find and validate the next free row for a given expert (row_id_i) 5096const int64_t routed_row = expert_row_next [row_id_i ]++ ; 5097GGML_ASSERT (routed_row >=expert_row_offsets [row_id_i ]); 5098GGML_ASSERT (routed_row < expert_row_offsets [row_id_i + 1 ]); 5099routed_row_src [routed_row ]= {(int32_t )id , (int32_t )iid1 }; 5100 } 5101 } 5102} 5103 5104static void ggml_sycl_mul_mat_id (ggml_backend_sycl_context & ctx , 5105ggml_tensor * dst )try { 5106scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 3 ); 5107const ggml_tensor * src0 = dst -> src [0 ]; 5108const ggml_tensor * src1 = dst -> src [1 ]; 5109GGML_ASSERT (!ggml_backend_buffer_is_sycl_split (src0 -> buffer )&& "mul_mat_id does not support split buffers" ); 5110 5111const ggml_tensor * ids = dst -> src [2 ]; 5112GGML_TENSOR_BINARY_OP_LOCALS 5113 5114const queue_ptr stream = ctx .stream (); 5115 5116const int64_t n_as = ne02 ; 5117const int64_t n_ids = ids -> ne [0 ]; 5118 5119if (ne12 == 1 ) { 5120if (ggml_sycl_mul_mat_id_mmvq_fused (ctx ,src0 ,src1 ,ids ,dst )) { 5121return ; 5122 } 5123 } 5124 5125 std::vector < char > ids_host (ggml_nbytes (ids )); 5126const char * ids_dev = (const char * )ids -> data ; 5127 5128SYCL_CHECK (CHECK_TRY_ERROR ( 5129stream -> memcpy (ids_host .data (),ids_dev ,ggml_nbytes (ids )))); 5130 5131// also ensures ctx.mmid_row_mapping_host is drained before we use it again 5132SYCL_CHECK (CHECK_TRY_ERROR (stream -> wait ())); 5133 5134ggml_tensor src0_row = * src0 ; 5135ggml_tensor src1_row = * src1 ; 5136ggml_tensor dst_row = * dst ; 5137 5138char * src0_original = (char * )src0 -> data ; 5139char * src1_original = (char * )src1 -> data ; 5140char * dst_original = (char * )dst -> data ; 5141 5142src0_row .ne [2 ]= 1 ; 5143src0_row .ne [3 ]= 1 ; 5144src0_row .nb [3 ]= nb02 ; 5145 5146src1_row .ne [1 ]= 1 ; 5147src1_row .ne [2 ]= 1 ; 5148src1_row .ne [3 ]= 1 ; 5149src1_row .nb [2 ]= nb11 ; 5150src1_row .nb [3 ]= nb11 ; 5151 5152dst_row .ne [1 ]= 1 ; 5153dst_row .ne [2 ]= 1 ; 5154dst_row .ne [3 ]= 1 ; 5155dst_row .nb [2 ]= nb1 ; 5156dst_row .nb [3 ]= nb1 ; 5157if (ne12 == 1 ) { 5158for (int64_t iid1 = 0 ;iid1 < ids -> ne [1 ];iid1 ++ ) { 5159for (int64_t id = 0 ;id < n_ids ;id ++ ) { 5160const int32_t i02 = * (const int32_t * ) (ids_host .data ()+ iid1 * ids -> nb [1 ]+ id * ids -> nb [0 ]); 5161GGML_ASSERT (i02 >=0 && i02 < n_as ); 5162 5163const int64_t i11 = id %ne11 ; 5164const int64_t i12 = iid1 ; 5165 5166const int64_t i1 = id ; 5167const int64_t i2 = i12 ; 5168 5169src0_row .data = src0_original + i02 * nb02 ; 5170src1_row .data = src1_original + i11 * nb11 + i12 * nb12 ; 5171dst_row .data = dst_original + i1 * nb1 + i2 * nb2 ; 5172 5173ggml_sycl_mul_mat (ctx ,& src0_row ,& src1_row ,& dst_row ); 5174 } 5175 } 5176 }else { 5177const int64_t n_routed_rows = ids -> ne [1 ]* n_ids ; 5178ggml_sycl_pool_alloc < char > src1_contiguous (ctx .pool (),sizeof (float )* n_routed_rows * ne10 ); 5179ggml_sycl_pool_alloc < char > dst_contiguous (ctx .pool (),sizeof (float )* n_routed_rows * ne0 ); 5180 5181src1_row .data = src1_contiguous .get (); 5182dst_row .data = dst_contiguous .get (); 5183 5184// how many "owned" routed rows to pass to each expert 5185 std::vector < int64_t > expert_row_counts ; 5186// where each expert's slice starts and the previous ends (row indices, right-exclusive) 5187 std::vector < int64_t > expert_row_offsets ; 5188// the sources (slot/token pairs) of contiguous rows to guide k_copy_src1_to_contiguous 5189 std::vector < mmid_row_mapping > & routed_row_src = ctx .mmid_row_mapping_host ; 5190 5191mmid_counting_sort_rows (ids ,ids_host .data (),n_ids ,n_as ,n_routed_rows , 5192expert_row_counts ,expert_row_offsets ,routed_row_src ); 5193 5194ggml_sycl_pool_alloc < mmid_row_mapping > dev_row_mapping (ctx .pool (),n_routed_rows ); 5195SYCL_CHECK (CHECK_TRY_ERROR ( 5196stream -> memcpy (dev_row_mapping .get (),routed_row_src .data (),n_routed_rows * sizeof (mmid_row_mapping )))); 5197 5198const unsigned int max_work_group_size = ggml_sycl_info ().max_work_group_sizes [ctx .device ]; 5199assert (max_work_group_size % (WARP_SIZE * WARP_SIZE )== 0 ); 5200 5201 { 5202 sycl::range < 3 > block_dims (1 ,1 , std::min ((unsigned int )ne10 ,max_work_group_size )); 5203 sycl::range < 3 > grid_dims (1 ,1 ,n_routed_rows ); 5204stream -> submit ([& ](sycl::handler & cgh ) { 5205char * __restrictsrc1_contiguous_get = 5206src1_contiguous .get (); 5207mmid_row_mapping * __restrictdev_row_mapping_get = 5208dev_row_mapping .get (); 5209 5210cgh .parallel_for ( 5211 sycl::nd_range < 3 > (grid_dims * block_dims ,block_dims ), 5212 [= ](sycl::nd_item < 3 > item_ct1 ) { 5213k_copy_src1_to_contiguous ( 5214src1_original ,src1_contiguous_get , 5215dev_row_mapping_get , 5216ne11 ,ne10 ,nb11 ,nb12 , 5217item_ct1 ); 5218 }); 5219 }); 5220 } 5221 5222for (int64_t i02 = 0 ;i02 < n_as ;i02 ++ ) { 5223const int64_t num_src1_rows = expert_row_counts [i02 ]; 5224 5225if (num_src1_rows == 0 ) { 5226continue ; 5227 } 5228 5229const int64_t expert_row_offset = expert_row_offsets [i02 ]; 5230 5231src0_row .data = src0_original + i02 * nb02 ; 5232 5233GGML_ASSERT (nb11 == sizeof (float )* ne10 ); 5234GGML_ASSERT (nb1 == sizeof (float )* ne0 ); 5235src1_row .data = src1_contiguous .get ()+ expert_row_offset * nb11 ; 5236src1_row .ne [1 ]= num_src1_rows ; 5237 5238src1_row .nb [1 ]= nb11 ; 5239src1_row .nb [2 ]= num_src1_rows * nb11 ; 5240src1_row .nb [3 ]= num_src1_rows * nb11 ; 5241 5242dst_row .data = dst_contiguous .get ()+ expert_row_offset * nb1 ; 5243dst_row .ne [1 ]= num_src1_rows ; 5244dst_row .nb [1 ]= nb1 ; 5245dst_row .nb [2 ]= num_src1_rows * nb1 ; 5246dst_row .nb [3 ]= num_src1_rows * nb1 ; 5247 5248ggml_sycl_mul_mat (ctx ,& src0_row ,& src1_row ,& dst_row ); 5249 } 5250 5251 { 5252 sycl::range < 3 > block_dims (1 ,1 , std::min ((unsigned int )ne0 ,max_work_group_size )); 5253 sycl::range < 3 > grid_dims (1 ,1 ,n_routed_rows ); 5254stream -> submit ([& ](sycl::handler & cgh ) { 5255const char * __restrictdst_contiguous_get = 5256dst_contiguous .get (); 5257const mmid_row_mapping * __restrictdev_row_mapping_get = 5258dev_row_mapping .get (); 5259 5260cgh .parallel_for ( 5261 sycl::nd_range < 3 > (grid_dims * block_dims ,block_dims ), 5262 [= ](sycl::nd_item < 3 > item_ct1 ) { 5263k_copy_dst_from_contiguous (dst_original , 5264dst_contiguous_get , 5265dev_row_mapping_get , 5266ne0 ,nb1 ,nb2 ,item_ct1 ); 5267 }); 5268 }); 5269 } 5270 } 5271} 5272catch (sycl::exception const & exc ) { 5273 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5274 <<", line:" <<__LINE__ << std::endl ; 5275 std::exit (1 ); 5276} 5277 5278static void ggml_sycl_scale (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5279scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5280ggml_sycl_op_scale (ctx ,dst ); 5281} 5282 5283static void ggml_sycl_diag_mask_inf (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5284scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5285ggml_sycl_op_diag_mask_inf (ctx ,dst ); 5286} 5287 5288static void ggml_sycl_pool2d (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5289scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5290ggml_sycl_op_pool2d (ctx ,dst ); 5291} 5292 5293static void ggml_sycl_pool1d (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5294scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5295ggml_sycl_op_pool1d (ctx ,dst ); 5296} 5297 5298static void ggml_sycl_im2col (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5299scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 2 ); 5300ggml_sycl_op_im2col (ctx ,dst ); 5301} 5302 5303static void ggml_sycl_im2col_3d (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5304scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 2 ); 5305ggml_sycl_op_im2col_3d (ctx ,dst ); 5306} 5307 5308static void ggml_sycl_col2im_1d (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5309scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5310ggml_sycl_op_col2im_1d (ctx ,dst ); 5311} 5312 5313static void ggml_sycl_conv_3d (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5314scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 2 ); 5315ggml_sycl_op_conv_3d (ctx ,dst ); 5316} 5317 5318static void ggml_sycl_sum (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5319scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5320GGML_ASSERT (ggml_is_contiguous (dst -> src [0 ])); 5321ggml_sycl_op_sum (ctx ,dst ); 5322} 5323 5324static void ggml_sycl_sum_rows (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5325scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5326GGML_ASSERT (ggml_is_contiguous (dst -> src [0 ])); 5327ggml_sycl_op_sum_rows (ctx ,dst ); 5328} 5329 5330static void ggml_sycl_mean (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5331scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5332GGML_ASSERT (ggml_is_contiguous (dst -> src [0 ])); 5333ggml_sycl_op_mean (ctx ,dst ); 5334} 5335 5336static void ggml_sycl_argsort (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5337scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5338GGML_ASSERT (ggml_is_contiguous (dst -> src [0 ])); 5339ggml_sycl_op_argsort (ctx ,dst ); 5340} 5341 5342static void ggml_sycl_argmax (ggml_backend_sycl_context & ctx ,ggml_tensor * dst ) { 5343scope_op_debug_print scope_dbg_print (__func__ ,dst ,/*num_src=*/ 1 ); 5344GGML_ASSERT (ggml_is_contiguous (dst -> src [0 ])); 5345ggml_sycl_op_argmax (ctx ,dst ); 5346} 5347 5348 5349static void ggml_sycl_set_main_device (const int main_device )try { 5350if (dpct::get_current_device_id ()== static_cast < unsigned int > (main_device )) { 5351return ; 5352 } 5353check_allow_gpu_index (main_device ); 5354 dpct::select_device (main_device ); 5355 5356if (g_ggml_sycl_debug ) { 5357 dpct::device_info prop ; 5358SYCL_CHECK (CHECK_TRY_ERROR (dpct::get_device_info ( 5359prop , dpct::dev_mgr::instance ().get_device (main_device )))); 5360GGML_LOG_INFO ("Using device %d (%s) as main device\n" , 5361main_device ,prop .get_name ()); 5362 } 5363} 5364catch (sycl::exception const & exc ) { 5365 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5366 <<", line:" <<__LINE__ << std::endl ; 5367 std::exit (1 ); 5368} 5369 5370static bool ggml_sycl_compute_forward (ggml_backend_sycl_context & ctx ,struct ggml_tensor * dst )try { 5371GGML_SYCL_DEBUG ("[SYCL] ggml_sycl_compute_forward: dst=%s, op=%s\n" ,dst -> name ,ggml_op_name (dst -> op )); 5372if (!g_sycl_loaded )return false; 5373 5374if (dst -> src [0 ]!= nullptr && ggml_backend_buffer_is_sycl_split (dst -> src [0 ]-> buffer )) { 5375ggml_sycl_set_peer_access (dst -> src [1 ]-> ne [1 ],ctx .device ); 5376 } 5377 5378switch (dst -> op ) { 5379case GGML_OP_ARGMAX : 5380ggml_sycl_argmax (ctx ,dst ); 5381break ; 5382case GGML_OP_CONV_2D : 5383ggml_sycl_op_conv2d (ctx ,dst ); 5384break ; 5385case GGML_OP_CONV_2D_DW : 5386ggml_sycl_op_conv2d_dw (ctx ,dst ); 5387break ; 5388case GGML_OP_CONV_3D : 5389ggml_sycl_conv_3d (ctx ,dst ); 5390break ; 5391case GGML_OP_CONV_TRANSPOSE_1D : 5392ggml_sycl_op_conv_transpose_1d (ctx ,dst ); 5393break ; 5394case GGML_OP_CONV_TRANSPOSE_2D : 5395ggml_sycl_op_conv2d_transpose (ctx ,dst ); 5396break ; 5397case GGML_OP_REPEAT : 5398ggml_sycl_repeat (ctx ,dst ); 5399break ; 5400case GGML_OP_REPEAT_BACK : 5401ggml_sycl_repeat_back (ctx ,dst ); 5402break ; 5403case GGML_OP_GET_ROWS : 5404ggml_sycl_get_rows (ctx ,dst ); 5405break ; 5406case GGML_OP_SET : 5407ggml_sycl_op_set (ctx ,dst ); 5408break ; 5409case GGML_OP_SET_ROWS : 5410ggml_sycl_op_set_rows (ctx ,dst ); 5411break ; 5412case GGML_OP_DSV4_HC_PRE : 5413ggml_sycl_op_dsv4_hc_pre (ctx ,dst ); 5414break ; 5415case GGML_OP_DSV4_HC_COMB : 5416ggml_sycl_op_dsv4_hc_comb (ctx ,dst ); 5417break ; 5418case GGML_OP_DSV4_HC_POST : 5419ggml_sycl_op_dsv4_hc_post (ctx ,dst ); 5420break ; 5421case GGML_OP_LIGHTNING_INDEXER : 5422ggml_sycl_op_lightning_indexer (ctx ,dst ); 5423break ; 5424case GGML_OP_DUP : 5425ggml_sycl_dup (ctx ,dst ); 5426break ; 5427case GGML_OP_ADD : 5428case GGML_OP_ADD1 :// TODO: more efficient implementation 5429ggml_sycl_add (ctx ,dst ); 5430break ; 5431case GGML_OP_ADD_ID : 5432ggml_sycl_add_id (ctx ,dst ); 5433break ; 5434case GGML_OP_SUB : 5435ggml_sycl_sub (ctx ,dst ); 5436break ; 5437case GGML_OP_COUNT_EQUAL : 5438ggml_sycl_count_equal (ctx ,dst ); 5439break ; 5440case GGML_OP_ACC : 5441ggml_sycl_acc (ctx ,dst ); 5442break ; 5443case GGML_OP_MUL : 5444ggml_sycl_mul (ctx ,dst ); 5445break ; 5446case GGML_OP_LOG : 5447ggml_sycl_log (ctx ,dst ); 5448break ; 5449case GGML_OP_DIV : 5450ggml_sycl_div (ctx ,dst ); 5451break ; 5452case GGML_OP_UNARY : 5453switch (ggml_get_unary_op (dst )) { 5454case GGML_UNARY_OP_NEG : 5455ggml_sycl_neg (ctx ,dst ); 5456break ; 5457case GGML_UNARY_OP_STEP : 5458ggml_sycl_step (ctx ,dst ); 5459break ; 5460case GGML_UNARY_OP_GELU : 5461ggml_sycl_gelu (ctx ,dst ); 5462break ; 5463case GGML_UNARY_OP_SILU : 5464ggml_sycl_silu (ctx ,dst ); 5465break ; 5466case GGML_UNARY_OP_GELU_QUICK : 5467ggml_sycl_gelu_quick (ctx ,dst ); 5468break ; 5469case GGML_UNARY_OP_GELU_ERF : 5470ggml_sycl_gelu_erf (ctx ,dst ); 5471break ; 5472case GGML_UNARY_OP_TANH : 5473ggml_sycl_tanh (ctx ,dst ); 5474break ; 5475case GGML_UNARY_OP_RELU : 5476ggml_sycl_relu (ctx ,dst ); 5477break ; 5478case GGML_UNARY_OP_SIGMOID : 5479ggml_sycl_sigmoid (ctx ,dst ); 5480break ; 5481case GGML_UNARY_OP_HARDSIGMOID : 5482ggml_sycl_hardsigmoid (ctx ,dst ); 5483break ; 5484case GGML_UNARY_OP_HARDSWISH : 5485ggml_sycl_hardswish (ctx ,dst ); 5486break ; 5487case GGML_UNARY_OP_EXP : 5488ggml_sycl_exp (ctx ,dst ); 5489break ; 5490case GGML_UNARY_OP_EXPM1 : 5491ggml_sycl_expm1 (ctx ,dst ); 5492break ; 5493case GGML_UNARY_OP_SOFTPLUS : 5494ggml_sycl_softplus (ctx ,dst ); 5495break ; 5496case GGML_UNARY_OP_SGN : 5497ggml_sycl_sgn (ctx ,dst ); 5498break ; 5499case GGML_UNARY_OP_ABS : 5500ggml_sycl_abs (ctx ,dst ); 5501break ; 5502case GGML_UNARY_OP_ELU : 5503ggml_sycl_elu (ctx ,dst ); 5504break ; 5505case GGML_UNARY_OP_XIELU : 5506ggml_sycl_xielu (ctx ,dst ); 5507break ; 5508case GGML_UNARY_OP_FLOOR : 5509ggml_sycl_floor (ctx ,dst ); 5510break ; 5511case GGML_UNARY_OP_CEIL : 5512ggml_sycl_ceil (ctx ,dst ); 5513break ; 5514case GGML_UNARY_OP_ROUND : 5515ggml_sycl_round (ctx ,dst ); 5516break ; 5517case GGML_UNARY_OP_TRUNC : 5518ggml_sycl_trunc (ctx ,dst ); 5519break ; 5520default : 5521return false; 5522 } 5523break ; 5524case GGML_OP_GLU : 5525switch (ggml_get_glu_op (dst )) { 5526case GGML_GLU_OP_REGLU : 5527ggml_sycl_reglu (ctx ,dst ); 5528break ; 5529case GGML_GLU_OP_GEGLU : 5530ggml_sycl_geglu (ctx ,dst ); 5531break ; 5532case GGML_GLU_OP_SWIGLU : 5533ggml_sycl_swiglu (ctx ,dst ); 5534break ; 5535case GGML_GLU_OP_SWIGLU_OAI : 5536ggml_sycl_swiglu_oai (ctx ,dst ); 5537break ; 5538case GGML_GLU_OP_SWIGLU_CLAMP : 5539ggml_sycl_swiglu_clamp (ctx ,dst ); 5540break ; 5541case GGML_GLU_OP_GEGLU_ERF : 5542ggml_sycl_geglu_erf (ctx ,dst ); 5543break ; 5544case GGML_GLU_OP_GEGLU_QUICK : 5545ggml_sycl_geglu_quick (ctx ,dst ); 5546break ; 5547default : 5548return false; 5549 } 5550break ; 5551case GGML_OP_NORM : 5552ggml_sycl_norm (ctx ,dst ); 5553break ; 5554case GGML_OP_GROUP_NORM : 5555ggml_sycl_group_norm (ctx ,dst ); 5556break ; 5557case GGML_OP_CONCAT : 5558ggml_sycl_op_concat (ctx ,dst ); 5559break ; 5560case GGML_OP_PAD_REFLECT_1D : 5561ggml_sycl_op_pad_reflect_1d (ctx ,dst ); 5562break ; 5563case GGML_OP_UPSCALE : 5564ggml_sycl_upscale (ctx ,dst ); 5565break ; 5566case GGML_OP_PAD : 5567ggml_sycl_pad (ctx ,dst ); 5568break ; 5569case GGML_OP_LEAKY_RELU : 5570ggml_sycl_leaky_relu (ctx ,dst ); 5571break ; 5572case GGML_OP_RMS_NORM_BACK : 5573ggml_sycl_rms_norm_back (ctx ,dst ); 5574break ; 5575case GGML_OP_RMS_NORM : 5576ggml_sycl_rms_norm (ctx ,dst ); 5577break ; 5578case GGML_OP_L2_NORM : 5579ggml_sycl_l2_norm (ctx ,dst ); 5580break ; 5581case GGML_OP_MUL_MAT : 5582if (dst -> src [0 ]-> ne [3 ]!= dst -> src [1 ]-> ne [3 ]) { 5583return false; 5584 } 5585/* ggml_sycl_mul_mat_id is dependent on ggml_sycl_mul_mat */ 5586ggml_sycl_mul_mat (ctx ,dst -> src [0 ],dst -> src [1 ],dst ); 5587break ; 5588case GGML_OP_MUL_MAT_ID : 5589if (dst -> src [0 ]-> ne [3 ]!= dst -> src [1 ]-> ne [3 ]) { 5590return false; 5591 } 5592ggml_sycl_mul_mat_id (ctx ,dst ); 5593break ; 5594case GGML_OP_OUT_PROD : 5595ggml_sycl_op_out_prod (ctx ,dst ); 5596break ; 5597case GGML_OP_SCALE : 5598ggml_sycl_scale (ctx ,dst ); 5599break ; 5600case GGML_OP_SQR : 5601ggml_sycl_sqr (ctx ,dst ); 5602break ; 5603case GGML_OP_SQRT : 5604ggml_sycl_sqrt (ctx ,dst ); 5605break ; 5606case GGML_OP_SIN : 5607ggml_sycl_sin (ctx ,dst ); 5608break ; 5609case GGML_OP_COS : 5610ggml_sycl_cos (ctx ,dst ); 5611break ; 5612case GGML_OP_CLAMP : 5613ggml_sycl_clamp (ctx ,dst ); 5614break ; 5615case GGML_OP_CPY : 5616ggml_sycl_cpy (ctx ,dst -> src [0 ],dst -> src [1 ]); 5617break ; 5618case GGML_OP_CONT : 5619ggml_sycl_dup (ctx ,dst ); 5620break ; 5621case GGML_OP_NONE : 5622case GGML_OP_RESHAPE : 5623case GGML_OP_VIEW : 5624case GGML_OP_PERMUTE : 5625case GGML_OP_TRANSPOSE : 5626GGML_SYCL_DEBUG ("%s: Tensor NO-OP\n" ,__func__ ); 5627break ; 5628case GGML_OP_TRI : 5629ggml_sycl_op_tri (ctx ,dst ); 5630break ; 5631case GGML_OP_DIAG_MASK_INF : 5632ggml_sycl_diag_mask_inf (ctx ,dst ); 5633break ; 5634case GGML_OP_SOFT_MAX : 5635ggml_sycl_op_soft_max (ctx ,dst ); 5636break ; 5637case GGML_OP_SOFT_MAX_BACK : 5638ggml_sycl_op_soft_max_back (ctx ,dst ); 5639break ; 5640case GGML_OP_CROSS_ENTROPY_LOSS : 5641ggml_sycl_cross_entropy_loss (ctx ,dst ); 5642break ; 5643case GGML_OP_CROSS_ENTROPY_LOSS_BACK : 5644ggml_sycl_cross_entropy_loss_back (ctx ,dst ); 5645break ; 5646case GGML_OP_ROPE : 5647ggml_sycl_rope (ctx ,dst ); 5648break ; 5649case GGML_OP_ROPE_BACK : 5650ggml_sycl_rope_back (ctx ,dst ); 5651break ; 5652case GGML_OP_IM2COL : 5653ggml_sycl_im2col (ctx ,dst ); 5654break ; 5655case GGML_OP_IM2COL_3D : 5656ggml_sycl_im2col_3d (ctx ,dst ); 5657break ; 5658case GGML_OP_COL2IM_1D : 5659ggml_sycl_col2im_1d (ctx ,dst ); 5660break ; 5661case GGML_OP_POOL_2D : 5662ggml_sycl_pool2d (ctx ,dst ); 5663break ; 5664case GGML_OP_POOL_1D : 5665ggml_sycl_pool1d (ctx ,dst ); 5666break ; 5667case GGML_OP_SUM : 5668ggml_sycl_sum (ctx ,dst ); 5669break ; 5670case GGML_OP_SUM_ROWS : 5671ggml_sycl_sum_rows (ctx ,dst ); 5672break ; 5673case GGML_OP_MEAN : 5674ggml_sycl_mean (ctx ,dst ); 5675break ; 5676case GGML_OP_ARGSORT : 5677ggml_sycl_argsort (ctx ,dst ); 5678break ; 5679case GGML_OP_TOP_K : 5680ggml_sycl_op_top_k (ctx ,dst ); 5681break ; 5682case GGML_OP_TIMESTEP_EMBEDDING : 5683ggml_sycl_op_timestep_embedding (ctx ,dst ); 5684break ; 5685case GGML_OP_RWKV_WKV6 : 5686ggml_sycl_op_rwkv_wkv6 (ctx ,dst ); 5687break ; 5688case GGML_OP_RWKV_WKV7 : 5689ggml_sycl_op_rwkv_wkv7 (ctx ,dst ); 5690break ; 5691case GGML_OP_GATED_LINEAR_ATTN : 5692ggml_sycl_op_gated_linear_attn (ctx ,dst ); 5693break ; 5694case GGML_OP_GATED_DELTA_NET : 5695ggml_sycl_gated_delta_net (ctx ,dst ); 5696break ; 5697case GGML_OP_OPT_STEP_ADAMW : 5698ggml_sycl_opt_step_adamw (ctx ,dst ); 5699break ; 5700case GGML_OP_OPT_STEP_SGD : 5701ggml_sycl_opt_step_sgd (ctx ,dst ); 5702break ; 5703case GGML_OP_SSM_CONV : 5704ggml_sycl_ssm_conv (ctx ,dst ); 5705break ; 5706case GGML_OP_SSM_SCAN : 5707ggml_sycl_ssm_scan (ctx ,dst ); 5708break ; 5709case GGML_OP_FILL : 5710ggml_sycl_fill (ctx ,dst ); 5711break ; 5712case GGML_OP_CUMSUM : 5713ggml_sycl_cumsum (ctx ,dst ); 5714break ; 5715case GGML_OP_DIAG : 5716ggml_sycl_diag (ctx ,dst ); 5717break ; 5718case GGML_OP_SOLVE_TRI : 5719ggml_sycl_solve_tri (ctx ,dst ); 5720break ; 5721case GGML_OP_ROLL : 5722ggml_sycl_roll (ctx ,dst ); 5723break ; 5724case GGML_OP_ARANGE : 5725ggml_sycl_arange (ctx ,dst ); 5726break ; 5727case GGML_OP_FLASH_ATTN_EXT : 5728ggml_sycl_flash_attn_ext (ctx ,dst ); 5729break ; 5730default : 5731return false; 5732 } 5733 5734return true; 5735}catch (sycl::exception & e ) { 5736 std::cerr <<e .what () <<"Exception caught at file:" <<__FILE__ <<", line:" <<__LINE__ << std::endl ; 5737 std::cerr <<"Error OP " <<ggml_op_name (dst -> op )<< std::endl ; 5738 std::exit (1 ); 5739} 5740 5741GGML_API void ggml_backend_sycl_get_device_description (int device ,char * description , 5742size_t description_size )try { 5743GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_get_device_description\n" ); 5744 dpct::device_info prop ; 5745SYCL_CHECK (CHECK_TRY_ERROR (dpct::get_device_info ( 5746prop , dpct::dev_mgr::instance ().get_device (device )))); 5747snprintf (description ,description_size ,"%s" ,prop .get_name ()); 5748} 5749catch (sycl::exception const & exc ) { 5750 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5751 <<", line:" <<__LINE__ << std::endl ; 5752 std::exit (1 ); 5753} 5754 5755bool sycl_get_mem_info (int device ,size_t * free ,size_t * total ) { 5756GGML_SYCL_DEBUG ("[SYCL] [%s] g_ggml_sycl_get_mem_api=%d\n" , 5757__func__ ,g_ggml_sycl_get_mem_api ); 5758 5759MemoryAPIType mem_api_type = MemoryAPIType ::MEMORY_API_TYPE_SYCL ; 5760 5761#ifdef GGML_SYCL_SUPPORT_LEVEL_ZERO_API 5762mem_api_type = get_zes_init_res ()== ZE_RESULT_SUCCESS ? 5763 (MemoryAPIType )g_ggml_sycl_get_mem_api :MemoryAPIType ::MEMORY_API_TYPE_SYCL ; 5764#else 5765mem_api_type = MemoryAPIType ::MEMORY_API_TYPE_SYCL ; 5766#endif 5767bool res = get_memory_size (dpct::dev_mgr::instance ().get_device (device ), 5768* free ,* total ,mem_api_type ); 5769GGML_SYCL_DEBUG ("[SYCL] [%s] total = %zu free = %zu\n" ,__func__ ,* total ,* free ); 5770return res ; 5771} 5772 5773void ggml_backend_sycl_get_device_memory (int device ,size_t * free ,size_t * total )try { 5774GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_get_device_memory\n" ); 5775if (!sycl_get_mem_info (device ,free ,total )) { 5776GGML_ABORT ("[%s] failed to get device memory size" ,__func__ ); 5777 } 5778ggml_sycl_memtrace_report_device ("device memory query" ,device ,* free ,* total ); 5779}catch (const sycl::exception & exc ) { 5780 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ <<", line:" <<__LINE__ << std::endl ; 5781 std::exit (1 ); 5782} 5783 5784//////////////////////////////////////////////////////////////////////////////// 5785 5786// backend 5787 5788static const char * ggml_backend_sycl_get_name (ggml_backend_t backend ) { 5789 5790ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context * )backend -> context ; 5791 5792return sycl_ctx -> name .c_str (); 5793} 5794 5795static void ggml_backend_sycl_free (ggml_backend_t backend ) { 5796ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context * )backend -> context ; 5797 5798delete sycl_ctx ; 5799delete backend ; 5800} 5801 5802static void ggml_backend_sycl_set_tensor_async (ggml_backend_t backend , 5803ggml_tensor * tensor , 5804const void * data ,size_t offset , 5805size_t size )try { 5806GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 5807GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 5808GGML_SYCL_DEBUG (" size=%zu offset=%zu\n" ,size ,offset ); 5809ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context * )backend -> context ; 5810ggml_backend_buffer_t buf = tensor -> view_src ?tensor -> view_src -> buffer :tensor -> buffer ; 5811 5812GGML_ASSERT (buf -> buft == ggml_backend_sycl_buffer_type (sycl_ctx -> device )&& "unsupported buffer type" ); 5813const queue_ptr stream = sycl_ctx -> stream (sycl_ctx -> device ,0 ); 5814SYCL_CHECK (CHECK_TRY_ERROR ( 5815 (stream )-> memcpy ((char * )tensor -> data + offset ,data ,size ))); 5816} 5817catch (sycl::exception const & exc ) { 5818 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5819 <<", line:" <<__LINE__ << std::endl ; 5820 std::exit (1 ); 5821} 5822 5823static void ggml_backend_sycl_get_tensor_async (ggml_backend_t backend , 5824const ggml_tensor * tensor , 5825void * data ,size_t offset , 5826size_t size )try { 5827GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 5828GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": tensor" ,tensor ).c_str ()); 5829GGML_SYCL_DEBUG (" size=%zu offset=%zu\n" ,size ,offset ); 5830ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context * )backend -> context ; 5831ggml_backend_buffer_t buf = tensor -> view_src ?tensor -> view_src -> buffer :tensor -> buffer ; 5832 5833GGML_ASSERT (buf -> buft == ggml_backend_sycl_buffer_type (sycl_ctx -> device )&& "unsupported buffer type" ); 5834const queue_ptr stream = sycl_ctx -> stream (sycl_ctx -> device ,0 ); 5835SYCL_CHECK (CHECK_TRY_ERROR ((stream )-> memcpy ( 5836data , (const char * )tensor -> data + offset ,size ))); 5837} 5838catch (sycl::exception const & exc ) { 5839 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5840 <<", line:" <<__LINE__ << std::endl ; 5841 std::exit (1 ); 5842} 5843 5844static bool ggml_backend_sycl_cpy_tensor_async (ggml_backend_t backend , 5845const ggml_tensor * src , 5846ggml_tensor * dst )try { 5847ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context * )backend -> context ; 5848bool is_cpy_supported = dst -> buffer -> buft == ggml_backend_sycl_buffer_type (sycl_ctx -> device )&& 5849ggml_backend_buffer_is_sycl (src -> buffer ); 5850GGML_SYCL_DEBUG ("[SYCL] call %s" ,__func__ ); 5851GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (": dst" ,dst ).c_str ()); 5852GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (" src" ,src ).c_str ()); 5853GGML_SYCL_DEBUG (" is_cpy_supported=%d\n" ,is_cpy_supported ); 5854if (is_cpy_supported ) { 5855/* 5856DPCT1009:215: SYCL uses exceptions to report errors and does not use the 5857error codes. The original code was commented out and a warning string 5858was inserted. You need to rewrite this code. 5859*/ 5860const queue_ptr stream = sycl_ctx -> stream (sycl_ctx -> device ,0 ); 5861SYCL_CHECK (CHECK_TRY_ERROR ((stream )-> memcpy ( 5862dst -> data ,src -> data ,ggml_nbytes (dst )))); 5863return true; 5864 } 5865 5866return false; 5867} 5868catch (sycl::exception const & exc ) { 5869 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5870 <<", line:" <<__LINE__ << std::endl ; 5871 std::exit (1 ); 5872} 5873 5874static void ggml_backend_sycl_synchronize (ggml_backend_t backend )try { 5875GGML_SYCL_DEBUG ("[SYCL] call %s\n" ,__func__ ); 5876ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context * )backend -> context ; 5877const queue_ptr stream = sycl_ctx -> stream (sycl_ctx -> device ,0 ); 5878SYCL_CHECK (CHECK_TRY_ERROR ((stream )-> wait ())); 5879 5880GGML_UNUSED (backend ); 5881} 5882catch (sycl::exception const & exc ) { 5883 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 5884 <<", line:" <<__LINE__ << std::endl ; 5885 std::exit (1 ); 5886} 5887 5888static bool ggml_sycl_is_view_or_noop (const ggml_tensor * t ) { 5889return ggml_is_empty (t )|| t -> op == GGML_OP_RESHAPE || t -> op == GGML_OP_TRANSPOSE || 5890t -> op == GGML_OP_VIEW || t -> op == GGML_OP_PERMUTE || t -> op == GGML_OP_NONE ; 5891} 5892 5893// match gated_delta_net + the strided cpy that scatters its state snapshots into the cache 5894// (slot i -> rollback group i, slot 0 newest), so the kernel can write them and skip the cpy. 5895// returns the number of following nodes to skip (0 = no fusion) 5896// ported from ggml_cuda_try_gdn_cache_fusion - pure graph inspection, backend-agnostic 5897static int ggml_sycl_try_gdn_cache_fusion (const ggml_cgraph * cgraph ,int node_idx , 5898ggml_sycl_gated_delta_net_fused_cache & fused_state_cpy ) { 5899if (!g_ggml_sycl_enable_fusion ) { 5900return 0 ; 5901 } 5902 5903const ggml_tensor * gdn = cgraph -> nodes [node_idx ]; 5904// the kernel skips the snapshot tail, so the gdn output must not be a graph output, and the cpy 5905// found below is taken to be its only reader, as it is in every graph that builds this op 5906if (gdn -> op != GGML_OP_GATED_DELTA_NET || gdn -> type != GGML_TYPE_F32 || 5907 (gdn -> flags & GGML_TENSOR_FLAG_OUTPUT )) { 5908return 0 ; 5909 } 5910 5911const ggml_tensor * src_v = gdn -> src [2 ]; 5912const int64_t S_v = src_v -> ne [0 ]; 5913const int64_t H = src_v -> ne [1 ]; 5914const int64_t n_tokens = src_v -> ne [2 ]; 5915const int64_t n_seqs = src_v -> ne [3 ]; 5916const int64_t D = S_v * S_v * H ; 5917const int64_t K = ggml_get_op_params_i32 (gdn ,0 );// snapshot slot count 5918const int64_t n_written = std::min < int64_t > (n_tokens ,K );// newest n_written slots are written 5919 5920// snapshot tail starts right after the attention scores 5921const size_t tail_off = ggml_row_size (GGML_TYPE_F32 ,S_v * H * n_tokens * n_seqs ); 5922 5923// the cpy must be the first node the compute loop below runs, so nothing can read the cache first. 5924// skip exactly what that loop skips: views, no-ops, and nodes the graph does not compute. 5925const ggml_tensor * cpy = nullptr ; 5926int skip = 0 ; 5927for (int j = node_idx + 1 ;j < cgraph -> n_nodes && cpy == nullptr ;++ j ) { 5928const ggml_tensor * n = cgraph -> nodes [j ]; 5929if (ggml_sycl_is_view_or_noop (n )|| (n -> flags & GGML_TENSOR_FLAG_COMPUTE )== 0 ) { 5930continue ; 5931 } 5932if (n -> op != GGML_OP_CPY || (n -> flags & GGML_TENSOR_FLAG_OUTPUT )) { 5933return 0 ; 5934 } 5935cpy = n ; 5936skip = j - node_idx ; 5937 } 5938if (cpy == nullptr ) { 5939return 0 ; 5940 } 5941 5942const ggml_tensor * src = cpy -> src [0 ];// view of the gdn snapshot tail 5943const ggml_tensor * dst = cpy -> src [1 ];// cache view the kernel writes to 5944 5945// src must be this gdn's snapshot tail (contiguous, at the tail offset) 5946if (src -> op != GGML_OP_VIEW || src -> view_src != gdn || src -> view_offs != tail_off || 5947 !ggml_is_contiguous (src )) { 5948return 0 ; 5949 } 5950 5951// dst is the [D, n_seqs, n_written] cache view, with the per-seq stride D that the kernel assumes. 5952// ggml_cpy pins src to the same element count, so src needs no shape check of its own. 5953const std::array < int64_t ,GGML_MAX_DIMS > expected_ne = {D ,n_seqs ,n_written ,1 }; 5954if (dst -> op != GGML_OP_VIEW || dst -> type != GGML_TYPE_F32 || dst -> data == nullptr || 5955 !std::equal (expected_ne .begin (),expected_ne .end (),dst -> ne )|| 5956dst -> nb [0 ]!= ggml_type_size (GGML_TYPE_F32 )|| 5957dst -> nb [1 ]!= (size_t )ggml_row_size (GGML_TYPE_F32 ,D )) { 5958return 0 ; 5959 } 5960 5961fused_state_cpy .data = (float * )dst -> data ;// rollback group 0 (newest) 5962fused_state_cpy .slot_stride = K > 1 ? (int64_t ) (dst -> nb [2 ] /sizeof (float )) :0 ; 5963return skip ; 5964} 5965 5966static void ggml_backend_sycl_graph_compute_impl (ggml_backend_sycl_context * sycl_ctx ,ggml_cgraph * cgraph ) { 5967ggml_sycl_set_main_device (sycl_ctx -> device ); 5968 5969for (int i = 0 ;i < cgraph -> n_nodes ;i ++ ) { 5970ggml_tensor * node = cgraph -> nodes [i ]; 5971if (ggml_sycl_is_view_or_noop (node )) { 5972continue ; 5973 } 5974if ((node -> flags & GGML_TENSOR_FLAG_COMPUTE )== 0 ) { 5975continue ; 5976 } 5977 5978const int nodes_to_skip = ggml_sycl_fuse (* sycl_ctx ,cgraph ,i ); 5979if (nodes_to_skip != 0 ) { 5980i += nodes_to_skip ; 5981continue ; 5982 } 5983#ifndef NDEBUG 5984assert (node -> buffer -> buft == ggml_backend_sycl_buffer_type (sycl_ctx -> device )); 5985for (int j = 0 ;j < GGML_MAX_SRC ;j ++ ) { 5986if (node -> src [j ]!= nullptr ) { 5987assert (node -> src [j ]-> buffer -> buft == ggml_backend_sycl_buffer_type (sycl_ctx -> device )); 5988 } 5989 } 5990#endif 5991// gated_delta_net -> cpy: scatter recurrent-state snapshots into the cache 5992if (node -> op == GGML_OP_GATED_DELTA_NET ) { 5993ggml_sycl_gated_delta_net_fused_cache fused_state_cpy ; 5994const int gdn_nodes_to_skip = ggml_sycl_try_gdn_cache_fusion (cgraph ,i ,fused_state_cpy ); 5995if (gdn_nodes_to_skip > 0 ) { 5996ggml_sycl_op_gated_delta_net_fused_cache (* sycl_ctx ,node ,fused_state_cpy ); 5997i += gdn_nodes_to_skip ; 5998continue ; 5999 } 6000 } 6001if (node -> op == GGML_OP_RMS_NORM && 6002ggml_sycl_can_fuse (cgraph ,i , {GGML_OP_RMS_NORM ,GGML_OP_MUL ,GGML_OP_ADD }, {})) { 6003ggml_sycl_op_rms_norm_fused_add (* sycl_ctx ,node ,cgraph -> nodes [i + 1 ],cgraph -> nodes [i + 2 ]); 6004i += 2 ; 6005continue ; 6006 } 6007if (node -> op == GGML_OP_RMS_NORM && 6008ggml_sycl_can_fuse (cgraph ,i , {GGML_OP_RMS_NORM ,GGML_OP_MUL }, {})) { 6009ggml_sycl_op_rms_norm_fused (* sycl_ctx ,node ,cgraph -> nodes [i + 1 ]); 6010i ++ ; 6011continue ; 6012 } 6013if (node -> op == GGML_OP_ADD && 6014ggml_sycl_can_fuse (cgraph ,i , {GGML_OP_ADD ,GGML_OP_ADD }, {})) { 6015ggml_sycl_op_add_add_fused (* sycl_ctx ,node ,cgraph -> nodes [i + 1 ]); 6016i ++ ; 6017continue ; 6018 } 6019if (node -> op == GGML_OP_UNARY && 6020ggml_sycl_can_fuse (cgraph ,i , {GGML_OP_UNARY ,GGML_OP_MUL }, {ggml_get_unary_op (node ) })) { 6021ggml_sycl_op_unary_mul_fused (* sycl_ctx ,node ,cgraph -> nodes [i + 1 ]); 6022i ++ ; 6023continue ; 6024 } 6025 6026// Batch consecutive independent same-shape F32 L2_NORM siblings (the GDN q/k 6027// norms) into one launch; sources are strided views of the fused qkv buffer, so 6028// the scan skips the interleaved view nodes instead of breaking on them. 6029if (node -> op == GGML_OP_L2_NORM ) { 6030const int l2_batch_skip = ggml_sycl_l2_norm_batch_fused (* sycl_ctx ,cgraph ,i ); 6031if (l2_batch_skip > 0 ) { 6032i += l2_batch_skip ; 6033continue ; 6034 } 6035 } 6036 6037if (node -> op == GGML_OP_MUL_MAT && ggml_sycl_mul_mat_glu_mmvq_fused (* sycl_ctx ,cgraph ,i )) { 6038i += 2 ; 6039continue ; 6040 } 6041 6042bool ok = ggml_sycl_compute_forward (* sycl_ctx ,node ); 6043if (!ok ) { 6044GGML_LOG_ERROR ("%s: error: op not supported %s (%s)\n" ,__func__ ,node -> name ,ggml_op_name (node -> op )); 6045 } 6046GGML_ASSERT (ok ); 6047 } 6048} 6049 6050#ifdef GGML_SYCL_GRAPH 6051static bool check_graph_compatibility (ggml_cgraph * cgraph ) { 6052if (ggml_sycl_info ().device_count > 1 ) { 6053// A sycl_ex::command_graph object can only be created for a single device 6054GGML_LOG_INFO ("%s: disabling SYCL graphs due to multiple devices\n" ,__func__ ); 6055return false; 6056 } 6057 6058for (int i = 0 ;i < cgraph -> n_nodes ;i ++ ) { 6059const ggml_op node_op = cgraph -> nodes [i ]-> op ; 6060switch (node_op ) { 6061default : 6062break ; 6063case GGML_OP_CONCAT : 6064// ggml_sycl_op_concat() does a blocking host wait after memcpy operations, 6065// but wait() can't be called on the events returned by a queue recording 6066// to a graph. 6067 [[fallthrough ]]; 6068case GGML_OP_MUL_MAT_ID : 6069// ggml_sycl_mul_mat_id() does a blocking host wait on the sycl queue after 6070// submitting a memcpy operation, but wait() can't be called on a queue that 6071// is recording to a graph. 6072GGML_LOG_INFO ("%s: disabling SYCL graphs due to unsupported node type %s\n" ,__func__ , 6073ggml_op_name (node_op )); 6074return false; 6075case GGML_OP_MUL_MAT : 6076// We cannot use graphs with ggml_sycl_mul_mat() when SYCL async memory allocation extensions are not available, 6077// as SYCL malloc / free and host wait calls are not supported when recording to a graph which are all present 6078// in reordering. 6079if (!g_ggml_sycl_use_async_mem_op ) { 6080GGML_LOG_INFO ( 6081"%s: disabling SYCL graphs due to unsupported node type when using a compiler without the " 6082"oneAPI async memory allocation extension " 6083"%s\n" , 6084__func__ ,ggml_op_name (node_op )); 6085return false; 6086 } 6087 } 6088 } 6089return true; 6090} 6091#endif 6092 6093static ggml_status ggml_backend_sycl_graph_compute (ggml_backend_t backend ,ggml_cgraph * cgraph ) { 6094auto * sycl_ctx = static_cast < ggml_backend_sycl_context *> (backend -> context ); 6095 6096#ifdef GGML_SYCL_GRAPH 6097bool use_sycl_graph = false; 6098if (g_ggml_sycl_enable_graph ) { 6099use_sycl_graph = check_graph_compatibility (cgraph ); 6100 } 6101if (use_sycl_graph ) { 6102const bool graph_support = dpct::get_device (sycl_ctx -> device ).has (sycl::aspect::ext_oneapi_limited_graph ); 6103if (!graph_support ) { 6104GGML_SYCL_DEBUG ("[SYCL-GRAPH] can not use graphs on device:%d\n" ,sycl_ctx -> device ); 6105ggml_backend_sycl_graph_compute_impl (sycl_ctx ,cgraph ); 6106return GGML_STATUS_SUCCESS ; 6107 } 6108 6109 sycl_ex::command_graph model_sycl_graph (* (sycl_ctx -> stream ()), {sycl_ex::property::graph::assume_buffer_outlives_graph {}}); 6110 6111model_sycl_graph .begin_recording (* (sycl_ctx -> stream ())); 6112ggml_backend_sycl_graph_compute_impl (sycl_ctx ,cgraph ); 6113model_sycl_graph .end_recording (); 6114 6115const bool graph_update_support = dpct::get_device (sycl_ctx -> device ).has (sycl::aspect::ext_oneapi_graph ); 6116if (!sycl_ctx -> exec_graph || !graph_update_support ) { 6117auto exec_graph = graph_update_support ?model_sycl_graph .finalize (sycl_ex::property::graph::updatable {}) : 6118model_sycl_graph .finalize (); 6119sycl_ctx -> exec_graph = std::make_unique < 6120 sycl_ex::command_graph < sycl_ex::graph_state::executable >> (exec_graph ); 6121 }else { 6122try { 6123sycl_ctx -> exec_graph -> update (model_sycl_graph ); 6124GGML_SYCL_DEBUG ("[SYCL-GRAPH] update success\n" ); 6125 }catch (sycl::exception const & e ) { 6126GGML_SYCL_DEBUG ("[SYCL-GRAPH] Exception when updating graph, %s\n" ,e .what ()); 6127auto exec_graph = model_sycl_graph .finalize ({sycl_ex::property::graph::updatable {}}); 6128sycl_ctx -> exec_graph = std::make_unique < 6129 sycl_ex::command_graph < sycl_ex::graph_state::executable >> (exec_graph ); 6130 } 6131 } 6132 6133sycl_ctx -> stream ()-> ext_oneapi_graph (* (sycl_ctx -> exec_graph )); 6134 }else 6135#endif 6136 { 6137ggml_backend_sycl_graph_compute_impl (sycl_ctx ,cgraph ); 6138 } 6139return GGML_STATUS_SUCCESS ; 6140} 6141 6142static void ggml_backend_sycl_event_record (ggml_backend_t backend ,ggml_backend_event_t event ) 6143try 6144{ 6145ggml_backend_sycl_context * sycl_ctx = 6146 (ggml_backend_sycl_context * )backend -> context ; 6147 6148 sycl::event * sycl_event = static_cast < sycl::event *> (event -> context ); 6149 6150const queue_ptr & stream = sycl_ctx -> stream (sycl_ctx -> device ,0 ); 6151// Record the current state of the queue 6152SYCL_CHECK (CHECK_TRY_ERROR (* sycl_event = stream -> ext_oneapi_submit_barrier ())); 6153} 6154catch (sycl::exception const & exc ) 6155{ 6156 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 6157 <<", line:" <<__LINE__ << std::endl ; 6158 std::exit (1 ); 6159} 6160 6161static void ggml_backend_sycl_event_wait (ggml_backend_t backend ,ggml_backend_event_t event )try { 6162GGML_SYCL_DEBUG ("[SYCL] call %s\n" ,__func__ ); 6163 sycl::event * sycl_event = static_cast < sycl::event *> (event -> context ); 6164 6165if (ggml_backend_is_sycl (backend )) { 6166SYCL_CHECK (CHECK_TRY_ERROR (sycl_event -> wait ())); 6167 }else 6168GGML_ABORT ("fatal error" ); 6169}catch (sycl::exception const & exc ) { 6170 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 6171 <<", line:" <<__LINE__ << std::endl ; 6172 std::exit (1 ); 6173} 6174 6175static ggml_backend_i ggml_backend_sycl_interface = { 6176/* .get_name = */ ggml_backend_sycl_get_name , 6177/* .free = */ ggml_backend_sycl_free , 6178/* .set_tensor_async = */ ggml_backend_sycl_set_tensor_async , 6179/* .get_tensor_async = */ ggml_backend_sycl_get_tensor_async , 6180/* .set_tensor_2d_async = */ NULL , 6181/* .get_tensor_2d_async = */ NULL , 6182/* .cpy_tensor_async = */ NULL ,// ggml_backend_sycl_cpy_tensor_async, 6183// // TODO: update for the new 6184// interface 6185/* .synchronize = */ ggml_backend_sycl_synchronize , 6186/* .graph_plan_create = */ NULL , 6187/* .graph_plan_free = */ NULL , 6188/* .graph_plan_update = */ NULL , 6189/* .graph_plan_compute = */ NULL , 6190/* .graph_compute = */ ggml_backend_sycl_graph_compute , 6191/* .event_record = */ ggml_backend_sycl_event_record , 6192/* .event_wait = */ ggml_backend_sycl_event_wait , 6193/* .graph_optimize = */ NULL , 6194}; 6195 6196static ggml_guid_t ggml_backend_sycl_guid () { 6197static ggml_guid guid = {0x58 ,0x05 ,0x13 ,0x8f ,0xcd ,0x3a ,0x61 ,0x9d ,0xe7 ,0xcd ,0x98 ,0xa9 ,0x03 ,0xfd ,0x7c ,0x53 }; 6198return & guid ; 6199} 6200 6201bool ggml_backend_is_sycl (ggml_backend_t backend ) { 6202return backend != NULL && ggml_guid_matches (backend -> guid ,ggml_backend_sycl_guid ()); 6203} 6204 6205int ggml_backend_sycl_get_device_count () { 6206return ggml_sycl_info ().device_count ; 6207} 6208 6209 6210// backend device 6211 6212static const char * ggml_backend_sycl_device_get_name (ggml_backend_dev_t dev ) { 6213ggml_backend_sycl_device_context * ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6214return ctx -> name .c_str (); 6215} 6216 6217static const char * ggml_backend_sycl_device_get_description (ggml_backend_dev_t dev ) { 6218ggml_backend_sycl_device_context * ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6219return ctx -> description .c_str (); 6220} 6221 6222static void ggml_backend_sycl_device_get_memory (ggml_backend_dev_t dev ,size_t * free ,size_t * total ) { 6223GGML_SYCL_DEBUG ("[SYCL] call %s\n" ,__func__ ); 6224ggml_backend_sycl_device_context * ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6225if (!sycl_get_mem_info (ctx -> device ,free ,total )) { 6226GGML_ABORT ("[%s] failed to get device memory size" ,__func__ ); 6227 } 6228GGML_SYCL_DEBUG ("[SYCL] call %s total %zu free %zu\n" ,__func__ ,* total ,* free ); 6229ggml_sycl_memtrace_report_device ("device memory query (dev)" ,ctx -> device ,* free ,* total ); 6230} 6231 6232static enum ggml_backend_dev_type ggml_backend_sycl_device_get_type (ggml_backend_dev_t dev ) { 6233ggml_backend_sycl_device_context * ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6234const sycl_device_info & info = ggml_sycl_info ().devices [ctx -> device ]; 6235if (info .l0_device_type_valid && !info .l0_discrete_gpu ) { 6236return GGML_BACKEND_DEVICE_TYPE_IGPU ; 6237 } 6238return GGML_BACKEND_DEVICE_TYPE_GPU ; 6239} 6240 6241static void ggml_backend_sycl_device_get_props (ggml_backend_dev_t dev ,ggml_backend_dev_props * props ) { 6242props -> name = ggml_backend_sycl_device_get_name (dev ); 6243props -> description = ggml_backend_sycl_device_get_description (dev ); 6244props -> type = ggml_backend_sycl_device_get_type (dev ); 6245ggml_backend_sycl_device_get_memory (dev ,& props -> memory_free ,& props -> memory_total ); 6246 6247bool host_buffer = getenv ("GGML_SYCL_NO_PINNED" )== nullptr ; 6248#ifdef GGML_SYCL_NO_PEER_COPY 6249bool events = false; 6250#else 6251bool events = true; 6252#endif 6253 6254props -> caps = { 6255/* .async = */ true, 6256/* .host_buffer = */ host_buffer , 6257/* .buffer_from_host_ptr = */ false, 6258/* .events = */ events , 6259/* .mmap_support = */ true, 6260 }; 6261} 6262 6263static ggml_backend_t ggml_backend_sycl_device_init (ggml_backend_dev_t dev ,const char * params ) { 6264GGML_UNUSED (params ); 6265ggml_backend_sycl_device_context * ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6266return ggml_backend_sycl_init (ctx -> device ); 6267} 6268 6269static ggml_backend_buffer_type_t ggml_backend_sycl_device_get_buffer_type (ggml_backend_dev_t dev ) { 6270ggml_backend_sycl_device_context * ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6271return ggml_backend_sycl_buffer_type (ctx -> device ); 6272} 6273 6274static ggml_backend_buffer_type_t ggml_backend_sycl_device_get_host_buffer_type (ggml_backend_dev_t dev ) { 6275GGML_UNUSED (dev ); 6276return ggml_backend_sycl_host_buffer_type (); 6277} 6278 6279static ggml_backend_buffer_t ggml_backend_sycl_device_buffer_from_host_ptr (ggml_backend_dev_t dev ,void * ptr ,size_t size ,size_t max_tensor_size ) { 6280GGML_UNUSED (dev ); 6281GGML_UNUSED (ptr ); 6282GGML_UNUSED (size ); 6283GGML_UNUSED (max_tensor_size ); 6284return nullptr ; 6285} 6286 6287static bool do_ggml_backend_sycl_device_supports_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 6288ggml_backend_sycl_device_context * sycl_ctx = 6289 (ggml_backend_sycl_device_context * )dev -> context ; 6290int device = sycl_ctx -> device ; 6291switch (op -> op ) { 6292case GGML_OP_CONV_TRANSPOSE_1D : 6293 { 6294ggml_type src0_type = op -> src [0 ]-> type ; 6295ggml_type src1_type = op -> src [1 ]-> type ; 6296if (src0_type == GGML_TYPE_F32 && src1_type == GGML_TYPE_F32 ) { 6297return true; 6298 } 6299return false; 6300 } 6301case GGML_OP_CONV_2D : 6302case GGML_OP_CONV_2D_DW : 6303case GGML_OP_CONV_TRANSPOSE_2D : 6304return true; 6305case GGML_OP_UNARY : 6306switch (ggml_get_unary_op (op )) { 6307case GGML_UNARY_OP_SGN : 6308case GGML_UNARY_OP_ABS : 6309case GGML_UNARY_OP_NEG : 6310case GGML_UNARY_OP_STEP : 6311case GGML_UNARY_OP_RELU : 6312case GGML_UNARY_OP_HARDSIGMOID : 6313case GGML_UNARY_OP_TANH : 6314case GGML_UNARY_OP_GELU : 6315case GGML_UNARY_OP_SILU : 6316case GGML_UNARY_OP_SIGMOID : 6317case GGML_UNARY_OP_HARDSWISH : 6318case GGML_UNARY_OP_GELU_QUICK : 6319case GGML_UNARY_OP_GELU_ERF : 6320case GGML_UNARY_OP_EXP : 6321case GGML_UNARY_OP_EXPM1 : 6322case GGML_UNARY_OP_SOFTPLUS : 6323case GGML_UNARY_OP_ELU : 6324case GGML_UNARY_OP_XIELU : 6325case GGML_UNARY_OP_CEIL : 6326return true; 6327case GGML_UNARY_OP_FLOOR : 6328case GGML_UNARY_OP_ROUND : 6329case GGML_UNARY_OP_TRUNC : 6330return true; 6331default : 6332return false; 6333 } 6334case GGML_OP_GLU : 6335switch (ggml_get_glu_op (op )) { 6336case GGML_GLU_OP_REGLU : 6337case GGML_GLU_OP_GEGLU : 6338case GGML_GLU_OP_SWIGLU : 6339case GGML_GLU_OP_SWIGLU_OAI : 6340case GGML_GLU_OP_GEGLU_ERF : 6341case GGML_GLU_OP_GEGLU_QUICK : 6342case GGML_GLU_OP_SWIGLU_CLAMP : 6343return ggml_is_contiguous_1 (op -> src [0 ]); 6344default : 6345return false; 6346 } 6347break ; 6348case GGML_OP_MUL_MAT : 6349case GGML_OP_MUL_MAT_ID : 6350 { 6351struct ggml_tensor * a = op -> src [0 ]; 6352struct ggml_tensor * b = op -> src [1 ]; 6353 6354if (a -> ne [3 ]!= b -> ne [3 ]) { 6355return false; 6356 } 6357 6358ggml_type src0_type = op -> src [0 ]-> type ; 6359 6360// TODO: The configuration below needs more work to be supported with oneDNN 6361if (ggml_is_permuted (a )&& !ggml_is_contiguous (a )&& 6362a -> ne [2 ]> 1 && a -> ne [3 ]> 1 && src0_type == GGML_TYPE_F16 ) { 6363return false; 6364 } 6365 6366// TODO: This specific configuration can fail with oneDNN and needs more debugging 6367if (!ggml_is_permuted (a )&& ggml_is_permuted (b )&& b -> ne [2 ]> 1 && b -> ne [3 ]> 1 && 6368a -> ne [0 ]> 128 && a -> ne [2 ]== 1 && src0_type == GGML_TYPE_F16 ) { 6369return false; 6370 } 6371 6372if (src0_type == GGML_TYPE_TQ2_0 || src0_type == GGML_TYPE_TQ1_0 ) { 6373return false; 6374 } 6375 6376return true; 6377 } 6378case GGML_OP_OUT_PROD : 6379return op -> type == GGML_TYPE_F32 && 6380 (op -> src [0 ]-> type == GGML_TYPE_F32 || 6381 (op -> src [0 ]-> type == GGML_TYPE_Q1_0 && op -> src [0 ]-> ne [2 ]== op -> src [1 ]-> ne [2 ]&& 6382op -> src [0 ]-> ne [3 ]== op -> src [1 ]-> ne [3 ]))&& 6383op -> src [1 ]-> type == GGML_TYPE_F32 ; 6384case GGML_OP_GET_ROWS : 6385 { 6386switch (op -> src [0 ]-> type ) { 6387case GGML_TYPE_I32 : 6388case GGML_TYPE_F16 : 6389case GGML_TYPE_BF16 : 6390case GGML_TYPE_F32 : 6391case GGML_TYPE_Q1_0 : 6392case GGML_TYPE_MXFP4 : 6393case GGML_TYPE_NVFP4 : 6394case GGML_TYPE_IQ2_XXS : 6395case GGML_TYPE_IQ2_XS : 6396case GGML_TYPE_IQ2_S : 6397case GGML_TYPE_IQ3_XXS : 6398case GGML_TYPE_IQ1_S : 6399case GGML_TYPE_IQ1_M : 6400case GGML_TYPE_IQ3_S : 6401case GGML_TYPE_IQ4_NL : 6402case GGML_TYPE_IQ4_XS : 6403case GGML_TYPE_Q2_K : 6404case GGML_TYPE_Q3_K : 6405case GGML_TYPE_Q4_0 : 6406case GGML_TYPE_Q4_1 : 6407case GGML_TYPE_Q4_K : 6408case GGML_TYPE_Q5_0 : 6409case GGML_TYPE_Q5_1 : 6410case GGML_TYPE_Q5_K : 6411case GGML_TYPE_Q6_K : 6412case GGML_TYPE_Q8_0 : 6413return true; 6414default : 6415return false; 6416 } 6417 } 6418case GGML_OP_SET : 6419return (op -> type == GGML_TYPE_F32 )&& 6420 (op -> src [0 ]&& op -> src [1 ])&& 6421 (op -> src [0 ]-> type == GGML_TYPE_F32 )&& 6422 (op -> src [1 ]-> type == GGML_TYPE_F32 ); 6423 6424case GGML_OP_SET_ROWS : 6425 { 6426if (op -> type == GGML_TYPE_TQ2_0 || op -> type == GGML_TYPE_TQ1_0 ) { 6427return false; 6428 } 6429auto res = (op -> src [0 ]-> type == GGML_TYPE_F32 || op -> src [0 ]-> type == GGML_TYPE_F16 || 6430op -> src [0 ]-> type == GGML_TYPE_BF16 )&& 6431 (op -> src [1 ]-> type == GGML_TYPE_I64 || op -> src [1 ]-> type == GGML_TYPE_I32 ); 6432return res ; 6433 } 6434break ; 6435case GGML_OP_DSV4_HC_PRE : 6436return op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]-> type == GGML_TYPE_F32 && 6437op -> type == GGML_TYPE_F32 ; 6438case GGML_OP_DSV4_HC_COMB : 6439return op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]-> type == GGML_TYPE_F32 && 6440op -> src [2 ]-> type == GGML_TYPE_F32 && op -> type == GGML_TYPE_F32 ; 6441case GGML_OP_DSV4_HC_POST : 6442return op -> src [0 ]-> type == GGML_TYPE_F32 && op -> src [1 ]-> type == GGML_TYPE_F32 && 6443op -> src [2 ]-> type == GGML_TYPE_F32 && op -> src [3 ]-> type == GGML_TYPE_F32 && 6444op -> type == GGML_TYPE_F32 ; 6445case GGML_OP_LIGHTNING_INDEXER : 6446return op -> src [0 ]-> type == GGML_TYPE_F32 && 6447 (op -> src [1 ]-> type == GGML_TYPE_F16 || op -> src [1 ]-> type == GGML_TYPE_F32 || 6448op -> src [1 ]-> type == GGML_TYPE_BF16 || op -> src [1 ]-> type == GGML_TYPE_Q8_0 || 6449op -> src [1 ]-> type == GGML_TYPE_Q5_1 || op -> src [1 ]-> type == GGML_TYPE_Q5_0 || 6450op -> src [1 ]-> type == GGML_TYPE_Q4_1 || op -> src [1 ]-> type == GGML_TYPE_Q4_0 || 6451op -> src [1 ]-> type == GGML_TYPE_IQ4_NL )&& 6452op -> src [2 ]-> type == GGML_TYPE_F32 && 6453op -> src [3 ]-> type == GGML_TYPE_F16 && 6454op -> type == GGML_TYPE_F32 && 6455op -> src [0 ]-> ne [0 ]== WARP_SIZE * 8 ; 6456case GGML_OP_CPY : 6457 { 6458ggml_type src0_type = op -> src [0 ]-> type ; 6459ggml_type src1_type = op -> src [1 ]-> type ; 6460 6461if (src0_type == GGML_TYPE_F16 ) { 6462if (src1_type == GGML_TYPE_Q2_K || 6463src1_type == GGML_TYPE_Q3_K || 6464src1_type == GGML_TYPE_Q4_K || 6465src1_type == GGML_TYPE_Q5_K || 6466src1_type == GGML_TYPE_Q6_K || 6467src1_type == GGML_TYPE_IQ2_XXS || 6468src1_type == GGML_TYPE_IQ2_XS || 6469src1_type == GGML_TYPE_IQ2_S || 6470src1_type == GGML_TYPE_IQ3_XXS || 6471src1_type == GGML_TYPE_IQ1_S || 6472src1_type == GGML_TYPE_IQ1_M || 6473src1_type == GGML_TYPE_IQ3_S || 6474src1_type == GGML_TYPE_IQ4_XS ) { 6475return false; 6476 } 6477 } 6478 6479if (src0_type == GGML_TYPE_BF16 ) { 6480if (src1_type == GGML_TYPE_Q4_0 || //big error in ut 6481src1_type == GGML_TYPE_Q4_1 || //big error in ut 6482src1_type == GGML_TYPE_Q8_0 || //big error in ut 6483src1_type == GGML_TYPE_Q2_K || 6484src1_type == GGML_TYPE_Q3_K || 6485src1_type == GGML_TYPE_Q4_K || 6486src1_type == GGML_TYPE_Q5_K || 6487src1_type == GGML_TYPE_Q6_K || 6488src1_type == GGML_TYPE_IQ2_XXS || 6489src1_type == GGML_TYPE_IQ2_XS || 6490src1_type == GGML_TYPE_IQ2_S || 6491src1_type == GGML_TYPE_IQ3_XXS || 6492src1_type == GGML_TYPE_IQ1_S || 6493src1_type == GGML_TYPE_IQ1_M || 6494src1_type == GGML_TYPE_IQ3_S || 6495src1_type == GGML_TYPE_IQ4_XS ) { 6496return false; 6497 } 6498 } 6499 6500if (src0_type == GGML_TYPE_F32 ) { 6501if (src1_type == GGML_TYPE_Q2_K || 6502src1_type == GGML_TYPE_Q3_K || 6503src1_type == GGML_TYPE_Q4_K || 6504src1_type == GGML_TYPE_Q5_K || 6505src1_type == GGML_TYPE_Q6_K || 6506src1_type == GGML_TYPE_IQ2_XXS || 6507src1_type == GGML_TYPE_IQ2_XS || 6508src1_type == GGML_TYPE_IQ2_S || 6509src1_type == GGML_TYPE_IQ3_XXS || 6510src1_type == GGML_TYPE_IQ1_S || 6511src1_type == GGML_TYPE_IQ1_M || 6512src1_type == GGML_TYPE_IQ3_S || 6513src1_type == GGML_TYPE_IQ4_XS ) { 6514return false; 6515 } 6516 } 6517 6518if (src1_type == GGML_TYPE_F32 ) { 6519if (src0_type == GGML_TYPE_Q1_0 || 6520src0_type == GGML_TYPE_NVFP4 || 6521src0_type == GGML_TYPE_Q2_K || 6522src0_type == GGML_TYPE_Q3_K || 6523src0_type == GGML_TYPE_Q4_K || 6524src0_type == GGML_TYPE_Q5_K || 6525src0_type == GGML_TYPE_Q6_K || 6526src0_type == GGML_TYPE_IQ2_XXS || 6527src0_type == GGML_TYPE_IQ2_XS || 6528src0_type == GGML_TYPE_IQ2_S || 6529src0_type == GGML_TYPE_IQ3_XXS || 6530src0_type == GGML_TYPE_IQ1_S || 6531src0_type == GGML_TYPE_IQ1_M || 6532src0_type == GGML_TYPE_IQ3_S || 6533src0_type == GGML_TYPE_IQ4_NL || 6534src0_type == GGML_TYPE_IQ4_XS 6535 ) { 6536return false; 6537 } 6538 } 6539 6540if (src0_type == src1_type ) { 6541if (src1_type == GGML_TYPE_IQ2_XXS || 6542src1_type == GGML_TYPE_IQ2_XS || 6543src1_type == GGML_TYPE_IQ2_S || 6544src1_type == GGML_TYPE_IQ3_XXS || 6545src1_type == GGML_TYPE_IQ3_S || 6546src1_type == GGML_TYPE_IQ1_S || 6547src1_type == GGML_TYPE_IQ1_M || 6548src1_type == GGML_TYPE_TQ2_0 || 6549src1_type == GGML_TYPE_TQ1_0 ) { 6550return false; 6551 } 6552 } 6553 6554if (src0_type == GGML_TYPE_TQ2_0 || src1_type == GGML_TYPE_TQ2_0 || 6555src0_type == GGML_TYPE_TQ1_0 || src1_type == GGML_TYPE_TQ1_0 ) { 6556return false; 6557 } 6558 6559return true; 6560 } 6561case GGML_OP_REPEAT_BACK : 6562 { 6563ggml_type src0_type = op -> src [0 ]-> type ; 6564return src0_type == GGML_TYPE_F32 ; 6565 } 6566case GGML_OP_CONCAT : 6567case GGML_OP_DUP : 6568case GGML_OP_ARGMAX : 6569case GGML_OP_NONE : 6570case GGML_OP_RESHAPE : 6571case GGML_OP_VIEW : 6572case GGML_OP_PERMUTE : 6573case GGML_OP_TRANSPOSE : 6574case GGML_OP_ADD : 6575case GGML_OP_ADD1 : 6576case GGML_OP_ADD_ID : 6577case GGML_OP_SUB : 6578case GGML_OP_COUNT_EQUAL : 6579case GGML_OP_MUL : 6580case GGML_OP_DIV : 6581case GGML_OP_REPEAT : 6582return true; 6583case GGML_OP_PAD_REFLECT_1D : 6584return ggml_is_contiguous (op -> src [0 ])&& op -> type == GGML_TYPE_F32 && op -> src [0 ]-> type == GGML_TYPE_F32 ; 6585case GGML_OP_SQR : 6586case GGML_OP_SQRT : 6587case GGML_OP_SIN : 6588case GGML_OP_COS : 6589case GGML_OP_CLAMP : 6590case GGML_OP_LOG : 6591case GGML_OP_NORM : 6592case GGML_OP_L2_NORM : 6593case GGML_OP_GROUP_NORM : 6594case GGML_OP_RMS_NORM : 6595return true; 6596case GGML_OP_RMS_NORM_BACK : 6597return ggml_is_contiguous (op -> src [0 ]); 6598case GGML_OP_SCALE : 6599return true; 6600case GGML_OP_CONT : 6601return true; 6602case GGML_OP_TRI : 6603 { 6604const ggml_tensor * src0 = op -> src [0 ]; 6605return src0 && 6606op -> type == GGML_TYPE_F32 && 6607ggml_is_contiguous (src0 ); 6608 } 6609case GGML_OP_DIAG_MASK_INF : 6610return true; 6611case GGML_OP_SOFT_MAX : 6612return true; 6613case GGML_OP_SOFT_MAX_BACK : { 6614float max_bias = 0.0f ; 6615memcpy (& max_bias , (const float * )op -> op_params + 1 ,sizeof (float )); 6616return max_bias == 0.0f ; 6617 } 6618case GGML_OP_ROPE : 6619case GGML_OP_ROPE_BACK : 6620case GGML_OP_IM2COL : 6621case GGML_OP_IM2COL_3D : 6622case GGML_OP_UPSCALE : 6623return true; 6624case GGML_OP_COL2IM_1D : 6625return ggml_is_contiguous (op -> src [0 ])&& 6626 (op -> type == GGML_TYPE_F32 || op -> type == GGML_TYPE_F16 6627#ifdef GGML_SYCL_HAS_BF16 6628|| op -> type == GGML_TYPE_BF16 6629#endif 6630 )&& 6631op -> src [0 ]-> type == op -> type ; 6632case GGML_OP_CONV_3D : 6633return op -> type == GGML_TYPE_F32 && 6634 (op -> src [0 ]-> type == GGML_TYPE_F32 || op -> src [0 ]-> type == GGML_TYPE_F16 )&& 6635op -> src [1 ]-> type == GGML_TYPE_F32 && 6636ggml_is_contiguous (op -> src [0 ])&& 6637ggml_is_contiguous (op -> src [1 ]); 6638case GGML_OP_SUM : 6639case GGML_OP_SUM_ROWS : 6640case GGML_OP_MEAN : 6641return ggml_is_contiguous (op -> src [0 ]); 6642case GGML_OP_ARGSORT : 6643return true; 6644case GGML_OP_TOP_K : { 6645const ggml_tensor * src0 = op -> src [0 ]; 6646const int k = op -> ne [0 ]; 6647return src0 && 6648op -> type == GGML_TYPE_I32 && 6649src0 -> type == GGML_TYPE_F32 && 6650ggml_is_contiguous (src0 )&& 6651k > 0 && k <=src0 -> ne [0 ]; 6652 } 6653case GGML_OP_POOL_2D : 6654case GGML_OP_POOL_1D : 6655case GGML_OP_ACC : 6656return true; 6657case GGML_OP_PAD : 6658if (ggml_get_op_params_i32 (op ,8 )!= 0 ) { 6659return false; 6660 } 6661return true; 6662case GGML_OP_LEAKY_RELU : 6663case GGML_OP_TIMESTEP_EMBEDDING : 6664case GGML_OP_RWKV_WKV6 : 6665case GGML_OP_RWKV_WKV7 : 6666case GGML_OP_GATED_LINEAR_ATTN : 6667case GGML_OP_GATED_DELTA_NET : 6668case GGML_OP_OPT_STEP_ADAMW : 6669case GGML_OP_OPT_STEP_SGD : 6670return true; 6671case GGML_OP_SSM_CONV : 6672return op -> type == GGML_TYPE_F32 && 6673op -> src [0 ]-> type == GGML_TYPE_F32 && 6674op -> src [1 ]-> type == GGML_TYPE_F32 ; 6675case GGML_OP_ROLL : 6676return op -> type == GGML_TYPE_F32 ; 6677case GGML_OP_ARANGE : 6678return op -> type == GGML_TYPE_F32 ; 6679case GGML_OP_SSM_SCAN : 6680if (op -> src [3 ]-> ne [0 ]== 1 ) { 6681// Mamba2 6682// (kernel only supports (d_state == 128 || d_state == 256) && d_head % WARP_SIZE == 0) 6683return (op -> src [0 ]-> ne [0 ]== 128 || op -> src [0 ]-> ne [0 ]== 256 )&& op -> src [0 ]-> ne [1 ] %WARP_SIZE == 0 ; 6684 }else { 6685// TODO Mamba-1 not yet ported to SYCL 6686return false; 6687 } 6688case GGML_OP_FILL : 6689case GGML_OP_CUMSUM : 6690case GGML_OP_DIAG : 6691case GGML_OP_CROSS_ENTROPY_LOSS : 6692case GGML_OP_CROSS_ENTROPY_LOSS_BACK : 6693return true; 6694case GGML_OP_SOLVE_TRI : 6695return op -> src [0 ]-> ne [0 ] <=SYCL_SOLVE_TRI_MAX_N && op -> src [1 ]-> ne [0 ] <=SYCL_SOLVE_TRI_MAX_K ; 6696case GGML_OP_FLASH_ATTN_EXT : 6697return ggml_sycl_flash_attn_ext_supported (device ,op ); 6698default : 6699return false; 6700 } 6701 6702GGML_UNUSED (dev ); 6703} 6704 6705static bool ggml_backend_sycl_device_supports_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 6706bool res = do_ggml_backend_sycl_device_supports_op (dev ,op ); 6707GGML_SYCL_DEBUG ("[SYCL] call %s op->op=%s op->type=%s -> %s\n" ,__func__ ,ggml_op_name (op -> op ), 6708ggml_type_name (op -> type ),res ?"true" :"false" ); 6709return res ; 6710} 6711 6712static bool ggml_backend_sycl_device_supports_buft (ggml_backend_dev_t dev ,ggml_backend_buffer_type_t buft ) { 6713if (buft -> iface .get_name != ggml_backend_sycl_buffer_type_get_name ) { 6714return false; 6715 } 6716ggml_backend_sycl_buffer_type_context * buft_ctx = (ggml_backend_sycl_buffer_type_context * )buft -> context ; 6717ggml_backend_sycl_device_context * sycl_ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6718return buft_ctx -> device == sycl_ctx -> device ; 6719} 6720 6721static int64_t get_op_batch_size (const ggml_tensor * op ) { 6722switch (op -> op ) { 6723case GGML_OP_GET_ROWS : 6724return 0 ; 6725case GGML_OP_MUL_MAT : 6726return op -> ne [1 ]; 6727case GGML_OP_MUL_MAT_ID : 6728case GGML_OP_ROPE : 6729return op -> ne [2 ]; 6730default : 6731return ggml_nrows (op ); 6732 } 6733} 6734 6735static bool ggml_backend_sycl_device_offload_op (ggml_backend_dev_t dev ,const ggml_tensor * op ) { 6736ggml_backend_sycl_device_context * sycl_ctx = (ggml_backend_sycl_device_context * )dev -> context ; 6737return get_op_batch_size (op ) >=sycl_ctx -> op_offload_min_batch_size ; 6738} 6739 6740static ggml_backend_event_t 6741ggml_backend_sycl_device_event_new (ggml_backend_dev_t dev ) { 6742 6743#ifdef GGML_SYCL_NO_PEER_COPY 6744return nullptr ; 6745#else 6746 sycl::event * event_ptr = new sycl::event (); 6747 6748return new ggml_backend_event { 6749/* .device = */ dev , 6750/* .context = */ event_ptr , 6751 }; 6752#endif 6753} 6754 6755static void ggml_backend_sycl_device_event_free (ggml_backend_dev_t dev ,ggml_backend_event_t event )try { 6756GGML_UNUSED (dev ); 6757if (event == nullptr ) { 6758return ; 6759 } 6760 6761if (event -> context != nullptr ) { 6762 sycl::event * sycl_event = static_cast < sycl::event *> (event -> context ); 6763delete sycl_event ; 6764event -> context = nullptr ; 6765 } 6766 6767delete event ; 6768}catch (sycl::exception const & exc ) { 6769 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 6770 <<", line:" <<__LINE__ << std::endl ; 6771 std::exit (1 ); 6772} 6773 6774 6775static void ggml_backend_sycl_device_event_synchronize (ggml_backend_dev_t dev ,ggml_backend_event_t event )try { 6776GGML_UNUSED (dev ); 6777GGML_SYCL_DEBUG ("[SYCL] call %s\n" ,__func__ ); 6778 6779 sycl::event * sycl_event = static_cast < sycl::event *> (event -> context ); 6780SYCL_CHECK (CHECK_TRY_ERROR (sycl_event -> wait ())); 6781}catch (sycl::exception const & exc ) { 6782 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 6783 <<", line:" <<__LINE__ << std::endl ; 6784 std::exit (1 ); 6785} 6786 6787static const ggml_backend_device_i ggml_backend_sycl_device_interface = { 6788/* .get_name = */ ggml_backend_sycl_device_get_name , 6789/* .get_description = */ ggml_backend_sycl_device_get_description , 6790/* .get_memory = */ ggml_backend_sycl_device_get_memory , 6791/* .get_type = */ ggml_backend_sycl_device_get_type , 6792/* .get_props = */ ggml_backend_sycl_device_get_props , 6793/* .init_backend = */ ggml_backend_sycl_device_init , 6794/* .get_buffer_type = */ ggml_backend_sycl_device_get_buffer_type , 6795/* .get_host_buffer_type = */ ggml_backend_sycl_device_get_host_buffer_type , 6796/* .buffer_from_host_ptr = */ ggml_backend_sycl_device_buffer_from_host_ptr , 6797/* .supports_op = */ ggml_backend_sycl_device_supports_op , 6798/* .supports_buft = */ ggml_backend_sycl_device_supports_buft , 6799/* .offload_op = */ ggml_backend_sycl_device_offload_op , 6800/* .event_new = */ ggml_backend_sycl_device_event_new , 6801/* .event_free = */ ggml_backend_sycl_device_event_free , 6802/* .event_synchronize = */ ggml_backend_sycl_device_event_synchronize , 6803}; 6804 6805// backend reg 6806 6807struct ggml_backend_sycl_reg_context { 6808 std::vector < ggml_backend_dev_t > devices ; 6809}; 6810 6811static const char * ggml_backend_sycl_reg_get_name (ggml_backend_reg_t reg ) { 6812GGML_UNUSED (reg ); 6813return GGML_SYCL_NAME ; 6814} 6815 6816static size_t ggml_backend_sycl_reg_get_device_count (ggml_backend_reg_t reg ) { 6817ggml_backend_sycl_reg_context * ctx = (ggml_backend_sycl_reg_context * )reg -> context ; 6818return ctx -> devices .size (); 6819} 6820 6821static ggml_backend_dev_t ggml_backend_sycl_reg_get_device (ggml_backend_reg_t reg ,size_t index ) { 6822ggml_backend_sycl_reg_context * ctx = (ggml_backend_sycl_reg_context * )reg -> context ; 6823GGML_ASSERT (index < ctx -> devices .size ()); 6824return ctx -> devices [index ]; 6825} 6826 6827// ========================================================================== 6828// Tensor parallelism (--split-mode tensor) for the SYCL backend. 6829// 6830// The meta-backend invokes these three entry points via get_proc_address: 6831// * ggml_backend_sycl_comm_init - one-time per-graph setup 6832// * ggml_backend_sycl_comm_allreduce_tensor - per-allreduce step 6833// * ggml_backend_sycl_comm_free - tear-down 6834// 6835// For N=2 (dual-GPU), this is a degenerate ring allreduce with dual paths 6836// chosen by tensor size: 6837// 6838// * Small (nelem < 32K): FP32 direct memcpy + per-device ADD 6839// kernel. The kernel depends_on() its corresponding memcpy event 6840// so it doesn't read partial data. Both devices run in parallel. 6841// 6842// * Large (nelem >= 32K): BF16-compressed. Each device compresses 6843// its FP32 partial to BF16 locally, cross-device memcpys 6844// to the peer (half the PCI bandwidth), where it is decompressed 6845// and added into the local FP32 partial. 6 SYCL submissions per 6846// allreduce (2 compress + 2 memcpy + 2 decompress-add) vs the 6847// 4 for the small path, but the bandwidth saving > 6 GB/s PCIe x 2 6848// dominates for larger tensors. 6849// 6850// Storage: A persistent uint8_t buffer per device, sized to 6851// 4 * nelem bytes. Both paths reinterpret the same bytes (small path 6852// as nelem floats; large path as outbox + inbox = 2*nelem uint16_t 6853// each, using the full 4*nelem byte budget either way). Single 6854// alloc+free per device keeps the SYCL pool's strict-LIFO invariant 6855// trivial. 6856// 6857// For non-(N=2 FP32 contiguous) cases, comm_init or comm_allreduce_tensor 6858// returns null/false, causing the meta-backend to use its generic 6859// butterfly all-reduce fallback. 6860// ========================================================================== 6861 6862struct ggml_backend_sycl_comm_context { 6863 std::vector < ggml_backend_t > backends ; 6864// ONE persistent per-device byte buffer, 4*nelem bytes. Both the 6865// FP32 small-tensor path and the BF16 large-tensor path share it 6866// by reinterpreting. 6867 std::unique_ptr < ggml_sycl_pool_alloc < uint8_t >> buf0 ; 6868 std::unique_ptr < ggml_sycl_pool_alloc < uint8_t >> buf1 ; 6869int64_t buf_nelem = 0 ; 6870}; 6871 6872void * ggml_backend_sycl_comm_init (ggml_backend_t * backends ,size_t n_backends )try { 6873for (size_t i = 0 ;i < n_backends ;++ i ) { 6874if (!ggml_backend_is_sycl (backends [i ])) { 6875return nullptr ; 6876 } 6877 } 6878 6879// Initial version: N=2 only. For N!=2, returning null makes the 6880// meta-backend skip this backend-specific allreduce entirely. 6881if (n_backends != 2 ) { 6882return nullptr ; 6883 } 6884 6885auto * ctx = new ggml_backend_sycl_comm_context ; 6886ctx -> backends .assign (backends ,backends + n_backends ); 6887auto * sctx0 = (ggml_backend_sycl_context * )backends [0 ]-> context ; 6888auto * sctx1 = (ggml_backend_sycl_context * )backends [1 ]-> context ; 6889ctx -> buf0 = std::make_unique < ggml_sycl_pool_alloc < uint8_t >> (sctx0 -> pool ()); 6890ctx -> buf1 = std::make_unique < ggml_sycl_pool_alloc < uint8_t >> (sctx1 -> pool ()); 6891return ctx ; 6892} 6893catch (const sycl::exception & ) {return nullptr ; } 6894catch (...) {return nullptr ; } 6895 6896void ggml_backend_sycl_comm_free (void * comm_ctx_v ) { 6897auto * comm_ctx = static_cast < ggml_backend_sycl_comm_context *> (comm_ctx_v ); 6898if (comm_ctx == nullptr ) { 6899return ; 6900 } 6901 6902// Sync both per-device queues so the pool_alloc destructors don't 6903// return memory still in use by the last kernel. 6904if (comm_ctx -> backends .size ()== 2 ) { 6905auto * sctx0 = (ggml_backend_sycl_context * )comm_ctx -> backends [0 ]-> context ; 6906auto * sctx1 = (ggml_backend_sycl_context * )comm_ctx -> backends [1 ]-> context ; 6907try { 6908sctx0 -> stream ()-> wait (); 6909sctx1 -> stream ()-> wait (); 6910 }catch (...) {/* best effort during shutdown */ } 6911 } 6912 6913delete comm_ctx ; 6914} 6915 6916bool ggml_backend_sycl_comm_allreduce_tensor (void * comm_ctx_v ,struct ggml_tensor ** tensors )try { 6917if (comm_ctx_v == nullptr ) { 6918return false; 6919 } 6920 6921auto * comm_ctx = static_cast < ggml_backend_sycl_comm_context *> (comm_ctx_v ); 6922const size_t n_backends = comm_ctx -> backends .size (); 6923 6924// Fast path: N=2, F32/F16, contiguous, matching shapes. 6925if (n_backends != 2 ) { 6926return false; 6927 } 6928// Accept F32 or F16 inputs natively (types must match). F16 takes the 6929// direct 2-byte memcpy + add path below; other types return false so the 6930// meta-backend uses its generic all-reduce. 6931if (tensors [0 ]-> type != tensors [1 ]-> type ) { 6932return false; 6933 } 6934if (tensors [0 ]-> type != GGML_TYPE_F32 && tensors [0 ]-> type != GGML_TYPE_F16 ) { 6935return false; 6936 } 6937if (!ggml_is_contiguous (tensors [0 ])|| !ggml_is_contiguous (tensors [1 ])) { 6938return false; 6939 } 6940if (ggml_nelements (tensors [0 ])!= ggml_nelements (tensors [1 ])) { 6941return false; 6942 } 6943 6944const int64_t nelem = ggml_nelements (tensors [0 ]); 6945const size_t nbytes = ggml_nbytes (tensors [0 ]); 6946if (nelem == 0 ) { 6947return true; 6948 } 6949 6950auto * ctx0 = (ggml_backend_sycl_context * )comm_ctx -> backends [0 ]-> context ; 6951auto * ctx1 = (ggml_backend_sycl_context * )comm_ctx -> backends [1 ]-> context ; 6952queue_ptr q0 = ctx0 -> stream (); 6953queue_ptr q1 = ctx1 -> stream (); 6954 6955// Grow per-device byte buffers if needed (4 * nelem bytes each). 6956if (comm_ctx -> buf_nelem < nelem ) { 6957comm_ctx -> buf0 -> realloc (nelem * 4 ); 6958comm_ctx -> buf1 -> realloc (nelem * 4 ); 6959comm_ctx -> buf_nelem = nelem ; 6960 } 6961uint8_t * buf0 = comm_ctx -> buf0 -> get (); 6962uint8_t * buf1 = comm_ctx -> buf1 -> get (); 6963 6964// F16 native path: direct 2-byte cross-device copy + add, skipping the 6965// F32 round-trip the meta-backend fallback would force. Cross-device copies 6966// go through dev2dev_memcpy because the two devices are in separate SYCL 6967// contexts (a raw peer-USM q->memcpy would be a silent no-op). 6968if (tensors [0 ]-> type == GGML_TYPE_F16 ) { 6969 sycl::half * f16_out0 = (sycl::half * )tensors [0 ]-> data ; 6970 sycl::half * f16_out1 = (sycl::half * )tensors [1 ]-> data ; 6971 sycl::half * f16_tmp0 = (sycl::half * )buf0 ; 6972 sycl::half * f16_tmp1 = (sycl::half * )buf1 ; 6973 6974q0 -> wait (); 6975q1 -> wait (); 6976dev2dev_memcpy (ctx0 -> device ,* q0 ,ctx1 -> device ,* q1 ,f16_tmp0 ,tensors [1 ]-> data ,nbytes ); 6977dev2dev_memcpy (ctx1 -> device ,* q1 ,ctx0 -> device ,* q0 ,f16_tmp1 ,tensors [0 ]-> data ,nbytes ); 6978 6979q0 -> submit ([& ](sycl::handler & h ) { 6980h .parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 6981f16_out0 [i ]= (sycl::half ) ((float )f16_out0 [i ]+ (float )f16_tmp0 [i ]); 6982 }); 6983 }); 6984q1 -> submit ([& ](sycl::handler & h ) { 6985h .parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 6986f16_out1 [i ]= (sycl::half ) ((float )f16_out1 [i ]+ (float )f16_tmp1 [i ]); 6987 }); 6988 }); 6989return true; 6990 } 6991 6992float * out0 = (float * )tensors [0 ]-> data ; 6993float * out1 = (float * )tensors [1 ]-> data ; 6994 6995// BF16 threshold: above this, the PCIe savings from halving the 6996// cross-device bytes outweigh the 2 extra compress kernels. 6997// Below: stay on the FP32 fast path. Threshold mirrors the CUDA 6998// NCCL allreduce pattern for n_backends=2. 6999static constexpr int64_t BF16_THRESHOLD = 32768 ; 7000 7001if (nelem < BF16_THRESHOLD ) { 7002// FP32 small path: 4 SYCL submissions per allreduce. 7003float * tmp0 = (float * )buf0 ; 7004float * tmp1 = (float * )buf1 ; 7005 7006// COMM-D2D-FIX: the two devices are in SEPARATE SYCL contexts, so a raw 7007// q->memcpy of a peer USM pointer is a silent no-op. Route cross-device 7008// copies through dev2dev_memcpy (L0 direct copy / host staging). It is 7009// synchronous, so wait for the local partials to be produced first. 7010q0 -> wait (); 7011q1 -> wait (); 7012dev2dev_memcpy (ctx0 -> device ,* q0 ,ctx1 -> device ,* q1 ,tmp0 ,tensors [1 ]-> data ,nbytes ); 7013dev2dev_memcpy (ctx1 -> device ,* q1 ,ctx0 -> device ,* q0 ,tmp1 ,tensors [0 ]-> data ,nbytes ); 7014 7015q0 -> submit ([& ](sycl::handler & h ) { 7016h .parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 7017out0 [i ]+= tmp0 [i ]; 7018 }); 7019 }); 7020q1 -> submit ([& ](sycl::handler & h ) { 7021h .parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 7022out1 [i ]+= tmp1 [i ]; 7023 }); 7024 }); 7025return true; 7026 } 7027 7028// BF16 large path: 6 SYCL submissions per allreduce, but the 7029// cross-device memcpy is HALF the bytes. Pure bit-shift 7030// conversion (no rounding) — matches ggml's truncating fp32->bf16. 7031uint16_t * outbox0 = (uint16_t * )buf0 ; 7032uint16_t * inbox0 = outbox0 + nelem ; 7033uint16_t * outbox1 = (uint16_t * )buf1 ; 7034uint16_t * inbox1 = outbox1 + nelem ; 7035 7036// Phase A: compress each device's local partial in parallel. 7037 sycl::event c0 = q0 -> parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 7038outbox0 [i ]= (uint16_t ) (sycl::bit_cast < uint32_t > (out0 [i ]) >>16 ); 7039 }); 7040 7041 sycl::event c1 = q1 -> parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 7042outbox1 [i ]= (uint16_t ) (sycl::bit_cast < uint32_t > (out1 [i ]) >>16 ); 7043 }); 7044 7045// Phase B: COMM-D2D-FIX-BF16 cross-device copy of compressed bytes via 7046// dev2dev_memcpy (separate SYCL contexts; sync copy after compress). 7047const size_t bf16_bytes = nelem * sizeof (uint16_t ); 7048c0 .wait (); 7049c1 .wait (); 7050dev2dev_memcpy (ctx0 -> device ,* q0 ,ctx1 -> device ,* q1 ,inbox0 ,outbox1 ,bf16_bytes ); 7051dev2dev_memcpy (ctx1 -> device ,* q1 ,ctx0 -> device ,* q0 ,inbox1 ,outbox0 ,bf16_bytes ); 7052 7053// Phase C: decompress + add into local FP32 partial. 7054q0 -> submit ([& ](sycl::handler & h ) { 7055h .parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 7056out0 [i ]+= sycl::bit_cast < float > (((uint32_t )inbox0 [i ]) <<16 ); 7057 }); 7058 }); 7059 7060q1 -> submit ([& ](sycl::handler & h ) { 7061h .parallel_for (sycl::range < 1 > (nelem ), [= ](sycl::id < 1 > i ) { 7062out1 [i ]+= sycl::bit_cast < float > (((uint32_t )inbox1 [i ]) <<16 ); 7063 }); 7064 }); 7065 7066return true; 7067} 7068catch (const sycl::exception & ) {return false; } 7069catch (...) {return false; } 7070 7071static void * ggml_backend_sycl_reg_get_proc_address (ggml_backend_reg_t reg ,const char * name ) { 7072GGML_UNUSED (reg ); 7073 7074if (strcmp (name ,"ggml_backend_split_buffer_type" )== 0 ) { 7075return (void * )ggml_backend_sycl_split_buffer_type ; 7076 } 7077 7078// Tensor parallelism (--split-mode tensor) entry points. 7079if (strcmp (name ,"ggml_backend_comm_init" )== 0 ) { 7080return (void * )ggml_backend_sycl_comm_init ; 7081 } 7082if (strcmp (name ,"ggml_backend_comm_free" )== 0 ) { 7083return (void * )ggml_backend_sycl_comm_free ; 7084 } 7085if (strcmp (name ,"ggml_backend_comm_allreduce_tensor" )== 0 ) { 7086return (void * )ggml_backend_sycl_comm_allreduce_tensor ; 7087 } 7088 7089// SYCL doesn't support registering host memory, left here for reference 7090// "ggml_backend_register_host_buffer" 7091// "ggml_backend_unregister_host_buffer" 7092GGML_UNUSED (name ); 7093return nullptr ; 7094} 7095 7096static const ggml_backend_reg_i ggml_backend_sycl_reg_interface = { 7097/* .get_name = */ ggml_backend_sycl_reg_get_name , 7098/* .get_device_count = */ ggml_backend_sycl_reg_get_device_count , 7099/* .get_device = */ ggml_backend_sycl_reg_get_device , 7100/* .get_proc_address = */ ggml_backend_sycl_reg_get_proc_address , 7101}; 7102 7103 7104// backend registry 7105 7106ggml_backend_reg_t ggml_backend_sycl_reg () { 7107GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_reg\n" ); 7108static ggml_backend_reg reg ; 7109static bool initialized = false; 7110 7111 { 7112static std::mutex mutex ; 7113 std::lock_guard < std::mutex > lock (mutex ); 7114if (!initialized ) { 7115ggml_check_sycl (); 7116ggml_backend_sycl_reg_context * ctx = new ggml_backend_sycl_reg_context ; 7117const int min_batch_size = getenv ("GGML_OP_OFFLOAD_MIN_BATCH" ) ?atoi (getenv ("GGML_OP_OFFLOAD_MIN_BATCH" )) :32 ; 7118 7119for (int i = 0 ;i < ggml_sycl_info ().device_count ;i ++ ) { 7120ggml_backend_sycl_device_context * dev_ctx = new ggml_backend_sycl_device_context ; 7121dev_ctx -> device = i ; 7122dev_ctx -> name = GGML_SYCL_NAME + std::to_string (i ); 7123 7124ggml_sycl_set_device (i ); 7125 7126 dpct::device_info prop ; 7127SYCL_CHECK (CHECK_TRY_ERROR (dpct::get_device_info ( 7128prop , dpct::dev_mgr::instance ().get_device (i )))); 7129 7130dev_ctx -> description = prop .get_name (); 7131dev_ctx -> op_offload_min_batch_size = min_batch_size ; 7132 7133ggml_backend_dev_t dev = new ggml_backend_device { 7134/* .iface = */ ggml_backend_sycl_device_interface , 7135/* .reg = */ & reg , 7136/* .context = */ dev_ctx 7137 }; 7138ctx -> devices .push_back (dev ); 7139 } 7140 7141reg = ggml_backend_reg { 7142/* .api_version = */ GGML_BACKEND_API_VERSION , 7143/* .iface = */ ggml_backend_sycl_reg_interface , 7144/* .context = */ ctx 7145 }; 7146 } 7147 7148initialized = true; 7149 } 7150 7151return & reg ; 7152} 7153 7154ggml_backend_t ggml_backend_sycl_init (int device ) { 7155GGML_SYCL_DEBUG ("[SYCL] call ggml_backend_sycl_init\n" ); 7156ggml_check_sycl (); 7157 7158check_allow_gpu_index (device ); 7159 7160ggml_backend_sycl_context * ctx = new ggml_backend_sycl_context (device ); 7161if (ctx == nullptr ) { 7162GGML_LOG_ERROR ("%s: error: failed to allocate context\n" ,__func__ ); 7163return nullptr ; 7164 }; 7165 7166ggml_backend_t sycl_backend = new ggml_backend { 7167/* .guid = */ ggml_backend_sycl_guid (), 7168/* .iface = */ ggml_backend_sycl_interface , 7169/* .device = */ ggml_backend_reg_dev_get (ggml_backend_sycl_reg (),device ), 7170/* .context = */ ctx 7171 }; 7172 7173return sycl_backend ; 7174} 7175 7176GGML_BACKEND_DL_IMPL (ggml_backend_sycl_reg )