char-fork/llama.cpp
git clone https://git.t4t.associates/char-fork/llama.cpp
661643e43
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#ifndef GGML_SYCL_COMMON_HPP 14#define GGML_SYCL_COMMON_HPP 15 16#include <cstddef> 17#include <fstream> 18#include <iostream> 19#include <string> 20 21#include "base.hpp" 22#include "dpct/helper.hpp" 23#include "ggml.h" 24#include "ggml-impl.h" 25#include "ggml-sycl.h" 26#include "presets.hpp" 27#include "type.hpp" 28#include "sycl_hw.hpp" 29#include "fattn-buffers.hpp" 30#include "memtrace.hpp" 31 32namespace syclexp= sycl::ext::oneapi::experimental; 33 34#if defined(__INTEL_LLVM_COMPILER )&& __has_include (< sycl /ext /oneapi /bfloat16 .hpp > ) 35#include <sycl/ext/oneapi/bfloat16.hpp> 36#ifndef GGML_SYCL_HAS_BF16 37#define GGML_SYCL_HAS_BF16 38#endif 39#endif 40 41#if GGML_SYCL_DNNL 42#include "dnnl.hpp" 43#include "dnnl_sycl.hpp" 44#endif 45 46#define GGML_COMMON_DECL_SYCL 47#define GGML_COMMON_IMPL_SYCL 48#define SYCL_FLASH_ATTN //remove it to disable FLASH_ATTENTION in building. 49#define SYCL_FAST_FP16 //don't change. remove it will break fattn-tile.hpp building 50#define GGML_SYCL_FA_ALL_QUANTS //define it to enable all quantization types in flash attention. undefine it to only support F16, Q4_0 and Q8_0 in flash attention. 51 52/* suppress warning spam */ 53#pragma clang diagnostic push 54#pragma clang diagnostic ignored "-Wnested-anon-types" 55#include "ggml-common.h" 56#pragma clang diagnostic pop 57#include "ggml-impl.h" 58 59void * ggml_sycl_host_malloc (size_t size ); 60void ggml_sycl_host_free (void * ptr ); 61 62 63extern int g_ggml_sycl_debug ; 64extern int g_ggml_sycl_enable_optimize ; 65extern int g_ggml_sycl_enable_fusion ; 66extern int g_ggml_sycl_enable_esimd ; 67extern int g_ggml_sycl_prioritize_dmmv ; 68extern int g_ggml_sycl_enable_flash_attention ; 69extern int g_ggml_sycl_dev2dev_memcpy ; 70extern int g_ggml_sycl_fa_onednn ; 71extern int g_ggml_sycl_fa_onednn_max_kv ; 72extern int g_ggml_sycl_enable_mkl_fa ; 73extern int g_ggml_sycl_memtrace ; 74extern int g_ggml_sycl_memtrace_step ; 75 76 77#define CHECK_TRY_ERROR (expr ) \ 78 [&]() { \ 79 try { \ 80 expr; \ 81 return dpct::success; \ 82 } catch (std::exception const& e) { \ 83 std::cerr << e.what() << "\nException caught at file:" << __FILE__ \ 84 << ", line:" << __LINE__ << ", func:" << __func__ \ 85 << std::endl; \ 86 return dpct::default_error; \ 87 } \ 88 }() 89 90 91#define __SYCL_ARCH__ DPCT_COMPATIBILITY_TEMP 92#define VER_4VEC 610 // todo for hardware optimize. 93#define VER_GEN9 700 // todo for hardware optimize. 94#define VER_GEN12 1000000 // todo for hardware optimize. 95#define VER_GEN13 (VER_GEN12 + 1030) // todo for hardware optimize. 96 97#define GGML_SYCL_MAX_NODES 8192 // TODO: adapt to hardwares 98 99// define for XMX in Intel GPU 100// TODO: currently, it's not used for XMX really. 101#if !defined(GGML_SYCL_FORCE_MMQ ) 102#define SYCL_USE_XMX 103#endif 104 105// max batch size to use MMQ kernels when tensor cores are available 106#define MMQ_MAX_BATCH_SIZE 32 107 108// dmmv = dequantize_mul_mat_vec 109#ifndef GGML_SYCL_DMMV_X 110#define GGML_SYCL_DMMV_X 32 111#endif 112#ifndef GGML_SYCL_MMV_Y 113#define GGML_SYCL_MMV_Y 1 114#endif 115 116typedef sycl::queue * queue_ptr ; 117 118enum ggml_sycl_backend_gpu_mode { 119SYCL_UNSET_GPU_MODE = -1 , 120SYCL_SINGLE_GPU_MODE = 0 , 121SYCL_MUL_GPU_MODE 122}; 123 124enum ggml_sycl_dev2dev_memcpy_mode { 125DEV2DEV_MEMCPY_SYCL = 0 , 126DEV2DEV_MEMCPY_L0 = 1 , 127DEV2DEV_MEMCPY_FORWARD = 2 128}; 129 130static_assert(sizeof (sycl::half )== sizeof (ggml_fp16_t ),"wrong fp16 size" ); 131 132static void crash () { 133int * ptr = NULL ; 134* ptr = 0 ; 135} 136 137[[noreturn ]]static void ggml_sycl_error ( 138const char * stmt , 139const char * func , 140const char * file , 141const int line , 142const char * msg ) { 143fprintf (stderr ,"SYCL error: %s: %s\n" ,stmt ,msg ); 144fprintf (stderr ," in function %s at %s:%d\n" ,func ,file ,line ); 145GGML_ABORT ("SYCL error" ); 146} 147 148#define SYCL_CHECK (err ) \ 149 do { \ 150 auto err_ = (err); \ 151 if (err_ != 0) \ 152 ggml_sycl_error(#err, __func__, __FILE__, __LINE__, "Exception caught in this line of code."); \ 153 } while (0) 154 155#if DPCT_COMPAT_RT_VERSION >=11100 156#define GGML_SYCL_ASSUME (x ) __builtin_assume(x) 157#else 158#define GGML_SYCL_ASSUME (x ) 159#endif // DPCT_COMPAT_RT_VERSION >= 11100 160 161#ifdef GGML_SYCL_F16 162typedef sycl::half dfloat ;// dequantize float 163typedef sycl::half2 dfloat2 ; 164#else 165typedef float dfloat ;// dequantize float 166typedef sycl::float2 dfloat2 ; 167#endif // GGML_SYCL_F16 168 169#define MMVQ_MAX_BATCH_SIZE 8 170 171static int g_all_sycl_device_count = -1 ; 172static bool g_ggml_backend_sycl_buffer_type_initialized = false; 173 174static ggml_sycl_backend_gpu_mode g_ggml_sycl_backend_gpu_mode = 175SYCL_UNSET_GPU_MODE ; 176 177static void * g_scratch_buffer = nullptr ; 178static size_t g_scratch_size = 0 ;// disabled by default 179static size_t g_scratch_offset = 0 ; 180 181[[noreturn ]]static inline void bad_arch (const sycl::stream & stream_ct1 ) { 182stream_ct1 <<"ERROR: ggml-sycl was compiled without support for the " 183"current GPU architecture.\n" ; 184// __trap(); 185 std::exit (1 ); 186 187 (void )bad_arch ;// suppress unused function warning 188} 189 190int get_current_device_id (); 191 192inline int ggml_sycl_get_device () { 193return get_current_device_id (); 194} 195 196inline dpct::err0 ggml_sycl_set_device (const int device )try { 197int current_device_id ; 198SYCL_CHECK (CHECK_TRY_ERROR (current_device_id = get_current_device_id ())); 199 200// GGML_SYCL_DEBUG("ggml_sycl_set_device device_id=%d, 201// current_device_id=%d\n", device, current_device); 202if (device == current_device_id ) { 203return 0 ; 204 } 205 206return CHECK_TRY_ERROR (dpct::select_device (device )); 207}catch (sycl::exception const & exc ) { 208 std::cerr <<exc .what () <<"Exception caught at file:" <<__FILE__ 209 <<", line:" <<__LINE__ << std::endl ; 210crash (); 211 std::exit (1 ); 212} 213 214////////////////////// 215struct optimize_feature { 216bool reorder = false; 217}; 218 219struct sycl_device_info { 220int cc ;// compute capability 221int nsm ;// number of streaming multiprocessors (CUDA) maps to the maximum 222// number of compute units on a SYCL device. 223// size_t smpb; // max. shared memory per block 224size_t smpbo ;// max. shared memory per block (with opt-in) 225int warp_size ;// WARP_SIZE(16)|WARP_32_SIZE(32)|WARP_16_SIZE(16). For Intel GPU, 16 is better in most cases. Some OP support 32 only. 226int max_wg_per_cu ;// max work groups per compute unit - refer to 227// cudaOccupancyMaxActiveBlocksPerMultiprocessor 228bool vmm ;// virtual memory support 229bool l0_device_type_valid ; 230bool l0_discrete_gpu ;// Level Zero backend and not an integrated GPU 231size_t vmm_granularity ;// granularity of virtual memory 232size_t total_vram ; 233sycl_hw_info hw_info ; 234optimize_feature opt_feature ; 235bool usm_system_support ;// support for USM system allocations 236}; 237 238 239struct ggml_sycl_device_info { 240int device_count ; 241 242sycl_device_info devices [GGML_SYCL_MAX_DEVICES ]= {}; 243 244 std::array < float ,GGML_SYCL_MAX_DEVICES > default_tensor_split = {}; 245 246int max_work_group_sizes [GGML_SYCL_MAX_DEVICES ]= {0 }; 247 248bool ext_oneapi_level_zero = true;// sycl::backend::ext_oneapi_level_zero used by all enumerated GPU devices 249}; 250 251const ggml_sycl_device_info & ggml_sycl_info (); 252 253static constexpr size_t SYCL_BUFFER_ALIGNMENT = 128 ; 254 255struct ggml_sycl_pool { 256virtual ~ggml_sycl_pool ()= default ; 257 258virtual void * alloc (size_t size ,size_t * actual_size )= 0 ; 259virtual void free (void * ptr ,size_t size )= 0 ; 260}; 261 262template < typename T > 263struct ggml_sycl_pool_alloc { 264ggml_sycl_pool * pool = nullptr ; 265T * ptr = nullptr ; 266size_t actual_size = 0 ; 267 268explicit ggml_sycl_pool_alloc (ggml_sycl_pool & pool ) :pool (& pool ) { 269 } 270 271ggml_sycl_pool_alloc (ggml_sycl_pool & pool ,size_t size ) :pool (& pool ) { 272alloc (size ); 273 } 274 275 ~ggml_sycl_pool_alloc () { 276if (ptr != nullptr ) { 277pool -> free (ptr ,actual_size ); 278 } 279 } 280 281T * realloc (size_t size ) { 282GGML_ASSERT (pool != nullptr ); 283if (ptr ) 284pool -> free (ptr ,actual_size ); 285ptr = (T * )pool -> alloc (size * sizeof (T ),& this -> actual_size ); 286return ptr ; 287 } 288 289// size is in number of elements 290T * alloc (size_t size ) { 291GGML_ASSERT (pool != nullptr ); 292GGML_ASSERT (ptr == nullptr ); 293ptr = (T * )pool -> alloc (size * sizeof (T ),& this -> actual_size ); 294return ptr ; 295 } 296 297T * alloc (ggml_sycl_pool & pool ,size_t size ) { 298this -> pool = & pool ; 299return alloc (size ); 300 } 301 302T * get () { 303return ptr ; 304 } 305 306ggml_sycl_pool_alloc ()= default ; 307ggml_sycl_pool_alloc (const ggml_sycl_pool_alloc & )= delete ; 308ggml_sycl_pool_alloc (ggml_sycl_pool_alloc && )= delete ; 309ggml_sycl_pool_alloc & operator= (const ggml_sycl_pool_alloc & )= delete ; 310ggml_sycl_pool_alloc & operator= (ggml_sycl_pool_alloc && )= delete ; 311}; 312 313// backend interface 314 315struct ggml_tensor_extra_gpu { 316void * data_device [GGML_SYCL_MAX_DEVICES ];// 1 pointer for each device for split 317// tensors 318 dpct::event_ptr events [GGML_SYCL_MAX_DEVICES ] 319 [GGML_SYCL_MAX_STREAMS ];// events for synchronizing multiple GPUs 320optimize_feature optimized_feature ; 321}; 322 323extern int g_ggml_sycl_use_level_zero_api ; 324void * ggml_sycl_malloc_device (size_t size , sycl::queue & q , 325ggml_sycl_mem_type type = GGML_SYCL_MEM_DIRECT ); 326void ggml_sycl_free_device (void * ptr , sycl::queue & q ); 327 328void release_extra_gpu (ggml_tensor_extra_gpu * extra , std::vector < queue_ptr > streams = {}); 329 330struct mmid_row_mapping { 331int32_t i1 ; 332int32_t i2 ; 333}; 334 335namespace sycl_ex= sycl::ext::oneapi::experimental; 336struct ggml_backend_sycl_context { 337int device ; 338 std::string name ; 339optimize_feature opt_feature ; 340 341queue_ptr qptrs [GGML_SYCL_MAX_DEVICES ][GGML_SYCL_MAX_STREAMS ]= { {nullptr } }; 342 343explicit ggml_backend_sycl_context (int device ) : 344device (device ), 345name (GGML_SYCL_NAME + std::to_string (device )) { 346opt_feature = ggml_sycl_info ().devices [device ].opt_feature ; 347 } 348 349queue_ptr stream (int device ,int stream ) { 350if (qptrs [device ][stream ]== nullptr ) { 351qptrs [device ][stream ]= & (dpct::get_device (device ).default_queue ()); 352 } 353return qptrs [device ][stream ]; 354 } 355 356queue_ptr stream () { 357return stream (device ,0 ); 358 } 359 360#if GGML_SYCL_DNNL 361 dnnl::engine make_engine (sycl::queue * q ) { 362// Get the device associated with the queue 363 sycl::device dev = q -> get_device (); 364// Get the context associated with the queue 365 sycl::context ctx = q -> get_context (); 366const dnnl::engine eng = dnnl::sycl_interop::make_engine (dev ,ctx ); 367return eng ; 368 } 369 370 std::unordered_map < sycl::queue * , dnnl::stream > stream_map ; 371 std::unordered_map < sycl::queue * , dnnl::engine > engine_map ; 372 dnnl::stream stream_dnnl (int device ,int _stream ) { 373auto q = stream (device ,_stream ); 374return stream_dnnl (q ); 375 } 376 dnnl::engine engine_dnnl (sycl::queue * qptr ) { 377auto it = engine_map .find (qptr ); 378if (it == engine_map .end ()) { 379auto eng = make_engine (qptr ); 380engine_map [qptr ]= eng ; 381return eng ; 382 } 383else 384 { 385return it -> second ; 386 } 387 } 388 dnnl::stream stream_dnnl (sycl::queue * qptr ) { 389auto it = stream_map .find (qptr ); 390if (it == stream_map .end ()) { 391auto eng = engine_dnnl (qptr ); 392auto stream = dnnl::sycl_interop::make_stream (eng ,* qptr ); 393stream_map [qptr ]= stream ; 394return stream ; 395 } 396else 397 { 398return it -> second ; 399 } 400 } 401 dnnl::stream stream_dnnl () { 402return stream_dnnl (device ,0 ); 403 } 404#endif 405 406// pool 407 std::unique_ptr < ggml_sycl_pool > pools [GGML_SYCL_MAX_DEVICES ]; 408 409 std::unique_ptr < ggml_sycl_fattn_kv_buffers > fattn_bufs [GGML_SYCL_MAX_DEVICES ]; 410 411 std::unique_ptr < ggml_sycl_pool > host_pools [GGML_SYCL_MAX_DEVICES ]; 412 413 std::vector < mmid_row_mapping > mmid_row_mapping_host ; 414 415static std::unique_ptr < ggml_sycl_pool > new_pool_for_device (queue_ptr qptr ,int device ); 416 417static std::unique_ptr < ggml_sycl_pool > new_pool_for_host (queue_ptr qptr ,int device ); 418 419static std::unique_ptr < ggml_sycl_fattn_kv_buffers > new_fattn_kv_buffers (queue_ptr qptr ,int device ); 420 421ggml_sycl_pool & pool (int device ) { 422if (pools [device ]== nullptr ) { 423pools [device ]= new_pool_for_device (stream (device ,0 ),device ); 424 } 425return * pools [device ]; 426 } 427 428ggml_sycl_pool & pool () { 429return pool (device ); 430 } 431 432ggml_sycl_fattn_kv_buffers & fattn_buffers (int device ) { 433if (fattn_bufs [device ]== nullptr ) { 434fattn_bufs [device ]= new_fattn_kv_buffers (stream (device ,0 ),device ); 435 } 436return * fattn_bufs [device ]; 437 } 438 439ggml_sycl_fattn_kv_buffers & fattn_buffers () { 440return fattn_buffers (device ); 441 } 442 443#ifdef GGML_SYCL_GRAPH 444 std::unique_ptr < sycl_ex::command_graph < sycl_ex::graph_state::executable >> exec_graph = nullptr ; 445#endif 446 447ggml_sycl_pool & host_pool (int device ) { 448if (host_pools [device ]== nullptr ) { 449host_pools [device ]= new_pool_for_host (stream (device ,0 ),device ); 450 } 451return * host_pools [device ]; 452 } 453 454ggml_sycl_pool & host_pool () {return host_pool (device ); } 455}; 456 457// common device functions 458 459static __dpct_inline__ float warp_reduce_sum (float x , 460const sycl::nd_item < 3 >& item_ct1 ) { 461#pragma unroll 462for (int mask = WARP_SIZE /2 ;mask > 0 ;mask >>=1 ) { 463x += dpct::permute_sub_group_by_xor (item_ct1 .get_sub_group (),x ,mask ); 464 } 465return x ; 466} 467 468static __dpct_inline__ sycl::float2 469warp_reduce_sum (sycl::float2 a ,const sycl::nd_item < 3 >& item_ct1 ) { 470#pragma unroll 471for (int mask = WARP_SIZE /2 ;mask > 0 ;mask >>=1 ) { 472a .x ()+= dpct::permute_sub_group_by_xor (item_ct1 .get_sub_group (),a .x (), 473mask ); 474a .y ()+= dpct::permute_sub_group_by_xor (item_ct1 .get_sub_group (),a .y (), 475mask ); 476 } 477return a ; 478} 479 480/* use WARP_SIZE or WARP_32_SIZE*/ 481template < int width > 482static __dpct_inline__ int warp_reduce_sum (int x ) { 483return sycl::reduce_over_group ( 484 sycl::ext::oneapi::this_work_item::get_sub_group (),x , sycl::plus <> ()); 485} 486 487/* use WARP_SIZE or WARP_32_SIZE*/ 488template < int width > 489static __dpct_inline__ float warp_reduce_sum (float x ) { 490#pragma unroll 491for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 492x += dpct::permute_sub_group_by_xor ( 493 sycl::ext::oneapi::this_work_item::get_sub_group (),x ,offset ,width ); 494 } 495return x ; 496} 497 498/* use WARP_SIZE or WARP_32_SIZE*/ 499template < int width > 500static __dpct_inline__ float warp_reduce_sum (float x ,const sycl::nd_item < 3 >& item_ct1 ) { 501#pragma unroll 502for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 503x += dpct::permute_sub_group_by_xor ( 504item_ct1 .get_sub_group (),x ,offset ); 505 } 506return x ; 507} 508 509/* use WARP_SIZE or WARP_32_SIZE*/ 510template < int width > 511static __dpct_inline__ sycl::float2warp_reduce_sum (sycl::float2 a ) { 512#pragma unroll 513for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 514a .x ()+= dpct::permute_sub_group_by_xor ( 515 sycl::ext::oneapi::this_work_item::get_sub_group (),a .x (),offset , 516width ); 517a .y ()+= dpct::permute_sub_group_by_xor ( 518 sycl::ext::oneapi::this_work_item::get_sub_group (),a .y (),offset , 519width ); 520 } 521return a ; 522} 523 524/* use WARP_SIZE or WARP_32_SIZE*/ 525template < int width > 526static __dpct_inline__ sycl::half2warp_reduce_sum (sycl::half2 a ) { 527#pragma unroll 528for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 529a = a + dpct::permute_sub_group_by_xor ( 530 sycl::ext::oneapi::this_work_item::get_sub_group (),a ,offset , 531width ); 532 } 533return a ; 534} 535 536static constexpr int ggml_sycl_get_physical_warp_size () { 537// todo: for old iGPU + dGPU case, need to be changed. 538return WARP_SIZE ; 539} 540 541/* use WARP_SIZE or WARP_32_SIZE*/ 542template < int width > 543static __dpct_inline__ int warp_reduce_all (int x ) { 544if (width == ggml_sycl_get_physical_warp_size ()) { 545return sycl::all_of_group ( 546 sycl::ext::oneapi::this_work_item::get_sub_group (), 547 (~0xffffffff & 548 (0x1 << sycl::ext::oneapi::this_work_item::get_sub_group () 549 .get_local_linear_id ()))|| 550x ); 551 }else { 552#pragma unroll 553for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 554x = dpct::permute_sub_group_by_xor ( 555 sycl::ext::oneapi::this_work_item::get_sub_group (),x , 556offset ,width )&& 557x ; 558 } 559return x ; 560 } 561} 562 563/* use WARP_SIZE or WARP_32_SIZE*/ 564template < int width > 565static __dpct_inline__ int warp_reduce_any (int x ) { 566if (width == ggml_sycl_get_physical_warp_size ()) { 567return sycl::any_of_group ( 568 sycl::ext::oneapi::this_work_item::get_sub_group (), 569 (0xffffffff & 570 (0x1 << sycl::ext::oneapi::this_work_item::get_sub_group () 571 .get_local_linear_id ()))&& 572x ); 573 }else { 574#pragma unroll 575for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 576x = dpct::permute_sub_group_by_xor ( 577 sycl::ext::oneapi::this_work_item::get_sub_group (),x , 578offset ,width )|| 579x ; 580 } 581return x ; 582 } 583} 584 585/* use WARP_SIZE or WARP_32_SIZE*/ 586template < int width > 587static __dpct_inline__ float warp_reduce_max (float x ) { 588#pragma unroll 589for (int offset = width /2 ;offset > 0 ;offset >>=1 ) { 590x = sycl::fmax (x , dpct::permute_sub_group_by_xor ( 591 sycl::ext::oneapi::this_work_item::get_sub_group (),x , 592offset ,width )); 593 } 594return x ; 595} 596 597static __dpct_inline__ float warp_reduce_max (float x , 598const sycl::nd_item < 3 >& item_ct1 ) { 599#pragma unroll 600for (int mask = WARP_SIZE /2 ;mask > 0 ;mask >>=1 ) { 601x = sycl::fmax (x , dpct::permute_sub_group_by_xor ( 602item_ct1 .get_sub_group (),x ,mask )); 603 } 604return x ; 605} 606 607/* Helper for Computing the linear offset of a ggml_tensor given 608per-dimension sizes, strides, and indices */ 609template < int N > 610__dpct_inline__ size_t calculate_offset (const std::array < int ,N > & strides ,const std::array < int ,N > & indices ) { 611size_t offset = 0 ; 612#pragma unroll 613for (int i = 0 ;i < N ;i ++ ) { 614auto index_i = indices [i ]; 615offset += strides [i ]* index_i ; 616 } 617return offset ; 618} 619 620// Helper for vec loading aligned data 621template < typename Tp ,int n > 622inline sycl::vec < Tp ,n > vec_aligned_load (const Tp * aligned_ptr ) { 623return * reinterpret_cast < const sycl::vec < Tp ,n >*> (aligned_ptr ); 624} 625 626// Helper for accessing pointers with no warnings 627template < typename Tp ,int dim > 628static __dpct_inline__ Tp * get_pointer (sycl::local_accessor < Tp ,dim > acc ) { 629return acc .template get_multi_ptr < sycl::access::decorated::no > ().get (); 630} 631 632int64_t downsample_sycl_global_range (int64_t accumulate_block_num ,int64_t block_size ); 633 634constexpr size_t ceil_div (const size_t m ,const size_t n ) { 635return (m + n - 1 ) /n ; 636} 637 638bool gpu_has_xmx (sycl::device & dev ); 639 640int ggml_sycl_get_env (const char * env_name ,int default_val ); 641 642template < int N ,class T > std::string debug_get_array_str (const std::string & prefix ,const T array [N ]) { 643if (LIKELY (!g_ggml_sycl_debug )) { 644return "" ; 645 } 646 std::stringstream ss ; 647ss <<prefix <<"=[" ; 648for (std::size_t i = 0 ;i < N - 1 ;++ i ) { 649ss <<array [i ] <<", " ; 650 } 651if constexpr (N > 0 ) { 652ss <<array [N - 1 ]; 653 } 654ss <<"]" ; 655return ss .str (); 656} 657 658inline std::string debug_get_tensor_str (const std::string & prefix , 659const ggml_tensor * tensor ,const std::string & suffix = "" ) { 660 std::stringstream ss ; 661if (LIKELY (!g_ggml_sycl_debug )) {return ss .str (); } 662ss <<prefix .c_str () <<"=" ; 663if (tensor ) { 664ss <<"'" <<tensor -> name <<"':type=" <<ggml_type_name (tensor -> type ); 665ss <<debug_get_array_str < GGML_MAX_DIMS > (";ne" ,tensor -> ne ); 666ss <<debug_get_array_str < GGML_MAX_DIMS > (";nb" ,tensor -> nb ); 667 668if (!ggml_is_contiguous (tensor )) {ss <<";strided" ; } 669if (ggml_is_permuted (tensor )) {ss <<";permuted" ; } 670 }else { 671ss <<"nullptr" ; 672 } 673ss <<suffix ; 674return ss .str (); 675} 676 677// Use scope_op_debug_print to log operations coming from running a model 678struct scope_op_debug_print { 679// Use string_views to avoid the cost of creating a string and concatenating them 680// string_views must be alive for as long as the object is alive 681// scope_op_debug_print are used with string literals in practice which are stored in constant space so always accessible 682scope_op_debug_print (const std::string_view & func ,const std::string_view & func_suffix ,const ggml_tensor * dst , 683 std::size_t num_src ,const std::string_view & suffix = "" ) : 684func (func ), 685func_suffix (func_suffix ) { 686if (LIKELY (!g_ggml_sycl_debug )) { 687return ; 688 } 689GGML_SYCL_DEBUG ("[SYCL][OP] call %s%s:" ,func .data (),func_suffix .data ()); 690GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str (" dst" ,dst ).c_str ()); 691if (dst ) { 692for (std::size_t i = 0 ;i < num_src ;++ i ) { 693GGML_SYCL_DEBUG ("%s" ,debug_get_tensor_str ("\tsrc" + std::to_string (i ),dst -> src [i ]).c_str ()); 694 } 695 } 696GGML_SYCL_DEBUG ("%s\n" ,suffix .data ()); 697 } 698 699scope_op_debug_print (const std::string_view & func ,const ggml_tensor * dst , std::size_t num_src , 700const std::string_view & suffix = "" ) : 701scope_op_debug_print (func ,"" ,dst ,num_src ,suffix ) {} 702 703 ~scope_op_debug_print () {GGML_SYCL_DEBUG ("[SYCL][OP] call %s%s done\n" ,func .data (),func_suffix .data ()); } 704 705private : 706 std::string_view func ; 707 std::string_view func_suffix ; 708}; 709 710static __dpct_inline__ float get_alibi_slope (const float max_bias , 711const uint32_t h , 712const uint32_t n_head_log2 , 713const float m0 , 714const float m1 ) { 715if (max_bias <=0.0f ) { 716return 1.0f ; 717 } 718const float base = h < n_head_log2 ?m0 :m1 ; 719const int exph = h < n_head_log2 ?h + 1 :2 * (h - n_head_log2 )+ 1 ; 720 721return dpct::pow (base ,exph ); 722} 723 724static const sycl::uint3 init_fastdiv_values (uint32_t d ) { 725GGML_ASSERT (d != 0 ); 726 727uint32_t L = 0 ; 728while (L < 32 && (uint32_t {1 } <<L )< d ) { 729L ++ ; 730 } 731 732uint32_t mp = (uint32_t ) ((uint64_t {1 } <<32 )* ((uint64_t {1 } <<L )- d ) /d + 1 ); 733return sycl::uint3 (mp ,L ,d ); 734} 735 736// Maximum number of bytes that can be copied in a single instruction. 737// Set by test result. 738static constexpr int ggml_sycl_get_max_cpy_bytes () { 739return 16 ; 740} 741 742// Aligned memory transfers of 8/16 bytes can be faster than 2 transfers with 4 bytes. 743template < int nbytes ,int alignment = 0 > 744static __dpct_inline__ void ggml_sycl_memcpy_1 (void * dst ,const void * src ) { 745if constexpr (alignment != 0 ) { 746 static_assert(nbytes %alignment == 0 ,"bad alignment" ); 747 } 748constexpr int nb_per_cpy = alignment == 0 ?nbytes :alignment ; 749 750#pragma unroll 751for (int i = 0 ;i < nbytes /nb_per_cpy ;++ i ) { 752if constexpr (nb_per_cpy == 1 ) { 753 ((char * )dst )[i ]= ((const char * )src )[i ]; 754 }else if constexpr (nb_per_cpy == 2 ) { 755 ((short * )dst )[i ]= ((const short * )src )[i ]; 756 }else if constexpr (nb_per_cpy == 4 ) { 757 ((int * )dst )[i ]= ((const int * )src )[i ]; 758 }else if constexpr (nb_per_cpy == 8 ) { 759 ((sycl::int2 * )dst )[i ]= ((const sycl::int2 * )src )[i ]; 760 }else if constexpr (nb_per_cpy == 16 ) { 761 ((sycl::int4 * )dst )[i ]= ((const sycl::int4 * )src )[i ]; 762 }else { 763 static_assert(nbytes == 0 && nbytes == -1 ,"bad nbytes" ); 764 } 765 } 766} 767template < typename T > 768sycl::half2 __dpct_inline__make_half2 (T x ,T y ) { 769 sycl::half2 res (static_cast < sycl::half > (x ),static_cast < sycl::half > (y )); 770return res ; 771} 772 773static __dpct_inline__ uint32_t fastdiv (uint32_t n ,const sycl::uint3 fastdiv_values ) { 774const uint32_t hi = sycl::mul_hi < unsigned > (n ,fastdiv_values .x ()); 775return (hi + n ) >>fastdiv_values .y (); 776} 777 778 779template < typename T > 780sycl::float2 __dpct_inline__make_float2 (T x ,T y ) { 781 sycl::float2 res (static_cast < float > (x ),static_cast < float > (y )); 782return res ; 783} 784 785sycl::float2 __dpct_inline____half22float2 (sycl::half2 & H ) { 786 sycl::float2 float2_value (static_cast < float > (H .x ()),static_cast < float > (H .y ())); 787return float2_value ; 788} 789 790static __dpct_inline__ sycl::uint2fast_div_modulo (uint32_t n ,const sycl::uint3 fastdiv_values ) { 791const uint32_t div_val = fastdiv (n ,fastdiv_values ); 792const uint32_t mod_val = n - div_val * fastdiv_values .z (); 793return sycl::uint2 (div_val ,mod_val ); 794} 795 796static __dpct_inline__ int ggml_sycl_dp4a (const int a ,const int b ,int c ) { 797return dpct::dp4a (a ,b ,c ); 798} 799 800static __dpct_inline__ float ggml_sycl_e8m0_to_fp32 (uint8_t x ) { 801uint32_t bits ; 802if (x == 0 ) { 803bits = 0x00400000 ; 804 }else { 805bits = (uint32_t )x <<23 ; 806 } 807 808float result ; 809memcpy (& result ,& bits ,sizeof (float )); 810return result ; 811} 812 813sycl::float2 __dpct_inline____half22float2 (const sycl::half2 & H ) { 814 sycl::float2 float2_value (static_cast < float > (H .x ()),static_cast < float > (H .y ())); 815return float2_value ; 816} 817 818float __dpct_inline____half2float (sycl::half H ) { 819return static_cast < float > (H ); 820} 821 822static __dpct_inline__ void ggml_sycl_mad (float & acc ,const float v ,const float u ) { 823acc += v * u ; 824} 825 826static __dpct_inline__ void ggml_sycl_mad (float & acc ,const sycl::float2 v ,const sycl::float2 u ) { 827acc += v .x ()* u .x (); 828acc += v .y ()* u .y (); 829} 830 831static __dpct_inline__ void ggml_sycl_mad (float & acc ,const sycl::half2 v ,const sycl::half2 u ) { 832#ifdef GGML_SYCL_F16 833const sycl::float2 tmp = (v * u ).template convert < float , sycl::rounding_mode::automatic > (); 834acc += tmp .x ()+ tmp .y (); 835#else 836const sycl::float2 tmpv = __half22float2 (v ); 837const sycl::float2 tmpu = __half22float2 (u ); 838acc += tmpv .x ()* tmpu .x (); 839acc += tmpv .y ()* tmpu .y (); 840#endif // GGML_SYCL_F16 841} 842 843static __dpct_inline__ void ggml_sycl_mad (sycl::half2 & acc ,const sycl::half2 v ,const sycl::half2 u ) { 844#ifdef GGML_SYCL_F16 845acc += v * u ; 846#else 847const sycl::float2 tmpv = __half22float2 (v ); 848const sycl::float2 tmpu = __half22float2 (u ); 849 sycl::float2 tmpacc = __half22float2 (acc ); 850// tmpacc.x += tmpv.x() * tmpu.x(); 851// tmpacc.y += tmpv.y() * tmpu.y(); 852 sycl::float2 tmp1 (tmpacc .x ()+ tmpv .x ()* tmpu .x (),tmpacc .y ()+ tmpv .y ()* tmpu .y ()); 853acc = make_half2 (tmp1 .x (),tmp1 .y ()); 854#endif // GGML_SYCL_F16 855} 856 857template < int n > 858struct ggml_sycl_unroll { 859template < typename Func ,typename ...Args > 860void operator()(const Func & f ,Args ...args )const { 861f (n - 1 ,args ...); 862ggml_sycl_unroll < n - 1 > {}(f ,args ...); 863 } 864}; 865 866template <> 867struct ggml_sycl_unroll < 1 > { 868template < typename Func ,typename ...Args > 869void operator()(const Func & f ,Args ...args )const { 870f (0 ,args ...); 871 } 872}; 873 874static __dpct_inline__ sycl::half2ggml_sycl_hmax2 (const sycl::half2 a ,const sycl::half2 b ) { 875 sycl::half2 ret ; 876reinterpret_cast < sycl::half &> (ret .x ())= 877 sycl::vec < float ,1 > (sycl::fmax (a [0 ],b [0 ])).convert < sycl::half , sycl::rounding_mode::automatic > ()[0 ]; 878reinterpret_cast < sycl::half &> (ret .y ())= 879 sycl::vec < float ,1 > (sycl::fmax (a [1 ],b [1 ])).convert < sycl::half , sycl::rounding_mode::automatic > ()[0 ]; 880return ret ; 881} 882 883static __dpct_inline__ sycl::half ggml_sycl_hmax (const sycl::half a ,const sycl::half b ) { 884return sycl::vec < float ,1 > ( 885 sycl::fmax (sycl::vec < sycl::half ,1 > (a ).convert < float , sycl::rounding_mode::automatic > ()[0 ], 886 sycl::vec < sycl::half ,1 > (b ).convert < float , sycl::rounding_mode::automatic > ()[0 ])) 887 .convert < sycl::half , sycl::rounding_mode::automatic > ()[0 ]; 888} 889 890static __dpct_inline__ uint32_t __hgt2_mask (const sycl::half2 a ,const sycl::half2 b ) { 891const uint32_t mask_low = 0x0000FFFF * (float (a [0 ])> float (b [0 ])); 892const uint32_t mask_high = 0xFFFF0000 * (float (a [1 ])> float (b [1 ])); 893return mask_low |mask_high ; 894} 895 896static __dpct_inline__ uint32_t fastmodulo (uint32_t n ,const sycl::uint3 fastdiv_values ) { 897// expects fastdiv_values to contain <mp, L, divisor> in <x, y, z> (see init_fastdiv_values) 898return n - fastdiv (n ,fastdiv_values )* fastdiv_values .z (); 899} 900 901static bool fast_fp16_available (const int cc ) { 902GGML_UNUSED (cc ); 903return true;//Intel GPUs always support FP16. 904} 905 906enum class block_reduce_method { 907MAX , 908SUM , 909}; 910 911template < block_reduce_method method_t ,typename T ,int warp_size > 912struct block_reduce_policy ; 913 914template < typename T ,typename ...Ts > 915inline constexpr bool is_any = (std::is_same_v < T ,Ts > || ...); 916 917template < typename ...> 918inline constexpr bool ggml_sycl_dependent_false_v = false; 919 920#define WARP_32_SIZE 32 921 922template < typename T ,int warp_size > struct block_reduce_policy < block_reduce_method::SUM ,T ,warp_size > { 923static T reduce (T val ) { 924if constexpr (is_any < T ,float , sycl::float2 , sycl::half2 ,int > ) { 925return warp_reduce_sum < warp_size > (val ); 926 }else { 927 static_assert(ggml_sycl_dependent_false_v < T > ,"Unsupported type for block reduce sum" ); 928 } 929 } 930 931static T sentinel () { 932if constexpr (std::is_same_v < T ,float > ) { 933return 0.0f ; 934 }else if constexpr (std::is_same_v < T , sycl::float2 > ) { 935return sycl::float2 (0.0f ,0.0f ); 936 }else if constexpr (std::is_same_v < T , sycl::half2 > ) { 937return sycl::half2 (0.0f ,0.0f ); 938 }else if constexpr (std::is_same_v < T ,int > ) { 939return 0 ; 940 }else { 941 static_assert(ggml_sycl_dependent_false_v < T > ,"Unsupported type for block reduce sum" ); 942 } 943 } 944}; 945 946template < typename T ,int warp_size > struct block_reduce_policy < block_reduce_method::MAX ,T ,warp_size > { 947static T reduce (T val ) { 948if constexpr (is_any < T ,float , sycl::half2 > ) { 949return warp_reduce_max < warp_size > (val ); 950 }else { 951 static_assert(ggml_sycl_dependent_false_v < T > ,"Unsupported type for block reduce max" ); 952 } 953 } 954 955static T sentinel () { 956if constexpr (std::is_same_v < T ,float > ) { 957return - INFINITY ; 958 }else if constexpr (std::is_same_v < T , sycl::half2 > ) { 959return sycl::half2 (- INFINITY ,- INFINITY ); 960 }else { 961 static_assert(ggml_sycl_dependent_false_v < T > ,"Unsupported type for block reduce max" ); 962 } 963 } 964}; 965 966 967template < block_reduce_method reduce_method_t ,int warp_size ,typename T > 968static T block_reduce (T val ,T * shared_vals ,int block_size_template ) { 969auto item_ct1 = sycl::ext::oneapi::this_work_item::get_nd_item < 3 > (); 970val = block_reduce_policy < reduce_method_t ,T ,warp_size > ::reduce (val ); 971const int block_size = block_size_template == 0 ?item_ct1 .get_local_range (2 ) :block_size_template ; 972const int nthreads = item_ct1 .get_local_range (2 ); 973const int nwarps = nthreads /WARP_SIZE ; 974 975if (block_size > warp_size ) { 976assert ((block_size <=1024 )&& (block_size %warp_size )== 0 ); 977const int warp_id = item_ct1 .get_local_id (2 ) /warp_size ; 978const int lane_id = item_ct1 .get_local_id (2 ) %warp_size ; 979if (lane_id == 0 ) { 980shared_vals [warp_id ]= val ; 981 } 982item_ct1 .barrier (sycl::access::fence_space::local_space ); 983 984size_t nreduce = nwarps /WARP_SIZE ; 985float tmp = 0.f ; 986if (lane_id < (static_cast < int > (block_size ) /warp_size )) { 987for (size_t i = 0 ;i < nreduce ;i += 1 ) 988 { 989tmp += shared_vals [lane_id + i * WARP_SIZE ]; 990 } 991 } 992return block_reduce_policy < reduce_method_t ,T ,warp_size > ::reduce (tmp ); 993 } 994return val ; 995} 996 997static __dpct_inline__ float ggml_sycl_ue4m3_to_fp32 (uint8_t x ) { 998// UE4M3 is unsigned: 4 exp bits (bias 7), 3 mantissa bits, no sign, no NaN. 999// exp == 0xF is a valid exponent (256-448 range), not NaN. 1000if (x == 0 || x == 0x7F ) { 1001return 0.0f ; 1002 } 1003const int exp = (x >>3 )& 0xF ; 1004const int man = x & 0x7 ; 1005float raw ; 1006if (exp == 0 ) { 1007raw = man * (1.0f /8.0f )* sycl::pow (2.0f ,-6.0f ); 1008 }else { 1009raw = (1.0f + man /8.0f )* sycl::pow (2.0f , (float )exp - 7.0f ); 1010 } 1011return raw * 0.5f ; 1012} 1013 1014#endif // GGML_SYCL_COMMON_HPP