Skip to content

Commit ebbd4c7

Browse files
airMengNuullll
authored andcommitted
[SYCL] remove global variables (#7710)
* separate DPCT helpers outside * replace global variables with context * remove useless extra * update mul_mat condition * remove duplicate buft initialization * remove duplicate extra and global work group size * remove useless backend check * remove duplicated extras * use macro for group_size and remove cuda-related
1 parent dee0d41 commit ebbd4c7

File tree

5 files changed

+3418
-0
lines changed

5 files changed

+3418
-0
lines changed

src/ggml-sycl/backend.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
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_BACKEND_HPP
14+
#define GGML_SYCL_BACKEND_HPP
15+
16+
#include "common.hpp"
17+
18+
#endif // GGML_SYCL_BACKEND_HPP

src/ggml-sycl/common.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 "common.hpp"
14+
15+
int get_current_device_id() {
16+
return dpct::dev_mgr::instance().current_device_id();
17+
}
18+
19+
void* ggml_sycl_host_malloc(size_t size) try {
20+
if (getenv("GGML_SYCL_NO_PINNED") != nullptr) {
21+
return nullptr;
22+
}
23+
24+
void* ptr = nullptr;
25+
// allow to use dpct::get_in_order_queue() for host malloc
26+
dpct::err0 err = CHECK_TRY_ERROR(
27+
ptr = (void*)sycl::malloc_host(size, dpct::get_in_order_queue()));
28+
29+
if (err != 0) {
30+
// clear the error
31+
fprintf(
32+
stderr,
33+
"WARNING: failed to allocate %.2f MB of pinned memory: %s\n",
34+
size / 1024.0 / 1024.0,
35+
"syclGetErrorString is not supported");
36+
return nullptr;
37+
}
38+
39+
return ptr;
40+
} catch (sycl::exception const& exc) {
41+
std::cerr << exc.what() << "Exception caught at file:" << __FILE__
42+
<< ", line:" << __LINE__ << std::endl;
43+
std::exit(1);
44+
}
45+
46+
void ggml_sycl_host_free(void* ptr) try {
47+
// allow to use dpct::get_in_order_queue() for host malloc
48+
SYCL_CHECK(CHECK_TRY_ERROR(sycl::free(ptr, dpct::get_in_order_queue())));
49+
} catch (sycl::exception const& exc) {
50+
std::cerr << exc.what() << "Exception caught at file:" << __FILE__
51+
<< ", line:" << __LINE__ << std::endl;
52+
std::exit(1);
53+
}

src/ggml-sycl/common.hpp

Lines changed: 298 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,298 @@
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 <fstream>
17+
#include <iostream>
18+
19+
#include "dpct/helper.hpp"
20+
#include "presets.hpp"
21+
22+
#define GGML_COMMON_DECL_SYCL
23+
#define GGML_COMMON_IMPL_SYCL
24+
#include "ggml-common.h"
25+
26+
void* ggml_sycl_host_malloc(size_t size);
27+
void ggml_sycl_host_free(void* ptr);
28+
29+
static int g_ggml_sycl_debug = 0;
30+
#define GGML_SYCL_DEBUG(...) \
31+
do { \
32+
if (g_ggml_sycl_debug) \
33+
fprintf(stderr, __VA_ARGS__); \
34+
} while (0)
35+
36+
#define CHECK_TRY_ERROR(expr) \
37+
[&]() { \
38+
try { \
39+
expr; \
40+
return dpct::success; \
41+
} catch (std::exception const& e) { \
42+
std::cerr << e.what() << "\nException caught at file:" << __FILE__ \
43+
<< ", line:" << __LINE__ << ", func:" << __func__ \
44+
<< std::endl; \
45+
return dpct::default_error; \
46+
} \
47+
}()
48+
49+
// #define DEBUG_SYCL_MALLOC
50+
51+
static int g_work_group_size = 0;
52+
// typedef sycl::half ggml_fp16_t;
53+
54+
#define __SYCL_ARCH__ DPCT_COMPATIBILITY_TEMP
55+
#define VER_4VEC 610 // todo for hardward optimize.
56+
#define VER_GEN9 700 // todo for hardward optimize.
57+
#define VER_GEN12 1000000 // todo for hardward optimize.
58+
#define VER_GEN13 (VER_GEN12 + 1030) // todo for hardward optimize.
59+
60+
#define GGML_SYCL_MAX_NODES 8192 // TODO: adapt to hardwares
61+
62+
// define for XMX in Intel GPU
63+
// TODO: currently, it's not used for XMX really.
64+
#if !defined(GGML_SYCL_FORCE_MMQ)
65+
#define SYCL_USE_XMX
66+
#endif
67+
68+
// max batch size to use MMQ kernels when tensor cores are available
69+
#define MMQ_MAX_BATCH_SIZE 32
70+
71+
#if defined(_MSC_VER)
72+
#pragma warning(disable : 4244 4267) // possible loss of data
73+
#endif
74+
75+
// dmmv = dequantize_mul_mat_vec
76+
#ifndef GGML_SYCL_DMMV_X
77+
#define GGML_SYCL_DMMV_X 32
78+
#endif
79+
#ifndef GGML_SYCL_MMV_Y
80+
#define GGML_SYCL_MMV_Y 1
81+
#endif
82+
83+
typedef sycl::queue *queue_ptr;
84+
85+
enum ggml_sycl_backend_gpu_mode {
86+
SYCL_UNSET_GPU_MODE = -1,
87+
SYCL_SINGLE_GPU_MODE = 0,
88+
SYCL_MUL_GPU_MODE
89+
};
90+
91+
static_assert(sizeof(sycl::half) == sizeof(ggml_fp16_t), "wrong fp16 size");
92+
93+
static void crash() {
94+
int* ptr = NULL;
95+
*ptr = 0;
96+
}
97+
98+
[[noreturn]] static void ggml_sycl_error(
99+
const char* stmt,
100+
const char* func,
101+
const char* file,
102+
const int line,
103+
const char* msg) {
104+
fprintf(stderr, "SYCL error: %s: %s\n", stmt, msg);
105+
fprintf(stderr, " in function %s at %s:%d\n", func, file, line);
106+
GGML_ASSERT(!"SYCL error");
107+
}
108+
109+
#define SYCL_CHECK(err) \
110+
do { \
111+
auto err_ = (err); \
112+
if (err_ != 0) \
113+
ggml_sycl_error( \
114+
#err, \
115+
__func__, \
116+
__FILE__, \
117+
__LINE__, \
118+
"Meet error in this line code!"); \
119+
} while (0)
120+
121+
#if DPCT_COMPAT_RT_VERSION >= 11100
122+
#define GGML_SYCL_ASSUME(x) __builtin_assume(x)
123+
#else
124+
#define GGML_SYCL_ASSUME(x)
125+
#endif // DPCT_COMPAT_RT_VERSION >= 11100
126+
127+
#ifdef GGML_SYCL_F16
128+
typedef sycl::half dfloat; // dequantize float
129+
typedef sycl::half2 dfloat2;
130+
#else
131+
typedef float dfloat; // dequantize float
132+
typedef sycl::float2 dfloat2;
133+
#endif // GGML_SYCL_F16
134+
135+
#define MMVQ_MAX_BATCH_SIZE 8
136+
137+
static const int8_t kvalues_iq4nl[16]={-127, -104, -83, -65, -49, -35, -22, -10, 1, 13, 25, 38, 53, 69, 89, 113};
138+
139+
static int g_all_sycl_device_count = -1;
140+
static bool g_ggml_backend_sycl_buffer_type_initialized = false;
141+
142+
static ggml_sycl_backend_gpu_mode g_ggml_sycl_backend_gpu_mode =
143+
SYCL_UNSET_GPU_MODE;
144+
145+
static void* g_scratch_buffer = nullptr;
146+
static size_t g_scratch_size = 0; // disabled by default
147+
static size_t g_scratch_offset = 0;
148+
149+
[[noreturn]] static inline void bad_arch(const sycl::stream& stream_ct1) {
150+
stream_ct1 << "ERROR: ggml-sycl was compiled without support for the "
151+
"current GPU architecture.\n";
152+
// __trap();
153+
std::exit(1);
154+
155+
(void)bad_arch; // suppress unused function warning
156+
}
157+
158+
int get_current_device_id();
159+
160+
inline dpct::err0 ggml_sycl_set_device(const int device) try {
161+
162+
int current_device_id;
163+
SYCL_CHECK(CHECK_TRY_ERROR(current_device_id = get_current_device_id()));
164+
165+
// GGML_SYCL_DEBUG("ggml_sycl_set_device device_id=%d,
166+
// current_device_id=%d\n", device, current_device);
167+
if (device == current_device_id) {
168+
return 0;
169+
}
170+
171+
return CHECK_TRY_ERROR(dpct::select_device(device));
172+
} catch (sycl::exception const& exc) {
173+
std::cerr << exc.what() << "Exception caught at file:" << __FILE__
174+
<< ", line:" << __LINE__ << std::endl;
175+
crash();
176+
std::exit(1);
177+
}
178+
179+
//////////////////////
180+
181+
struct ggml_sycl_device_info {
182+
int device_count;
183+
184+
struct sycl_device_info {
185+
int cc; // compute capability
186+
// int nsm; // number of streaming multiprocessors
187+
// size_t smpb; // max. shared memory per block
188+
bool vmm; // virtual memory support
189+
size_t total_vram;
190+
};
191+
192+
sycl_device_info devices[GGML_SYCL_MAX_DEVICES] = {};
193+
194+
std::array<float, GGML_SYCL_MAX_DEVICES> default_tensor_split = {};
195+
};
196+
197+
const ggml_sycl_device_info & ggml_sycl_info();
198+
199+
struct ggml_sycl_pool {
200+
virtual ~ggml_sycl_pool() = default;
201+
202+
virtual void * alloc(size_t size, size_t * actual_size) = 0;
203+
virtual void free(void * ptr, size_t size) = 0;
204+
};
205+
206+
template<typename T>
207+
struct ggml_sycl_pool_alloc {
208+
ggml_sycl_pool * pool = nullptr;
209+
T * ptr = nullptr;
210+
size_t actual_size = 0;
211+
212+
explicit ggml_sycl_pool_alloc(ggml_sycl_pool & pool) : pool(&pool) {
213+
}
214+
215+
ggml_sycl_pool_alloc(ggml_sycl_pool & pool, size_t size) : pool(&pool) {
216+
alloc(size);
217+
}
218+
219+
~ggml_sycl_pool_alloc() {
220+
if (ptr != nullptr) {
221+
pool->free(ptr, actual_size);
222+
}
223+
}
224+
225+
// size is in number of elements
226+
T * alloc(size_t size) {
227+
GGML_ASSERT(pool != nullptr);
228+
GGML_ASSERT(ptr == nullptr);
229+
ptr = (T *) pool->alloc(size * sizeof(T), &this->actual_size);
230+
return ptr;
231+
}
232+
233+
T * alloc(ggml_sycl_pool & pool, size_t size) {
234+
this->pool = &pool;
235+
return alloc(size);
236+
}
237+
238+
T * get() {
239+
return ptr;
240+
}
241+
242+
ggml_sycl_pool_alloc() = default;
243+
ggml_sycl_pool_alloc(const ggml_sycl_pool_alloc &) = delete;
244+
ggml_sycl_pool_alloc(ggml_sycl_pool_alloc &&) = delete;
245+
ggml_sycl_pool_alloc& operator=(const ggml_sycl_pool_alloc &) = delete;
246+
ggml_sycl_pool_alloc& operator=(ggml_sycl_pool_alloc &&) = delete;
247+
};
248+
249+
// backend interface
250+
251+
struct ggml_tensor_extra_gpu {
252+
void* data_device[GGML_SYCL_MAX_DEVICES]; // 1 pointer for each device for split
253+
// tensors
254+
dpct::event_ptr events[GGML_SYCL_MAX_DEVICES]
255+
[GGML_SYCL_MAX_STREAMS]; // events for synchronizing multiple GPUs
256+
};
257+
258+
struct ggml_backend_sycl_context {
259+
int device;
260+
std::string name;
261+
262+
queue_ptr qptrs[GGML_SYCL_MAX_DEVICES][GGML_SYCL_MAX_STREAMS] = { { nullptr } };
263+
264+
explicit ggml_backend_sycl_context(int device) :
265+
device(device),
266+
name(GGML_SYCL_NAME + std::to_string(device)) {
267+
}
268+
269+
queue_ptr stream(int device, int stream) {
270+
if (qptrs[device][stream] == nullptr) {
271+
qptrs[device][stream] = &(dpct::get_current_device().default_queue());
272+
}
273+
return qptrs[device][stream];
274+
}
275+
276+
queue_ptr stream() {
277+
return stream(device, 0);
278+
}
279+
280+
// pool
281+
std::unique_ptr<ggml_sycl_pool> pools[GGML_SYCL_MAX_DEVICES];
282+
283+
static std::unique_ptr<ggml_sycl_pool> new_pool_for_device(queue_ptr qptr, int device);
284+
285+
ggml_sycl_pool & pool(int device) {
286+
if (pools[device] == nullptr) {
287+
pools[device] = new_pool_for_device(stream(device,0), device);
288+
}
289+
return *pools[device];
290+
}
291+
292+
ggml_sycl_pool & pool() {
293+
return pool(device);
294+
}
295+
};
296+
297+
298+
#endif // GGML_SYCL_COMMON_HPP

0 commit comments

Comments
 (0)