llama-cpp-capacitor 0.0.6 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. package/cpp/LICENSE +21 -0
  2. package/cpp/README.md +4 -0
  3. package/cpp/anyascii.c +22223 -0
  4. package/cpp/anyascii.h +42 -0
  5. package/cpp/chat-parser.cpp +393 -0
  6. package/cpp/chat-parser.h +120 -0
  7. package/cpp/chat.cpp +2315 -0
  8. package/cpp/chat.h +221 -0
  9. package/cpp/common.cpp +1619 -0
  10. package/cpp/common.h +744 -0
  11. package/cpp/ggml-alloc.c +1028 -0
  12. package/cpp/ggml-alloc.h +76 -0
  13. package/cpp/ggml-backend-impl.h +255 -0
  14. package/cpp/ggml-backend-reg.cpp +600 -0
  15. package/cpp/ggml-backend.cpp +2118 -0
  16. package/cpp/ggml-backend.h +354 -0
  17. package/cpp/ggml-common.h +1878 -0
  18. package/cpp/ggml-cpp.h +39 -0
  19. package/cpp/ggml-cpu/amx/amx.cpp +221 -0
  20. package/cpp/ggml-cpu/amx/amx.h +8 -0
  21. package/cpp/ggml-cpu/amx/common.h +91 -0
  22. package/cpp/ggml-cpu/amx/mmq.cpp +2512 -0
  23. package/cpp/ggml-cpu/amx/mmq.h +10 -0
  24. package/cpp/ggml-cpu/arch/arm/cpu-feats.cpp +94 -0
  25. package/cpp/ggml-cpu/arch/arm/quants.c +3650 -0
  26. package/cpp/ggml-cpu/arch/arm/repack.cpp +1891 -0
  27. package/cpp/ggml-cpu/arch/x86/cpu-feats.cpp +327 -0
  28. package/cpp/ggml-cpu/arch/x86/quants.c +3820 -0
  29. package/cpp/ggml-cpu/arch/x86/repack.cpp +6307 -0
  30. package/cpp/ggml-cpu/arch-fallback.h +215 -0
  31. package/cpp/ggml-cpu/binary-ops.cpp +158 -0
  32. package/cpp/ggml-cpu/binary-ops.h +16 -0
  33. package/cpp/ggml-cpu/common.h +73 -0
  34. package/cpp/ggml-cpu/ggml-cpu-impl.h +525 -0
  35. package/cpp/ggml-cpu/ggml-cpu.c +3578 -0
  36. package/cpp/ggml-cpu/ggml-cpu.cpp +672 -0
  37. package/cpp/ggml-cpu/ops.cpp +10587 -0
  38. package/cpp/ggml-cpu/ops.h +114 -0
  39. package/cpp/ggml-cpu/quants.c +1193 -0
  40. package/cpp/ggml-cpu/quants.h +97 -0
  41. package/cpp/ggml-cpu/repack.cpp +1982 -0
  42. package/cpp/ggml-cpu/repack.h +120 -0
  43. package/cpp/ggml-cpu/simd-mappings.h +1184 -0
  44. package/cpp/ggml-cpu/traits.cpp +36 -0
  45. package/cpp/ggml-cpu/traits.h +38 -0
  46. package/cpp/ggml-cpu/unary-ops.cpp +186 -0
  47. package/cpp/ggml-cpu/unary-ops.h +28 -0
  48. package/cpp/ggml-cpu/vec.cpp +348 -0
  49. package/cpp/ggml-cpu/vec.h +1121 -0
  50. package/cpp/ggml-cpu.h +145 -0
  51. package/cpp/ggml-impl.h +622 -0
  52. package/cpp/ggml-metal-impl.h +688 -0
  53. package/cpp/ggml-metal.h +66 -0
  54. package/cpp/ggml-metal.m +6833 -0
  55. package/cpp/ggml-opt.cpp +1093 -0
  56. package/cpp/ggml-opt.h +256 -0
  57. package/cpp/ggml-quants.c +5324 -0
  58. package/cpp/ggml-quants.h +106 -0
  59. package/cpp/ggml-threading.cpp +12 -0
  60. package/cpp/ggml-threading.h +14 -0
  61. package/cpp/ggml.c +7108 -0
  62. package/cpp/ggml.h +2492 -0
  63. package/cpp/gguf.cpp +1358 -0
  64. package/cpp/gguf.h +202 -0
  65. package/cpp/json-partial.cpp +256 -0
  66. package/cpp/json-partial.h +38 -0
  67. package/cpp/json-schema-to-grammar.cpp +985 -0
  68. package/cpp/json-schema-to-grammar.h +21 -0
  69. package/cpp/llama-adapter.cpp +388 -0
  70. package/cpp/llama-adapter.h +76 -0
  71. package/cpp/llama-arch.cpp +2355 -0
  72. package/cpp/llama-arch.h +499 -0
  73. package/cpp/llama-batch.cpp +875 -0
  74. package/cpp/llama-batch.h +160 -0
  75. package/cpp/llama-chat.cpp +783 -0
  76. package/cpp/llama-chat.h +65 -0
  77. package/cpp/llama-context.cpp +2748 -0
  78. package/cpp/llama-context.h +306 -0
  79. package/cpp/llama-cparams.cpp +5 -0
  80. package/cpp/llama-cparams.h +41 -0
  81. package/cpp/llama-cpp.h +30 -0
  82. package/cpp/llama-grammar.cpp +1229 -0
  83. package/cpp/llama-grammar.h +173 -0
  84. package/cpp/llama-graph.cpp +1891 -0
  85. package/cpp/llama-graph.h +810 -0
  86. package/cpp/llama-hparams.cpp +180 -0
  87. package/cpp/llama-hparams.h +233 -0
  88. package/cpp/llama-impl.cpp +167 -0
  89. package/cpp/llama-impl.h +61 -0
  90. package/cpp/llama-io.cpp +15 -0
  91. package/cpp/llama-io.h +35 -0
  92. package/cpp/llama-kv-cache-iswa.cpp +318 -0
  93. package/cpp/llama-kv-cache-iswa.h +135 -0
  94. package/cpp/llama-kv-cache.cpp +2059 -0
  95. package/cpp/llama-kv-cache.h +374 -0
  96. package/cpp/llama-kv-cells.h +491 -0
  97. package/cpp/llama-memory-hybrid.cpp +258 -0
  98. package/cpp/llama-memory-hybrid.h +137 -0
  99. package/cpp/llama-memory-recurrent.cpp +1146 -0
  100. package/cpp/llama-memory-recurrent.h +179 -0
  101. package/cpp/llama-memory.cpp +59 -0
  102. package/cpp/llama-memory.h +119 -0
  103. package/cpp/llama-mmap.cpp +600 -0
  104. package/cpp/llama-mmap.h +68 -0
  105. package/cpp/llama-model-loader.cpp +1164 -0
  106. package/cpp/llama-model-loader.h +170 -0
  107. package/cpp/llama-model-saver.cpp +282 -0
  108. package/cpp/llama-model-saver.h +37 -0
  109. package/cpp/llama-model.cpp +19042 -0
  110. package/cpp/llama-model.h +491 -0
  111. package/cpp/llama-sampling.cpp +2575 -0
  112. package/cpp/llama-sampling.h +32 -0
  113. package/cpp/llama-vocab.cpp +3792 -0
  114. package/cpp/llama-vocab.h +176 -0
  115. package/cpp/llama.cpp +358 -0
  116. package/cpp/llama.h +1373 -0
  117. package/cpp/log.cpp +427 -0
  118. package/cpp/log.h +103 -0
  119. package/cpp/minja/chat-template.hpp +550 -0
  120. package/cpp/minja/minja.hpp +3009 -0
  121. package/cpp/nlohmann/json.hpp +25526 -0
  122. package/cpp/nlohmann/json_fwd.hpp +187 -0
  123. package/cpp/regex-partial.cpp +204 -0
  124. package/cpp/regex-partial.h +56 -0
  125. package/cpp/rn-completion.cpp +681 -0
  126. package/cpp/rn-completion.h +116 -0
  127. package/cpp/rn-llama.cpp +345 -0
  128. package/cpp/rn-llama.h +149 -0
  129. package/cpp/rn-mtmd.hpp +602 -0
  130. package/cpp/rn-tts.cpp +591 -0
  131. package/cpp/rn-tts.h +59 -0
  132. package/cpp/sampling.cpp +579 -0
  133. package/cpp/sampling.h +107 -0
  134. package/cpp/tools/mtmd/clip-impl.h +473 -0
  135. package/cpp/tools/mtmd/clip.cpp +4322 -0
  136. package/cpp/tools/mtmd/clip.h +106 -0
  137. package/cpp/tools/mtmd/miniaudio/miniaudio.h +93468 -0
  138. package/cpp/tools/mtmd/mtmd-audio.cpp +769 -0
  139. package/cpp/tools/mtmd/mtmd-audio.h +47 -0
  140. package/cpp/tools/mtmd/mtmd-helper.cpp +460 -0
  141. package/cpp/tools/mtmd/mtmd-helper.h +91 -0
  142. package/cpp/tools/mtmd/mtmd.cpp +1066 -0
  143. package/cpp/tools/mtmd/mtmd.h +298 -0
  144. package/cpp/tools/mtmd/stb/stb_image.h +7988 -0
  145. package/cpp/unicode-data.cpp +7034 -0
  146. package/cpp/unicode-data.h +20 -0
  147. package/cpp/unicode.cpp +1061 -0
  148. package/cpp/unicode.h +68 -0
  149. package/package.json +2 -1
@@ -0,0 +1,3578 @@
1
+ #define _CRT_SECURE_NO_DEPRECATE // Disables "unsafe" warnings on Windows
2
+ #define _USE_MATH_DEFINES // For M_PI on MSVC
3
+
4
+ #include "ggml-backend-impl.h"
5
+ #include "ggml-backend.h"
6
+ #include "traits.h"
7
+ #include "ggml-cpu-impl.h"
8
+ #include "ggml-cpu.h"
9
+ #include "ggml-impl.h"
10
+ #include "quants.h"
11
+ #include "ggml-threading.h"
12
+ #include "unary-ops.h"
13
+ #include "binary-ops.h"
14
+ #include "vec.h"
15
+ #include "ops.h"
16
+ #include "ggml.h"
17
+
18
+ #if defined(_MSC_VER) || defined(__MINGW32__)
19
+ #include <malloc.h> // using malloc.h with MSC/MINGW
20
+ #elif !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
21
+ #include <alloca.h>
22
+ #endif
23
+
24
+ #include <assert.h>
25
+ #include <errno.h>
26
+ #include <time.h>
27
+ #include <math.h>
28
+ #include <stdlib.h>
29
+ #include <string.h>
30
+ #include <stdint.h>
31
+ #include <inttypes.h>
32
+ #include <stdio.h>
33
+ #include <float.h>
34
+ #include <limits.h>
35
+ #include <stdarg.h>
36
+ #include <signal.h>
37
+ #if defined(__gnu_linux__)
38
+ #include <syscall.h>
39
+ #endif
40
+
41
+ #ifdef LM_GGML_USE_OPENMP
42
+ #include <omp.h>
43
+ #endif
44
+
45
+ #if defined(__ARM_FEATURE_SVE) || defined(__ARM_FEATURE_MATMUL_INT8)
46
+ #undef LM_GGML_USE_LLAMAFILE
47
+ #endif
48
+
49
+ #ifdef LM_GGML_USE_LLAMAFILE
50
+ #include "llamafile/sgemm.h"
51
+ #endif
52
+
53
+ // Note: once we move threading into a separate C++ file
54
+ // will use std::hardware_destructive_interference_size instead of hardcoding it here
55
+ // and we'll use C++ attribute syntax.
56
+ #define LM_GGML_CACHE_LINE 64
57
+
58
+ #if defined(__clang__) || defined(__GNUC__)
59
+ #define LM_GGML_CACHE_ALIGN __attribute__((aligned(LM_GGML_CACHE_LINE)))
60
+ #endif
61
+
62
+ #if defined(__has_feature)
63
+ #if __has_feature(thread_sanitizer)
64
+ #define LM_GGML_TSAN_ENABLED 1
65
+ #endif
66
+ #else // __has_feature
67
+ #if defined(__SANITIZE_THREAD__)
68
+ #define LM_GGML_TSAN_ENABLED 1
69
+ #endif
70
+ #endif // __has_feature
71
+
72
+ #define UNUSED LM_GGML_UNUSED
73
+ #define SWAP(x, y, T) do { T SWAP = x; (x) = y; (y) = SWAP; } while (0)
74
+
75
+ // precomputed f32 table for f16 (256 KB) (simd-mappings.h)
76
+ float lm_ggml_table_f32_f16[1 << 16];
77
+
78
+ #if defined(__ARM_ARCH)
79
+ struct lm_ggml_arm_arch_features_type {
80
+ int sve_cnt;
81
+ } lm_ggml_arm_arch_features = { 0 };
82
+ #endif
83
+
84
+
85
+ #if defined(_WIN32)
86
+
87
+ #define WIN32_LEAN_AND_MEAN
88
+ #ifndef NOMINMAX
89
+ #define NOMINMAX
90
+ #endif
91
+ #include <windows.h>
92
+
93
+ #if defined(_MSC_VER) && !defined(__clang__)
94
+ #define LM_GGML_CACHE_ALIGN __declspec(align(LM_GGML_CACHE_LINE))
95
+
96
+ typedef volatile LONG atomic_int;
97
+ typedef atomic_int atomic_bool;
98
+ typedef atomic_int atomic_flag;
99
+
100
+ #define ATOMIC_FLAG_INIT 0
101
+
102
+ typedef enum {
103
+ memory_order_relaxed,
104
+ memory_order_consume,
105
+ memory_order_acquire,
106
+ memory_order_release,
107
+ memory_order_acq_rel,
108
+ memory_order_seq_cst
109
+ } memory_order;
110
+
111
+ static void atomic_store(atomic_int * ptr, LONG val) {
112
+ InterlockedExchange(ptr, val);
113
+ }
114
+ static void atomic_store_explicit(atomic_int * ptr, LONG val, memory_order mo) {
115
+ // TODO: add support for explicit memory order
116
+ InterlockedExchange(ptr, val);
117
+ }
118
+ static LONG atomic_load(atomic_int * ptr) {
119
+ return InterlockedCompareExchange(ptr, 0, 0);
120
+ }
121
+ static LONG atomic_load_explicit(atomic_int * ptr, memory_order mo) {
122
+ // TODO: add support for explicit memory order
123
+ return InterlockedCompareExchange(ptr, 0, 0);
124
+ }
125
+ static LONG atomic_fetch_add(atomic_int * ptr, LONG inc) {
126
+ return InterlockedExchangeAdd(ptr, inc);
127
+ }
128
+ static LONG atomic_fetch_add_explicit(atomic_int * ptr, LONG inc, memory_order mo) {
129
+ // TODO: add support for explicit memory order
130
+ return InterlockedExchangeAdd(ptr, inc);
131
+ }
132
+ static atomic_bool atomic_flag_test_and_set(atomic_flag * ptr) {
133
+ return InterlockedExchange(ptr, 1);
134
+ }
135
+ static void atomic_flag_clear(atomic_flag * ptr) {
136
+ InterlockedExchange(ptr, 0);
137
+ }
138
+ static void atomic_thread_fence(memory_order mo) {
139
+ MemoryBarrier();
140
+ }
141
+ #else // clang
142
+ #include <stdatomic.h>
143
+ #endif
144
+
145
+ typedef HANDLE pthread_t;
146
+
147
+ typedef DWORD thread_ret_t;
148
+ static int pthread_create(pthread_t * out, void * unused, thread_ret_t(*func)(void *), void * arg) {
149
+ (void) unused;
150
+ HANDLE handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, arg, 0, NULL);
151
+ if (handle == NULL)
152
+ {
153
+ return EAGAIN;
154
+ }
155
+
156
+ *out = handle;
157
+ return 0;
158
+ }
159
+
160
+ static int pthread_join(pthread_t thread, void * unused) {
161
+ (void) unused;
162
+ int ret = (int) WaitForSingleObject(thread, INFINITE);
163
+ CloseHandle(thread);
164
+ return ret;
165
+ }
166
+
167
+ static int sched_yield (void) {
168
+ Sleep (0);
169
+ return 0;
170
+ }
171
+ #else
172
+
173
+ #include <pthread.h>
174
+ #include <stdatomic.h>
175
+ #include <sched.h>
176
+ #if defined(__FreeBSD__)
177
+ #include <pthread_np.h>
178
+ #endif
179
+
180
+ typedef void * thread_ret_t;
181
+
182
+ #include <sys/types.h>
183
+ #include <sys/stat.h>
184
+ #include <unistd.h>
185
+
186
+ #endif
187
+
188
+ typedef pthread_t lm_ggml_thread_t;
189
+
190
+ #if defined(__APPLE__)
191
+ #include <unistd.h>
192
+ #include <mach/mach.h>
193
+ #include <TargetConditionals.h>
194
+ #endif
195
+
196
+ static const struct lm_ggml_type_traits_cpu type_traits_cpu[LM_GGML_TYPE_COUNT] = {
197
+ [LM_GGML_TYPE_F32] = {
198
+ .from_float = (lm_ggml_from_float_t) lm_ggml_cpu_fp32_to_fp32,
199
+ .vec_dot = (lm_ggml_vec_dot_t) lm_ggml_vec_dot_f32,
200
+ .vec_dot_type = LM_GGML_TYPE_F32,
201
+ .nrows = 1,
202
+ },
203
+ [LM_GGML_TYPE_F16] = {
204
+ .from_float = (lm_ggml_from_float_t) lm_ggml_cpu_fp32_to_fp16,
205
+ .vec_dot = (lm_ggml_vec_dot_t) lm_ggml_vec_dot_f16,
206
+ .vec_dot_type = LM_GGML_TYPE_F16,
207
+ .nrows = 1,
208
+ },
209
+ [LM_GGML_TYPE_Q4_0] = {
210
+ .from_float = quantize_row_q4_0,
211
+ .vec_dot = lm_ggml_vec_dot_q4_0_q8_0,
212
+ .vec_dot_type = LM_GGML_TYPE_Q8_0,
213
+ #if defined (__ARM_FEATURE_MATMUL_INT8)
214
+ .nrows = 2,
215
+ #else
216
+ .nrows = 1,
217
+ #endif
218
+ },
219
+ [LM_GGML_TYPE_Q4_1] = {
220
+ .from_float = quantize_row_q4_1,
221
+ .vec_dot = lm_ggml_vec_dot_q4_1_q8_1,
222
+ .vec_dot_type = LM_GGML_TYPE_Q8_1,
223
+ #if defined (__ARM_FEATURE_MATMUL_INT8)
224
+ .nrows = 2,
225
+ #else
226
+ .nrows = 1,
227
+ #endif
228
+ },
229
+ [LM_GGML_TYPE_Q5_0] = {
230
+ .from_float = quantize_row_q5_0,
231
+ .vec_dot = lm_ggml_vec_dot_q5_0_q8_0,
232
+ .vec_dot_type = LM_GGML_TYPE_Q8_0,
233
+ .nrows = 1,
234
+ },
235
+ [LM_GGML_TYPE_Q5_1] = {
236
+ .from_float = quantize_row_q5_1,
237
+ .vec_dot = lm_ggml_vec_dot_q5_1_q8_1,
238
+ .vec_dot_type = LM_GGML_TYPE_Q8_1,
239
+ .nrows = 1,
240
+ },
241
+ [LM_GGML_TYPE_Q8_0] = {
242
+ .from_float = quantize_row_q8_0,
243
+ .vec_dot = lm_ggml_vec_dot_q8_0_q8_0,
244
+ .vec_dot_type = LM_GGML_TYPE_Q8_0,
245
+ #if defined (__ARM_FEATURE_MATMUL_INT8)
246
+ .nrows = 2,
247
+ #else
248
+ .nrows = 1,
249
+ #endif
250
+ },
251
+ [LM_GGML_TYPE_Q8_1] = {
252
+ .from_float = quantize_row_q8_1,
253
+ .vec_dot_type = LM_GGML_TYPE_Q8_1,
254
+ .nrows = 1,
255
+ },
256
+ [LM_GGML_TYPE_MXFP4] = {
257
+ .from_float = quantize_row_mxfp4,
258
+ .vec_dot = lm_ggml_vec_dot_mxfp4_q8_0,
259
+ .vec_dot_type = LM_GGML_TYPE_Q8_0,
260
+ .nrows = 1,
261
+ },
262
+ [LM_GGML_TYPE_Q2_K] = {
263
+ .from_float = quantize_row_q2_K,
264
+ .vec_dot = lm_ggml_vec_dot_q2_K_q8_K,
265
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
266
+ .nrows = 1,
267
+ },
268
+ [LM_GGML_TYPE_Q3_K] = {
269
+ .from_float = quantize_row_q3_K,
270
+ .vec_dot = lm_ggml_vec_dot_q3_K_q8_K,
271
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
272
+ .nrows = 1,
273
+ },
274
+ [LM_GGML_TYPE_Q4_K] = {
275
+ .from_float = quantize_row_q4_K,
276
+ .vec_dot = lm_ggml_vec_dot_q4_K_q8_K,
277
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
278
+ #if defined (__ARM_FEATURE_MATMUL_INT8)
279
+ .nrows = 2,
280
+ #else
281
+ .nrows = 1,
282
+ #endif
283
+ },
284
+ [LM_GGML_TYPE_Q5_K] = {
285
+ .from_float = quantize_row_q5_K,
286
+ .vec_dot = lm_ggml_vec_dot_q5_K_q8_K,
287
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
288
+ .nrows = 1,
289
+ },
290
+ [LM_GGML_TYPE_Q6_K] = {
291
+ .from_float = quantize_row_q6_K,
292
+ .vec_dot = lm_ggml_vec_dot_q6_K_q8_K,
293
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
294
+ #if defined (__ARM_FEATURE_MATMUL_INT8)
295
+ .nrows = 2,
296
+ #else
297
+ .nrows = 1,
298
+ #endif
299
+ },
300
+ [LM_GGML_TYPE_IQ2_XXS] = {
301
+ .from_float = NULL,
302
+ .vec_dot = lm_ggml_vec_dot_iq2_xxs_q8_K,
303
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
304
+ .nrows = 1,
305
+ },
306
+ [LM_GGML_TYPE_IQ2_XS] = {
307
+ .from_float = NULL,
308
+ .vec_dot = lm_ggml_vec_dot_iq2_xs_q8_K,
309
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
310
+ .nrows = 1,
311
+ },
312
+ [LM_GGML_TYPE_IQ3_XXS] = {
313
+ // NOTE: from_float for iq3 and iq2_s was removed because these quants require initialization in lm_ggml_quantize_init
314
+ //.from_float = quantize_row_iq3_xxs,
315
+ .vec_dot = lm_ggml_vec_dot_iq3_xxs_q8_K,
316
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
317
+ .nrows = 1,
318
+ },
319
+ [LM_GGML_TYPE_IQ3_S] = {
320
+ //.from_float = quantize_row_iq3_s,
321
+ .vec_dot = lm_ggml_vec_dot_iq3_s_q8_K,
322
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
323
+ .nrows = 1,
324
+ },
325
+ [LM_GGML_TYPE_IQ2_S] = {
326
+ //.from_float = quantize_row_iq2_s,
327
+ .vec_dot = lm_ggml_vec_dot_iq2_s_q8_K,
328
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
329
+ .nrows = 1,
330
+ },
331
+ [LM_GGML_TYPE_IQ1_S] = {
332
+ .from_float = NULL,
333
+ .vec_dot = lm_ggml_vec_dot_iq1_s_q8_K,
334
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
335
+ .nrows = 1,
336
+ },
337
+ [LM_GGML_TYPE_IQ1_M] = {
338
+ .from_float = NULL,
339
+ .vec_dot = lm_ggml_vec_dot_iq1_m_q8_K,
340
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
341
+ .nrows = 1,
342
+ },
343
+ [LM_GGML_TYPE_IQ4_NL] = {
344
+ .from_float = quantize_row_iq4_nl,
345
+ .vec_dot = lm_ggml_vec_dot_iq4_nl_q8_0,
346
+ .vec_dot_type = LM_GGML_TYPE_Q8_0,
347
+ .nrows = 1,
348
+ },
349
+ [LM_GGML_TYPE_IQ4_XS] = {
350
+ .from_float = quantize_row_iq4_xs,
351
+ .vec_dot = lm_ggml_vec_dot_iq4_xs_q8_K,
352
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
353
+ .nrows = 1,
354
+ },
355
+ [LM_GGML_TYPE_Q8_K] = {
356
+ .from_float = quantize_row_q8_K,
357
+ },
358
+ [LM_GGML_TYPE_BF16] = {
359
+ .from_float = (lm_ggml_from_float_t) lm_ggml_cpu_fp32_to_bf16,
360
+ .vec_dot = (lm_ggml_vec_dot_t) lm_ggml_vec_dot_bf16,
361
+ .vec_dot_type = LM_GGML_TYPE_BF16,
362
+ .nrows = 1,
363
+ },
364
+ [LM_GGML_TYPE_TQ1_0] = {
365
+ .from_float = quantize_row_tq1_0,
366
+ .vec_dot = lm_ggml_vec_dot_tq1_0_q8_K,
367
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
368
+ .nrows = 1,
369
+ },
370
+ [LM_GGML_TYPE_TQ2_0] = {
371
+ .from_float = quantize_row_tq2_0,
372
+ .vec_dot = lm_ggml_vec_dot_tq2_0_q8_K,
373
+ .vec_dot_type = LM_GGML_TYPE_Q8_K,
374
+ .nrows = 1,
375
+ },
376
+ };
377
+
378
+ const struct lm_ggml_type_traits_cpu * lm_ggml_get_type_traits_cpu(enum lm_ggml_type type) {
379
+ return &type_traits_cpu[type];
380
+ }
381
+
382
+ //
383
+ // Threading defs
384
+ //
385
+
386
+ typedef pthread_t lm_ggml_thread_t;
387
+
388
+ #if defined(_WIN32)
389
+
390
+ typedef CONDITION_VARIABLE lm_ggml_cond_t;
391
+ typedef SRWLOCK lm_ggml_mutex_t;
392
+
393
+ #define lm_ggml_mutex_init(m) InitializeSRWLock(m)
394
+ #define lm_ggml_mutex_destroy(m)
395
+ #define lm_ggml_mutex_lock(m) AcquireSRWLockExclusive(m)
396
+ #define lm_ggml_mutex_unlock(m) ReleaseSRWLockExclusive(m)
397
+ #define lm_ggml_mutex_lock_shared(m) AcquireSRWLockShared(m)
398
+ #define lm_ggml_mutex_unlock_shared(m) ReleaseSRWLockShared(m)
399
+
400
+ #define lm_ggml_cond_init(c) InitializeConditionVariable(c)
401
+ #define lm_ggml_cond_destroy(c)
402
+ #define lm_ggml_cond_wait(c, m) SleepConditionVariableSRW(c, m, INFINITE, CONDITION_VARIABLE_LOCKMODE_SHARED)
403
+ #define lm_ggml_cond_broadcast(c) WakeAllConditionVariable(c)
404
+
405
+ #define lm_ggml_thread_create pthread_create
406
+ #define lm_ggml_thread_join pthread_join
407
+
408
+ #else
409
+
410
+ typedef pthread_cond_t lm_ggml_cond_t;
411
+ typedef pthread_mutex_t lm_ggml_mutex_t;
412
+
413
+ #define lm_ggml_mutex_init(m) pthread_mutex_init(m, NULL)
414
+ #define lm_ggml_mutex_destroy(m) pthread_mutex_destroy(m)
415
+ #define lm_ggml_mutex_lock(m) pthread_mutex_lock(m)
416
+ #define lm_ggml_mutex_unlock(m) pthread_mutex_unlock(m)
417
+ #define lm_ggml_mutex_lock_shared(m) pthread_mutex_lock(m)
418
+ #define lm_ggml_mutex_unlock_shared(m) pthread_mutex_unlock(m)
419
+
420
+ #define lm_ggml_lock_init(x) UNUSED(x)
421
+ #define lm_ggml_lock_destroy(x) UNUSED(x)
422
+ #if defined(__x86_64__) || (defined(_MSC_VER) && defined(_M_AMD64))
423
+ #define lm_ggml_lock_lock(x) _mm_pause()
424
+ #else
425
+ #define lm_ggml_lock_lock(x) UNUSED(x)
426
+ #endif
427
+ #define lm_ggml_lock_unlock(x) UNUSED(x)
428
+
429
+ #define LM_GGML_LOCK_INITIALIZER 0
430
+ #define lm_ggml_cond_init(c) pthread_cond_init(c, NULL)
431
+ #define lm_ggml_cond_destroy(c) pthread_cond_destroy(c)
432
+ #define lm_ggml_cond_wait(c, m) pthread_cond_wait(c, m)
433
+ #define lm_ggml_cond_broadcast(c) pthread_cond_broadcast(c)
434
+
435
+ #define lm_ggml_thread_create pthread_create
436
+ #define lm_ggml_thread_join pthread_join
437
+
438
+ #endif
439
+
440
+ // Threadpool def
441
+ struct lm_ggml_threadpool {
442
+ lm_ggml_mutex_t mutex; // mutex for cond.var
443
+ lm_ggml_cond_t cond; // cond.var for waiting for new work
444
+
445
+ struct lm_ggml_cgraph * cgraph;
446
+ struct lm_ggml_cplan * cplan;
447
+
448
+ // synchronization primitives
449
+ atomic_int n_graph; // incremented when there is work to be done (i.e each graph)
450
+ atomic_int LM_GGML_CACHE_ALIGN n_barrier;
451
+ atomic_int LM_GGML_CACHE_ALIGN n_barrier_passed;
452
+ atomic_int LM_GGML_CACHE_ALIGN current_chunk; // currently processing chunk during Mat_Mul, shared between all the threads.
453
+
454
+ // these are atomic as an annotation for thread-sanitizer
455
+ atomic_bool stop; // Used for stopping the threadpool altogether
456
+ atomic_bool pause; // Used for pausing the threadpool or individual threads
457
+ atomic_int abort; // Used for aborting processing of a graph
458
+
459
+ struct lm_ggml_compute_state * workers; // per thread state
460
+ int n_threads_max; // number of threads in the pool
461
+ atomic_int n_threads_cur; // number of threads used in the current graph
462
+
463
+ int32_t prio; // Scheduling priority
464
+ uint32_t poll; // Polling level (0 - no polling)
465
+
466
+ enum lm_ggml_status ec;
467
+ };
468
+
469
+ // Per-thread state
470
+ struct lm_ggml_compute_state {
471
+ #ifndef LM_GGML_USE_OPENMP
472
+ lm_ggml_thread_t thrd;
473
+ bool cpumask[LM_GGML_MAX_N_THREADS];
474
+ int last_graph;
475
+ bool pending;
476
+ #endif
477
+ struct lm_ggml_threadpool * threadpool;
478
+ int ith;
479
+ };
480
+
481
+ // Helpers for polling loops
482
+ #if defined(__aarch64__) && ( defined(__clang__) || defined(__GNUC__) )
483
+ static inline void lm_ggml_thread_cpu_relax(void) {
484
+ __asm__ volatile("yield" ::: "memory");
485
+ }
486
+ #elif defined(__x86_64__)
487
+ static inline void lm_ggml_thread_cpu_relax(void) {
488
+ _mm_pause();
489
+ }
490
+ #else
491
+ static inline void lm_ggml_thread_cpu_relax(void) {;}
492
+ #endif
493
+
494
+ //
495
+ // NUMA support
496
+ //
497
+
498
+ #define LM_GGML_NUMA_MAX_NODES 8
499
+ #define LM_GGML_NUMA_MAX_CPUS 512
500
+
501
+ struct lm_ggml_numa_node {
502
+ uint32_t cpus[LM_GGML_NUMA_MAX_CPUS]; // hardware threads on this node
503
+ uint32_t n_cpus;
504
+ };
505
+
506
+ struct lm_ggml_numa_nodes {
507
+ enum lm_ggml_numa_strategy numa_strategy;
508
+ struct lm_ggml_numa_node nodes[LM_GGML_NUMA_MAX_NODES];
509
+ uint32_t n_nodes;
510
+ uint32_t total_cpus; // hardware threads on system
511
+ uint32_t current_node; // node on which main process is execting
512
+ #if defined(__gnu_linux__)
513
+ cpu_set_t cpuset; // cpuset from numactl
514
+ #else
515
+ uint32_t cpuset; // no NUMA support outside of Linux at this time. Use a portable datatype
516
+ #endif
517
+ };
518
+
519
+ //
520
+ // ggml state
521
+ //
522
+
523
+ struct lm_ggml_state {
524
+ struct lm_ggml_numa_nodes numa;
525
+ };
526
+
527
+ static struct lm_ggml_state g_state = {0};
528
+
529
+ void lm_ggml_barrier(struct lm_ggml_threadpool * tp) {
530
+ int n_threads = atomic_load_explicit(&tp->n_threads_cur, memory_order_relaxed);
531
+ if (n_threads == 1) {
532
+ return;
533
+ }
534
+
535
+ #ifdef LM_GGML_USE_OPENMP
536
+ #pragma omp barrier
537
+ #else
538
+ int n_passed = atomic_load_explicit(&tp->n_barrier_passed, memory_order_relaxed);
539
+
540
+ // enter barrier (full seq-cst fence)
541
+ int n_barrier = atomic_fetch_add_explicit(&tp->n_barrier, 1, memory_order_seq_cst);
542
+
543
+ if (n_barrier == (n_threads - 1)) {
544
+ // last thread
545
+ atomic_store_explicit(&tp->n_barrier, 0, memory_order_relaxed);
546
+
547
+ // exit barrier (fill seq-cst fence)
548
+ atomic_fetch_add_explicit(&tp->n_barrier_passed, 1, memory_order_seq_cst);
549
+ return;
550
+ }
551
+
552
+ // wait for other threads
553
+ while (atomic_load_explicit(&tp->n_barrier_passed, memory_order_relaxed) == n_passed) {
554
+ lm_ggml_thread_cpu_relax();
555
+ }
556
+
557
+ // exit barrier (full seq-cst fence)
558
+ // TSAN doesn't support standalone fence yet, we use a dummy read-modify-write instead
559
+ #ifdef LM_GGML_TSAN_ENABLED
560
+ atomic_fetch_add_explicit(&tp->n_barrier_passed, 0, memory_order_seq_cst);
561
+ #else
562
+ atomic_thread_fence(memory_order_seq_cst);
563
+ #endif
564
+ #endif
565
+ }
566
+
567
+ void lm_ggml_threadpool_chunk_set(struct lm_ggml_threadpool * tp, int value) {
568
+ atomic_store_explicit(&tp->current_chunk, value, memory_order_relaxed);
569
+ }
570
+
571
+ int lm_ggml_threadpool_chunk_add(struct lm_ggml_threadpool * tp, int value) {
572
+ return atomic_fetch_add_explicit(&tp->current_chunk, value, memory_order_relaxed);
573
+ }
574
+
575
+ #if defined(__gnu_linux__)
576
+ static cpu_set_t lm_ggml_get_numa_affinity(void) {
577
+ cpu_set_t cpuset;
578
+ pthread_t thread;
579
+ thread = pthread_self();
580
+ CPU_ZERO(&cpuset);
581
+ pthread_getaffinity_np(thread, sizeof(cpu_set_t), &cpuset);
582
+ return cpuset;
583
+ }
584
+ #else
585
+ static uint32_t lm_ggml_get_numa_affinity(void) {
586
+ return 0; // no NUMA support
587
+ }
588
+ #endif
589
+
590
+ void lm_ggml_numa_init(enum lm_ggml_numa_strategy numa_flag) {
591
+ if (g_state.numa.n_nodes > 0) {
592
+ fprintf(stderr, "lm_ggml_numa_init: NUMA already initialized\n");
593
+
594
+ return;
595
+ }
596
+
597
+ #if defined(__gnu_linux__)
598
+ struct stat st;
599
+ char path[256];
600
+ int rv;
601
+
602
+ // set numa scheme
603
+ g_state.numa.numa_strategy = numa_flag;
604
+
605
+ LM_GGML_PRINT_DEBUG("numa strategy %u\n",g_state.numa.numa_strategy);
606
+
607
+ g_state.numa.cpuset = lm_ggml_get_numa_affinity();
608
+
609
+ // enumerate nodes
610
+ while (g_state.numa.n_nodes < LM_GGML_NUMA_MAX_NODES) {
611
+ rv = snprintf(path, sizeof(path), "/sys/devices/system/node/node%u", g_state.numa.n_nodes);
612
+ LM_GGML_ASSERT(rv > 0 && (unsigned)rv < sizeof(path));
613
+ if (stat(path, &st) != 0) { break; }
614
+ ++g_state.numa.n_nodes;
615
+ }
616
+
617
+ // enumerate CPUs
618
+ while (g_state.numa.total_cpus < LM_GGML_NUMA_MAX_CPUS) {
619
+ rv = snprintf(path, sizeof(path), "/sys/devices/system/cpu/cpu%u", g_state.numa.total_cpus);
620
+ LM_GGML_ASSERT(rv > 0 && (unsigned)rv < sizeof(path));
621
+ if (stat(path, &st) != 0) { break; }
622
+ ++g_state.numa.total_cpus;
623
+ }
624
+
625
+ LM_GGML_PRINT_DEBUG("found %u numa nodes, %u CPUs\n", g_state.numa.n_nodes, g_state.numa.total_cpus);
626
+
627
+ // figure out which node we're on
628
+ uint current_cpu;
629
+ int getcpu_ret = 0;
630
+ #if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ > 33) || defined(__COSMOPOLITAN__)
631
+ getcpu_ret = getcpu(&current_cpu, &g_state.numa.current_node);
632
+ #else
633
+ // old glibc doesn't have a wrapper for this call. Fall back on direct syscall
634
+ # if !defined(SYS_getcpu) && defined(SYS_get_cpu)
635
+ # define SYS_getcpu SYS_get_cpu // some older glibc versions use this name
636
+ # endif
637
+ getcpu_ret = syscall(SYS_getcpu, &current_cpu, &g_state.numa.current_node);
638
+ #endif
639
+
640
+ if (g_state.numa.n_nodes < 1 || g_state.numa.total_cpus < 1 || getcpu_ret != 0) {
641
+ g_state.numa.n_nodes = 0;
642
+ return;
643
+ }
644
+
645
+ LM_GGML_PRINT_DEBUG("found our process on numa node %u, CPU %u\n", g_state.numa.current_node, current_cpu);
646
+
647
+ for (uint32_t n = 0; n < g_state.numa.n_nodes; ++n) {
648
+ struct lm_ggml_numa_node * node = &g_state.numa.nodes[n];
649
+ LM_GGML_PRINT_DEBUG("CPUs on node %u:", n);
650
+ node->n_cpus = 0;
651
+ for (uint32_t c = 0; c < g_state.numa.total_cpus; ++c) {
652
+ rv = snprintf(path, sizeof(path), "/sys/devices/system/node/node%u/cpu%u", n, c);
653
+ LM_GGML_ASSERT(rv > 0 && (unsigned)rv < sizeof(path));
654
+ if (stat(path, &st) == 0) {
655
+ node->cpus[node->n_cpus++] = c;
656
+ LM_GGML_PRINT_DEBUG(" %u", c);
657
+ }
658
+ }
659
+ LM_GGML_PRINT_DEBUG("\n");
660
+ }
661
+
662
+ if (lm_ggml_is_numa()) {
663
+ FILE *fptr = fopen("/proc/sys/kernel/numa_balancing", "r");
664
+ if (fptr != NULL) {
665
+ char buf[42];
666
+ if (fgets(buf, sizeof(buf), fptr) && strncmp(buf, "0\n", sizeof(buf)) != 0) {
667
+ LM_GGML_LOG_WARN("/proc/sys/kernel/numa_balancing is enabled, this has been observed to impair performance\n");
668
+ }
669
+ fclose(fptr);
670
+ }
671
+ }
672
+ #else
673
+ UNUSED(numa_flag);
674
+ // TODO
675
+ #endif
676
+ }
677
+
678
+ bool lm_ggml_is_numa(void) {
679
+ return g_state.numa.n_nodes > 1;
680
+ }
681
+
682
+ #if defined(__ARM_ARCH)
683
+
684
+ #if defined(__linux__) && defined(__aarch64__)
685
+ #include <sys/auxv.h>
686
+ #endif
687
+
688
+ static void lm_ggml_init_arm_arch_features(void) {
689
+ #if defined(__linux__) && defined(__aarch64__) && defined(__ARM_FEATURE_SVE)
690
+ lm_ggml_arm_arch_features.sve_cnt = PR_SVE_VL_LEN_MASK & prctl(PR_SVE_GET_VL);
691
+ #endif
692
+ }
693
+
694
+ #endif // __ARM_ARCH
695
+
696
+ struct lm_ggml_tensor * lm_ggml_new_i32(struct lm_ggml_context * ctx, int32_t value) {
697
+ LM_GGML_ASSERT(!lm_ggml_get_no_alloc(ctx));
698
+
699
+ struct lm_ggml_tensor * result = lm_ggml_new_tensor_1d(ctx, LM_GGML_TYPE_I32, 1);
700
+
701
+ lm_ggml_set_i32(result, value);
702
+
703
+ return result;
704
+ }
705
+
706
+ struct lm_ggml_tensor * lm_ggml_new_f32(struct lm_ggml_context * ctx, float value) {
707
+ LM_GGML_ASSERT(!lm_ggml_get_no_alloc(ctx));
708
+
709
+ struct lm_ggml_tensor * result = lm_ggml_new_tensor_1d(ctx, LM_GGML_TYPE_F32, 1);
710
+
711
+ lm_ggml_set_f32(result, value);
712
+
713
+ return result;
714
+ }
715
+
716
+ struct lm_ggml_tensor * lm_ggml_set_i32 (struct lm_ggml_tensor * tensor, int32_t value) {
717
+ const int n = lm_ggml_nrows(tensor);
718
+ const int nc = tensor->ne[0];
719
+ const size_t n1 = tensor->nb[1];
720
+
721
+ char * const data = tensor->data;
722
+
723
+ switch (tensor->type) {
724
+ case LM_GGML_TYPE_I8:
725
+ {
726
+ assert(tensor->nb[0] == sizeof(int8_t));
727
+ for (int i = 0; i < n; i++) {
728
+ lm_ggml_vec_set_i8(nc, (int8_t *)(data + i*n1), value);
729
+ }
730
+ } break;
731
+ case LM_GGML_TYPE_I16:
732
+ {
733
+ assert(tensor->nb[0] == sizeof(int16_t));
734
+ for (int i = 0; i < n; i++) {
735
+ lm_ggml_vec_set_i16(nc, (int16_t *)(data + i*n1), value);
736
+ }
737
+ } break;
738
+ case LM_GGML_TYPE_I32:
739
+ {
740
+ assert(tensor->nb[0] == sizeof(int32_t));
741
+ for (int i = 0; i < n; i++) {
742
+ lm_ggml_vec_set_i32(nc, (int32_t *)(data + i*n1), value);
743
+ }
744
+ } break;
745
+ case LM_GGML_TYPE_F16:
746
+ {
747
+ assert(tensor->nb[0] == sizeof(lm_ggml_fp16_t));
748
+ for (int i = 0; i < n; i++) {
749
+ lm_ggml_vec_set_f16(nc, (lm_ggml_fp16_t *)(data + i*n1), LM_GGML_CPU_FP32_TO_FP16(value));
750
+ }
751
+ } break;
752
+ case LM_GGML_TYPE_BF16:
753
+ {
754
+ assert(tensor->nb[0] == sizeof(lm_ggml_fp16_t));
755
+ for (int i = 0; i < n; i++) {
756
+ lm_ggml_vec_set_bf16(nc, (lm_ggml_bf16_t *)(data + i*n1), LM_GGML_FP32_TO_BF16(value));
757
+ }
758
+ } break;
759
+ case LM_GGML_TYPE_F32:
760
+ {
761
+ assert(tensor->nb[0] == sizeof(float));
762
+ for (int i = 0; i < n; i++) {
763
+ lm_ggml_vec_set_f32(nc, (float *)(data + i*n1), value);
764
+ }
765
+ } break;
766
+ default:
767
+ {
768
+ LM_GGML_ABORT("fatal error");
769
+ }
770
+ }
771
+
772
+ return tensor;
773
+ }
774
+
775
+ struct lm_ggml_tensor * lm_ggml_set_f32(struct lm_ggml_tensor * tensor, float value) {
776
+ const int n = lm_ggml_nrows(tensor);
777
+ const int nc = tensor->ne[0];
778
+ const size_t n1 = tensor->nb[1];
779
+
780
+ char * const data = tensor->data;
781
+
782
+ switch (tensor->type) {
783
+ case LM_GGML_TYPE_I8:
784
+ {
785
+ assert(tensor->nb[0] == sizeof(int8_t));
786
+ for (int i = 0; i < n; i++) {
787
+ lm_ggml_vec_set_i8(nc, (int8_t *)(data + i*n1), value);
788
+ }
789
+ } break;
790
+ case LM_GGML_TYPE_I16:
791
+ {
792
+ assert(tensor->nb[0] == sizeof(int16_t));
793
+ for (int i = 0; i < n; i++) {
794
+ lm_ggml_vec_set_i16(nc, (int16_t *)(data + i*n1), value);
795
+ }
796
+ } break;
797
+ case LM_GGML_TYPE_I32:
798
+ {
799
+ assert(tensor->nb[0] == sizeof(int32_t));
800
+ for (int i = 0; i < n; i++) {
801
+ lm_ggml_vec_set_i32(nc, (int32_t *)(data + i*n1), value);
802
+ }
803
+ } break;
804
+ case LM_GGML_TYPE_F16:
805
+ {
806
+ assert(tensor->nb[0] == sizeof(lm_ggml_fp16_t));
807
+ for (int i = 0; i < n; i++) {
808
+ lm_ggml_vec_set_f16(nc, (lm_ggml_fp16_t *)(data + i*n1), LM_GGML_CPU_FP32_TO_FP16(value));
809
+ }
810
+ } break;
811
+ case LM_GGML_TYPE_BF16:
812
+ {
813
+ assert(tensor->nb[0] == sizeof(lm_ggml_bf16_t));
814
+ for (int i = 0; i < n; i++) {
815
+ lm_ggml_vec_set_bf16(nc, (lm_ggml_bf16_t *)(data + i*n1), LM_GGML_FP32_TO_BF16(value));
816
+ }
817
+ } break;
818
+ case LM_GGML_TYPE_F32:
819
+ {
820
+ assert(tensor->nb[0] == sizeof(float));
821
+ for (int i = 0; i < n; i++) {
822
+ lm_ggml_vec_set_f32(nc, (float *)(data + i*n1), value);
823
+ }
824
+ } break;
825
+ default:
826
+ {
827
+ LM_GGML_ABORT("fatal error");
828
+ }
829
+ }
830
+
831
+ return tensor;
832
+ }
833
+
834
+ int32_t lm_ggml_get_i32_1d(const struct lm_ggml_tensor * tensor, int i) {
835
+ if (!lm_ggml_is_contiguous(tensor)) {
836
+ int64_t id[4] = { 0, 0, 0, 0 };
837
+ lm_ggml_unravel_index(tensor, i, &id[0], &id[1], &id[2], &id[3]);
838
+ return lm_ggml_get_i32_nd(tensor, id[0], id[1], id[2], id[3]);
839
+ }
840
+ switch (tensor->type) {
841
+ case LM_GGML_TYPE_I8:
842
+ {
843
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(int8_t));
844
+ return ((int8_t *)(tensor->data))[i];
845
+ }
846
+ case LM_GGML_TYPE_I16:
847
+ {
848
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(int16_t));
849
+ return ((int16_t *)(tensor->data))[i];
850
+ }
851
+ case LM_GGML_TYPE_I32:
852
+ {
853
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(int32_t));
854
+ return ((int32_t *)(tensor->data))[i];
855
+ }
856
+ case LM_GGML_TYPE_F16:
857
+ {
858
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(lm_ggml_fp16_t));
859
+ return LM_GGML_CPU_FP16_TO_FP32(((lm_ggml_fp16_t *)(tensor->data))[i]);
860
+ }
861
+ case LM_GGML_TYPE_BF16:
862
+ {
863
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(lm_ggml_bf16_t));
864
+ return LM_GGML_BF16_TO_FP32(((lm_ggml_bf16_t *)(tensor->data))[i]);
865
+ }
866
+ case LM_GGML_TYPE_F32:
867
+ {
868
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(float));
869
+ return ((float *)(tensor->data))[i];
870
+ }
871
+ default:
872
+ {
873
+ LM_GGML_ABORT("fatal error");
874
+ }
875
+ }
876
+ }
877
+
878
+ void lm_ggml_set_i32_1d(const struct lm_ggml_tensor * tensor, int i, int32_t value) {
879
+ if (!lm_ggml_is_contiguous(tensor)) {
880
+ int64_t id[4] = { 0, 0, 0, 0 };
881
+ lm_ggml_unravel_index(tensor, i, &id[0], &id[1], &id[2], &id[3]);
882
+ lm_ggml_set_i32_nd(tensor, id[0], id[1], id[2], id[3], value);
883
+ return;
884
+ }
885
+ switch (tensor->type) {
886
+ case LM_GGML_TYPE_I8:
887
+ {
888
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(int8_t));
889
+ ((int8_t *)(tensor->data))[i] = value;
890
+ } break;
891
+ case LM_GGML_TYPE_I16:
892
+ {
893
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(int16_t));
894
+ ((int16_t *)(tensor->data))[i] = value;
895
+ } break;
896
+ case LM_GGML_TYPE_I32:
897
+ {
898
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(int32_t));
899
+ ((int32_t *)(tensor->data))[i] = value;
900
+ } break;
901
+ case LM_GGML_TYPE_F16:
902
+ {
903
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(lm_ggml_fp16_t));
904
+ ((lm_ggml_fp16_t *)(tensor->data))[i] = LM_GGML_CPU_FP32_TO_FP16(value);
905
+ } break;
906
+ case LM_GGML_TYPE_BF16:
907
+ {
908
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(lm_ggml_bf16_t));
909
+ ((lm_ggml_bf16_t *)(tensor->data))[i] = LM_GGML_FP32_TO_BF16(value);
910
+ } break;
911
+ case LM_GGML_TYPE_F32:
912
+ {
913
+ LM_GGML_ASSERT(tensor->nb[0] == sizeof(float));
914
+ ((float *)(tensor->data))[i] = value;
915
+ } break;
916
+ default:
917
+ {
918
+ LM_GGML_ABORT("fatal error");
919
+ }
920
+ }
921
+ }
922
+
923
+ int32_t lm_ggml_get_i32_nd(const struct lm_ggml_tensor * tensor, int i0, int i1, int i2, int i3) {
924
+ void * data = (char *) tensor->data + i0*tensor->nb[0] + i1*tensor->nb[1] + i2*tensor->nb[2] + i3*tensor->nb[3];
925
+ switch (tensor->type) {
926
+ case LM_GGML_TYPE_I8:
927
+ return ((int8_t *) data)[0];
928
+ case LM_GGML_TYPE_I16:
929
+ return ((int16_t *) data)[0];
930
+ case LM_GGML_TYPE_I32:
931
+ return ((int32_t *) data)[0];
932
+ case LM_GGML_TYPE_F16:
933
+ return LM_GGML_CPU_FP16_TO_FP32(((lm_ggml_fp16_t *) data)[0]);
934
+ case LM_GGML_TYPE_BF16:
935
+ return LM_GGML_BF16_TO_FP32(((lm_ggml_bf16_t *) data)[0]);
936
+ case LM_GGML_TYPE_F32:
937
+ return ((float *) data)[0];
938
+ default:
939
+ LM_GGML_ABORT("fatal error");
940
+ }
941
+ }
942
+
943
+ void lm_ggml_set_i32_nd(const struct lm_ggml_tensor * tensor, int i0, int i1, int i2, int i3, int32_t value) {
944
+ void * data = (char *) tensor->data + i0*tensor->nb[0] + i1*tensor->nb[1] + i2*tensor->nb[2] + i3*tensor->nb[3];
945
+ switch (tensor->type) {
946
+ case LM_GGML_TYPE_I8:
947
+ {
948
+ ((int8_t *)(data))[0] = value;
949
+ } break;
950
+ case LM_GGML_TYPE_I16:
951
+ {
952
+ ((int16_t *)(data))[0] = value;
953
+ } break;
954
+ case LM_GGML_TYPE_I32:
955
+ {
956
+ ((int32_t *)(data))[0] = value;
957
+ } break;
958
+ case LM_GGML_TYPE_F16:
959
+ {
960
+ ((lm_ggml_fp16_t *)(data))[0] = LM_GGML_CPU_FP32_TO_FP16(value);
961
+ } break;
962
+ case LM_GGML_TYPE_BF16:
963
+ {
964
+ ((lm_ggml_bf16_t *)(data))[0] = LM_GGML_FP32_TO_BF16(value);
965
+ } break;
966
+ case LM_GGML_TYPE_F32:
967
+ {
968
+ ((float *)(data))[0] = value;
969
+ } break;
970
+ default:
971
+ {
972
+ LM_GGML_ABORT("fatal error");
973
+ }
974
+ }
975
+ }
976
+
977
+ float lm_ggml_get_f32_1d(const struct lm_ggml_tensor * tensor, int i) {
978
+ if (!lm_ggml_is_contiguous(tensor)) {
979
+ int64_t id[4] = { 0, 0, 0, 0 };
980
+ lm_ggml_unravel_index(tensor, i, &id[0], &id[1], &id[2], &id[3]);
981
+ return lm_ggml_get_f32_nd(tensor, id[0], id[1], id[2], id[3]);
982
+ }
983
+ switch (tensor->type) {
984
+ case LM_GGML_TYPE_I8:
985
+ {
986
+ return ((int8_t *)(tensor->data))[i];
987
+ }
988
+ case LM_GGML_TYPE_I16:
989
+ {
990
+ return ((int16_t *)(tensor->data))[i];
991
+ }
992
+ case LM_GGML_TYPE_I32:
993
+ {
994
+ return ((int32_t *)(tensor->data))[i];
995
+ }
996
+ case LM_GGML_TYPE_F16:
997
+ {
998
+ return LM_GGML_CPU_FP16_TO_FP32(((lm_ggml_fp16_t *)(tensor->data))[i]);
999
+ }
1000
+ case LM_GGML_TYPE_BF16:
1001
+ {
1002
+ return LM_GGML_BF16_TO_FP32(((lm_ggml_bf16_t *)(tensor->data))[i]);
1003
+ }
1004
+ case LM_GGML_TYPE_F32:
1005
+ {
1006
+ return ((float *)(tensor->data))[i];
1007
+ }
1008
+ default:
1009
+ {
1010
+ LM_GGML_ABORT("fatal error");
1011
+ }
1012
+ }
1013
+ }
1014
+
1015
+ void lm_ggml_set_f32_1d(const struct lm_ggml_tensor * tensor, int i, float value) {
1016
+ if (!lm_ggml_is_contiguous(tensor)) {
1017
+ int64_t id[4] = { 0, 0, 0, 0 };
1018
+ lm_ggml_unravel_index(tensor, i, &id[0], &id[1], &id[2], &id[3]);
1019
+ lm_ggml_set_f32_nd(tensor, id[0], id[1], id[2], id[3], value);
1020
+ return;
1021
+ }
1022
+ switch (tensor->type) {
1023
+ case LM_GGML_TYPE_I8:
1024
+ {
1025
+ ((int8_t *)(tensor->data))[i] = value;
1026
+ } break;
1027
+ case LM_GGML_TYPE_I16:
1028
+ {
1029
+ ((int16_t *)(tensor->data))[i] = value;
1030
+ } break;
1031
+ case LM_GGML_TYPE_I32:
1032
+ {
1033
+ ((int32_t *)(tensor->data))[i] = value;
1034
+ } break;
1035
+ case LM_GGML_TYPE_F16:
1036
+ {
1037
+ ((lm_ggml_fp16_t *)(tensor->data))[i] = LM_GGML_CPU_FP32_TO_FP16(value);
1038
+ } break;
1039
+ case LM_GGML_TYPE_BF16:
1040
+ {
1041
+ ((lm_ggml_bf16_t *)(tensor->data))[i] = LM_GGML_FP32_TO_BF16(value);
1042
+ } break;
1043
+ case LM_GGML_TYPE_F32:
1044
+ {
1045
+ ((float *)(tensor->data))[i] = value;
1046
+ } break;
1047
+ default:
1048
+ {
1049
+ LM_GGML_ABORT("fatal error");
1050
+ }
1051
+ }
1052
+ }
1053
+
1054
+ float lm_ggml_get_f32_nd(const struct lm_ggml_tensor * tensor, int i0, int i1, int i2, int i3) {
1055
+ void * data = (char *) tensor->data + i0*tensor->nb[0] + i1*tensor->nb[1] + i2*tensor->nb[2] + i3*tensor->nb[3];
1056
+ switch (tensor->type) {
1057
+ case LM_GGML_TYPE_I8:
1058
+ return ((int8_t *) data)[0];
1059
+ case LM_GGML_TYPE_I16:
1060
+ return ((int16_t *) data)[0];
1061
+ case LM_GGML_TYPE_I32:
1062
+ return ((int32_t *) data)[0];
1063
+ case LM_GGML_TYPE_F16:
1064
+ return LM_GGML_CPU_FP16_TO_FP32(((lm_ggml_fp16_t *) data)[0]);
1065
+ case LM_GGML_TYPE_BF16:
1066
+ return LM_GGML_BF16_TO_FP32(((lm_ggml_bf16_t *) data)[0]);
1067
+ case LM_GGML_TYPE_F32:
1068
+ return ((float *) data)[0];
1069
+ default:
1070
+ LM_GGML_ABORT("fatal error");
1071
+ }
1072
+ }
1073
+
1074
+ void lm_ggml_set_f32_nd(const struct lm_ggml_tensor * tensor, int i0, int i1, int i2, int i3, float value) {
1075
+ void * data = (char *) tensor->data + i0*tensor->nb[0] + i1*tensor->nb[1] + i2*tensor->nb[2] + i3*tensor->nb[3];
1076
+ switch (tensor->type) {
1077
+ case LM_GGML_TYPE_I8:
1078
+ {
1079
+ ((int8_t *)(data))[0] = value;
1080
+ } break;
1081
+ case LM_GGML_TYPE_I16:
1082
+ {
1083
+ ((int16_t *)(data))[0] = value;
1084
+ } break;
1085
+ case LM_GGML_TYPE_I32:
1086
+ {
1087
+ ((int32_t *)(data))[0] = value;
1088
+ } break;
1089
+ case LM_GGML_TYPE_F16:
1090
+ {
1091
+ ((lm_ggml_fp16_t *)(data))[0] = LM_GGML_CPU_FP32_TO_FP16(value);
1092
+ } break;
1093
+ case LM_GGML_TYPE_BF16:
1094
+ {
1095
+ ((lm_ggml_bf16_t *)(data))[0] = LM_GGML_FP32_TO_BF16(value);
1096
+ } break;
1097
+ case LM_GGML_TYPE_F32:
1098
+ {
1099
+ ((float *)(data))[0] = value;
1100
+ } break;
1101
+ default:
1102
+ {
1103
+ LM_GGML_ABORT("fatal error");
1104
+ }
1105
+ }
1106
+ }
1107
+
1108
+ ////////////////////////////////////////////////////////////////////////////////
1109
+
1110
+ // lm_ggml_compute_forward_mul_mat
1111
+
1112
+ static void lm_ggml_compute_forward_mul_mat_one_chunk(
1113
+ const struct lm_ggml_compute_params * params,
1114
+ struct lm_ggml_tensor * dst,
1115
+ const enum lm_ggml_type type,
1116
+ const int64_t num_rows_per_vec_dot,
1117
+ const int64_t ir0_start,
1118
+ const int64_t ir0_end,
1119
+ const int64_t ir1_start,
1120
+ const int64_t ir1_end) {
1121
+
1122
+ const struct lm_ggml_tensor * src0 = dst->src[0];
1123
+ const struct lm_ggml_tensor * src1 = dst->src[1];
1124
+
1125
+ LM_GGML_TENSOR_BINARY_OP_LOCALS
1126
+
1127
+ const bool src1_cont = lm_ggml_is_contiguous(src1);
1128
+
1129
+ lm_ggml_vec_dot_t const vec_dot = type_traits_cpu[type].vec_dot;
1130
+ enum lm_ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
1131
+
1132
+ // broadcast factors
1133
+ const int64_t r2 = ne12 / ne02;
1134
+ const int64_t r3 = ne13 / ne03;
1135
+
1136
+ //printf("ir0_start = %6lld, ir0_end = %6lld, ir1_start = %6lld, ir1_end = %6lld\n", ir0_start, ir0_end, ir1_start, ir1_end);
1137
+
1138
+ // threads with no work simply yield (not sure if it helps)
1139
+ if (ir0_start >= ir0_end || ir1_start >= ir1_end) {
1140
+ return;
1141
+ }
1142
+
1143
+ const void * wdata = (src1->type == vec_dot_type) ? src1->data : params->wdata;
1144
+ const size_t row_size = lm_ggml_row_size(vec_dot_type, ne10);
1145
+
1146
+ assert(ne12 % ne02 == 0);
1147
+ assert(ne13 % ne03 == 0);
1148
+
1149
+ // block-tiling attempt
1150
+ const int64_t blck_0 = 16;
1151
+ const int64_t blck_1 = 16;
1152
+
1153
+ const size_t src1_col_stride = src1_cont || src1->type != vec_dot_type ? row_size : nb11;
1154
+
1155
+ // attempt to reduce false-sharing (does not seem to make a difference)
1156
+ // 16 * 2, accounting for mmla kernels
1157
+ float tmp[32];
1158
+
1159
+ for (int64_t iir1 = ir1_start; iir1 < ir1_end; iir1 += blck_1) {
1160
+ for (int64_t iir0 = ir0_start; iir0 < ir0_end; iir0 += blck_0) {
1161
+ for (int64_t ir1 = iir1; ir1 < iir1 + blck_1 && ir1 < ir1_end; ir1 += num_rows_per_vec_dot) {
1162
+ const int64_t i13 = (ir1 / (ne12 * ne1));
1163
+ const int64_t i12 = (ir1 - i13 * ne12 * ne1) / ne1;
1164
+ const int64_t i11 = (ir1 - i13 * ne12 * ne1 - i12 * ne1);
1165
+
1166
+ // broadcast src0 into src1
1167
+ const int64_t i03 = i13 / r3;
1168
+ const int64_t i02 = i12 / r2;
1169
+
1170
+ const int64_t i1 = i11;
1171
+ const int64_t i2 = i12;
1172
+ const int64_t i3 = i13;
1173
+
1174
+ const char * src0_row = (const char*)src0->data + (0 + i02 * nb02 + i03 * nb03);
1175
+
1176
+ // desc: when src1 is not a contiguous memory block we have to calculate the offset using the strides
1177
+ // if it is, then we have either copied the data to params->wdata and made it contiguous or we are using
1178
+ // the original src1 data pointer, so we should index using the indices directly
1179
+ // TODO: this is a bit of a hack, we should probably have a better way to handle this
1180
+ const char * src1_col = (const char*)wdata +
1181
+ (src1_cont || src1->type != vec_dot_type
1182
+ ? (i11 + i12 * ne11 + i13 * ne12 * ne11) * row_size
1183
+ : (i11 * nb11 + i12 * nb12 + i13 * nb13));
1184
+ float * dst_col = (float*)((char*)dst->data + (i1 * nb1 + i2 * nb2 + i3 * nb3));
1185
+
1186
+ //for (int64_t ir0 = iir0; ir0 < iir0 + blck_0 && ir0 < ir0_end; ++ir0) {
1187
+ // vec_dot(ne00, &dst_col[ir0], src0_row + ir0*nb01, src1_col);
1188
+ //}
1189
+
1190
+ for (int64_t ir0 = iir0; ir0 < iir0 + blck_0 && ir0 < ir0_end; ir0 += num_rows_per_vec_dot) {
1191
+ vec_dot(ne00, &tmp[ir0 - iir0], (num_rows_per_vec_dot > 1 ? 16 : 0), src0_row + ir0 * nb01, (num_rows_per_vec_dot > 1 ? nb01 : 0), src1_col, (num_rows_per_vec_dot > 1 ? src1_col_stride : 0), num_rows_per_vec_dot);
1192
+ }
1193
+
1194
+ for (int cn = 0; cn < num_rows_per_vec_dot; ++cn) {
1195
+ memcpy(&dst_col[iir0 + cn * nb1 / nb0], tmp + (cn * 16), (MIN(iir0 + blck_0, ir0_end) - iir0) * sizeof(float));
1196
+ }
1197
+ }
1198
+ }
1199
+ }
1200
+ }
1201
+
1202
+ void lm_ggml_compute_forward_mul_mat(
1203
+ const struct lm_ggml_compute_params * params,
1204
+ struct lm_ggml_tensor * dst) {
1205
+
1206
+ const struct lm_ggml_tensor * src0 = dst->src[0];
1207
+ const struct lm_ggml_tensor * src1 = dst->src[1];
1208
+
1209
+ LM_GGML_TENSOR_BINARY_OP_LOCALS
1210
+
1211
+ const int ith = params->ith;
1212
+ const int nth = params->nth;
1213
+
1214
+ enum lm_ggml_type const vec_dot_type = type_traits_cpu[src0->type].vec_dot_type;
1215
+ lm_ggml_from_float_t const from_float = type_traits_cpu[vec_dot_type].from_float;
1216
+ int64_t const vec_dot_num_rows = type_traits_cpu[src0->type].nrows;
1217
+
1218
+ LM_GGML_ASSERT(ne0 == ne01);
1219
+ LM_GGML_ASSERT(ne1 == ne11);
1220
+ LM_GGML_ASSERT(ne2 == ne12);
1221
+ LM_GGML_ASSERT(ne3 == ne13);
1222
+
1223
+ // we don't support permuted src0 or src1
1224
+ LM_GGML_ASSERT(nb00 == lm_ggml_type_size(src0->type));
1225
+ LM_GGML_ASSERT(nb10 == lm_ggml_type_size(src1->type));
1226
+
1227
+ // dst cannot be transposed or permuted
1228
+ LM_GGML_ASSERT(nb0 == sizeof(float));
1229
+ LM_GGML_ASSERT(nb0 <= nb1);
1230
+ LM_GGML_ASSERT(nb1 <= nb2);
1231
+ LM_GGML_ASSERT(nb2 <= nb3);
1232
+
1233
+ // nb01 >= nb00 - src0 is not transposed
1234
+ // compute by src0 rows
1235
+
1236
+ // TODO: extract to "extra_op"
1237
+ #if LM_GGML_USE_LLAMAFILE
1238
+ // broadcast factors
1239
+ const int64_t r2 = ne12 / ne02;
1240
+ const int64_t r3 = ne13 / ne03;
1241
+
1242
+ const bool src1_cont = lm_ggml_is_contiguous(src1);
1243
+
1244
+ if (src1_cont) {
1245
+ for (int64_t i13 = 0; i13 < ne13; i13++)
1246
+ for (int64_t i12 = 0; i12 < ne12; i12++)
1247
+ if (!llamafile_sgemm(params,
1248
+ ne01, ne11, ne00/lm_ggml_blck_size(src0->type),
1249
+ (const char *)src0->data + i12/r2*nb02 + i13/r3*nb03,
1250
+ nb01/lm_ggml_type_size(src0->type),
1251
+ (const char *)src1->data + i12*nb12 + i13*nb13,
1252
+ nb11/lm_ggml_type_size(src1->type),
1253
+ (char *)dst->data + i12*nb2 + i13*nb3,
1254
+ nb1/lm_ggml_type_size(dst->type),
1255
+ src0->type,
1256
+ src1->type,
1257
+ dst->type))
1258
+ goto UseGgmlGemm1;
1259
+ return;
1260
+ }
1261
+ UseGgmlGemm1:;
1262
+ #endif
1263
+
1264
+ if (src1->type != vec_dot_type) {
1265
+ char * wdata = params->wdata;
1266
+
1267
+ const size_t nbw0 = lm_ggml_type_size(vec_dot_type);
1268
+ const size_t nbw1 = lm_ggml_row_size(vec_dot_type, ne10);
1269
+ const size_t nbw2 = nbw1*ne11;
1270
+ const size_t nbw3 = nbw2*ne12;
1271
+
1272
+ assert(params->wsize >= ne13*nbw3);
1273
+ LM_GGML_ASSERT(src1->type == LM_GGML_TYPE_F32);
1274
+
1275
+ #if 0
1276
+ for (int64_t i13 = 0; i13 < ne13; ++i13) {
1277
+ for (int64_t i12 = 0; i12 < ne12; ++i12) {
1278
+ for (int64_t i11 = ith; i11 < ne11; i11 += nth) {
1279
+ from_float((float *)((char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11),
1280
+ (void *) (wdata + i13*nbw3 + i12*nbw2 + i11*nbw1),
1281
+ ne10);
1282
+ }
1283
+ }
1284
+ }
1285
+ #else
1286
+ for (int64_t i13 = 0; i13 < ne13; ++i13) {
1287
+ for (int64_t i12 = 0; i12 < ne12; ++i12) {
1288
+ for (int64_t i11 = 0; i11 < ne11; ++i11) {
1289
+ size_t bs = lm_ggml_blck_size(vec_dot_type);
1290
+ int64_t ne10_block_start = (ith * ne10/bs) / nth;
1291
+ int64_t ne10_block_end = ((ith + 1) * ne10/bs) / nth;
1292
+ from_float((float *)((char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11 + ne10_block_start*bs*nb10),
1293
+ (void *) (wdata + i13*nbw3 + i12*nbw2 + i11*nbw1 + ne10_block_start*nbw0),
1294
+ (ne10_block_end - ne10_block_start) * bs);
1295
+ }
1296
+ }
1297
+ }
1298
+ #endif
1299
+ }
1300
+
1301
+ if (ith == 0) {
1302
+ // Every thread starts at ith, so the first unprocessed chunk is nth. This save a bit of coordination right at the start.
1303
+ atomic_store_explicit(&params->threadpool->current_chunk, nth, memory_order_relaxed);
1304
+ }
1305
+
1306
+ lm_ggml_barrier(params->threadpool);
1307
+
1308
+ #if LM_GGML_USE_LLAMAFILE
1309
+ if (src1->type != vec_dot_type) {
1310
+ const void* wdata = (src1->type == vec_dot_type) ? src1->data : params->wdata;
1311
+ const size_t row_size = lm_ggml_row_size(vec_dot_type, ne10);
1312
+
1313
+ for (int64_t i13 = 0; i13 < ne13; i13++)
1314
+ for (int64_t i12 = 0; i12 < ne12; i12++)
1315
+ if (!llamafile_sgemm(params,
1316
+ ne01, ne11, ne00/lm_ggml_blck_size(src0->type),
1317
+ (const char *)src0->data + i12/r2*nb02 + i13/r3*nb03,
1318
+ nb01/lm_ggml_type_size(src0->type),
1319
+ (const char *)wdata + (i12*ne11 + i13*ne12*ne11)*row_size,
1320
+ row_size/lm_ggml_type_size(vec_dot_type),
1321
+ (char *)dst->data + i12*nb2 + i13*nb3,
1322
+ nb1/lm_ggml_type_size(dst->type),
1323
+ src0->type,
1324
+ vec_dot_type,
1325
+ dst->type))
1326
+ goto UseGgmlGemm2;
1327
+ return;
1328
+ }
1329
+ UseGgmlGemm2:;
1330
+ #endif
1331
+
1332
+ // This is the size of the first dimension of the result, so we can iterate that way. (see the ASSERT above, these are the same numbers)
1333
+ const int64_t nr0 = ne0;
1334
+
1335
+ // This is the size of the rest of the dimensions of the result
1336
+ const int64_t nr1 = ne1 * ne2 * ne3;
1337
+
1338
+ // Now select a reasonable chunk size.
1339
+ int chunk_size = 16;
1340
+
1341
+ // We need to step up the size if it's small
1342
+ if (nr0 == 1 || nr1 == 1) {
1343
+ chunk_size = 64;
1344
+ }
1345
+
1346
+ // distribute the work across the inner or outer loop based on which one is larger
1347
+ // The number of chunks in the 0/1 dim.
1348
+ // CEIL(nr0/chunk_size)
1349
+ int64_t nchunk0 = (nr0 + chunk_size - 1) / chunk_size;
1350
+ int64_t nchunk1 = (nr1 + chunk_size - 1) / chunk_size;
1351
+
1352
+ // If the chunking is poor for the number of threads on this setup, scrap the whole plan. Re-chunk it by thread.
1353
+ // Also, chunking by thread was measured to have perform better on NUMA systems. See https://github.com/ggml-org/llama.cpp/pull/6915
1354
+ // In theory, chunking should be just as useful on NUMA and non NUMA systems, but testing disagreed with that.
1355
+ if (nchunk0 * nchunk1 < nth * 4 || lm_ggml_is_numa()) {
1356
+ // distribute the thread work across the inner or outer loop based on which one is larger
1357
+ nchunk0 = nr0 > nr1 ? nth : 1; // parallelize by src0 rows
1358
+ nchunk1 = nr0 > nr1 ? 1 : nth; // parallelize by src1 rows
1359
+ }
1360
+
1361
+ // The number of elements in each chunk
1362
+ const int64_t dr0 = (nr0 + nchunk0 - 1) / nchunk0;
1363
+ const int64_t dr1 = (nr1 + nchunk1 - 1) / nchunk1;
1364
+
1365
+ // The first chunk comes from our thread_id, the rest will get auto-assigned.
1366
+ int current_chunk = ith;
1367
+
1368
+ while (current_chunk < nchunk0 * nchunk1) {
1369
+ const int64_t ith0 = current_chunk % nchunk0;
1370
+ const int64_t ith1 = current_chunk / nchunk0;
1371
+
1372
+ const int64_t ir0_start = dr0 * ith0;
1373
+ const int64_t ir0_end = MIN(ir0_start + dr0, nr0);
1374
+
1375
+ const int64_t ir1_start = dr1 * ith1;
1376
+ const int64_t ir1_end = MIN(ir1_start + dr1, nr1);
1377
+
1378
+ // dot kernels can handle 1 row and col at a time, but mmla kernels can process 2 rows and cols
1379
+ int64_t num_rows_per_vec_dot = vec_dot_num_rows;
1380
+
1381
+ // these checks are needed to avoid crossing dim1 boundaries
1382
+ // can be optimized, but the logic would become more complicated, so keeping it like this for simplicity
1383
+ if ((nr0 % 2 != 0) || (ne11 % 2 != 0) || ((ir0_end - ir0_start) % 2 != 0) || ((ir1_end - ir1_start) % 2 != 0)) {
1384
+ num_rows_per_vec_dot = 1;
1385
+ }
1386
+ lm_ggml_compute_forward_mul_mat_one_chunk(params, dst, src0->type, num_rows_per_vec_dot, ir0_start, ir0_end, ir1_start, ir1_end);
1387
+
1388
+ if (nth >= nchunk0 * nchunk1) {
1389
+ break;
1390
+ }
1391
+
1392
+ current_chunk = atomic_fetch_add_explicit(&params->threadpool->current_chunk, 1, memory_order_relaxed);
1393
+ }
1394
+ }
1395
+
1396
+ // lm_ggml_compute_forward_mul_mat_id
1397
+
1398
+ #define MMID_MATRIX_ROW(row_id, i1) matrix_rows[(row_id)*ids->ne[0]*ids->ne[1] + (i1)]
1399
+
1400
+ struct mmid_row_mapping {
1401
+ int32_t i1;
1402
+ int32_t i2;
1403
+ };
1404
+
1405
+ static void lm_ggml_compute_forward_mul_mat_id_one_chunk(
1406
+ struct lm_ggml_tensor * dst,
1407
+ const struct lm_ggml_tensor * src0,
1408
+ const struct lm_ggml_tensor * src1,
1409
+ const struct lm_ggml_tensor * ids,
1410
+ const int64_t cur_a,
1411
+ const int64_t ir0_start,
1412
+ const int64_t ir0_end,
1413
+ const int64_t ir1_start,
1414
+ const int64_t ir1_end,
1415
+ const char * src0_cur,
1416
+ const struct mmid_row_mapping * matrix_rows,
1417
+ const size_t row_size,
1418
+ const bool src1_cont,
1419
+ const void * wdata) {
1420
+
1421
+ LM_GGML_TENSOR_BINARY_OP_LOCALS
1422
+
1423
+ const enum lm_ggml_type type = src0->type;
1424
+
1425
+ lm_ggml_vec_dot_t const vec_dot = type_traits_cpu[type].vec_dot;
1426
+ enum lm_ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
1427
+
1428
+ const int64_t blck_0 = 16;
1429
+ const int64_t blck_1 = 16;
1430
+
1431
+ float tmp[16];
1432
+
1433
+ for (int64_t iir1 = ir1_start; iir1 < ir1_end; iir1 += blck_1) {
1434
+ for (int64_t iir0 = ir0_start; iir0 < ir0_end; iir0 += blck_0) {
1435
+ for (int64_t ir1 = iir1; ir1 < iir1 + blck_1 && ir1 < ir1_end; ++ir1) {
1436
+ const int64_t _i12 = ir1; // logical row index for this expert
1437
+
1438
+ struct mmid_row_mapping row_mapping = MMID_MATRIX_ROW(cur_a, _i12);
1439
+ const int id = row_mapping.i1; // selected expert index
1440
+
1441
+ const int64_t i11 = id % ne11;
1442
+ const int64_t i12 = row_mapping.i2; // row index in src1
1443
+
1444
+ const int64_t i1 = id; // selected expert index
1445
+ const int64_t i2 = i12; // row
1446
+
1447
+ // desc: when src1 is not a contiguous memory block we have to calculate the offset using the strides
1448
+ // if it is, then we have either copied the data to params->wdata and made it contiguous or we are using
1449
+ // the original src1 data pointer, so we should index using the indices directly
1450
+ // TODO: this is a bit of a hack, we should probably have a better way to handle this
1451
+ const char * src1_col = (const char *) wdata +
1452
+ (src1_cont || src1->type != vec_dot_type
1453
+ ? (i11 + i12*ne11)*row_size
1454
+ : (i11*nb11 + i12*nb12));
1455
+
1456
+ float * dst_col = (float *) ((char *) dst->data + (i1*nb1 + i2*nb2));
1457
+
1458
+ for (int64_t ir0 = iir0; ir0 < iir0 + blck_0 && ir0 < ir0_end; ++ir0) {
1459
+ vec_dot(ne00, &tmp[ir0 - iir0], 0, src0_cur + ir0*nb01, 0, src1_col, 0, 1);
1460
+ }
1461
+
1462
+ memcpy(&dst_col[iir0], tmp, (MIN(iir0 + blck_0, ir0_end) - iir0)*sizeof(float));
1463
+ }
1464
+ }
1465
+ }
1466
+ }
1467
+
1468
+ static void * incr_ptr_aligned(void ** p, size_t size, size_t align) {
1469
+
1470
+ void * ptr = *p;
1471
+ ptr = (void *) LM_GGML_PAD((uintptr_t) ptr, align);
1472
+ *p = (void *) ((char *) ptr + size);
1473
+ return ptr;
1474
+ }
1475
+
1476
+ static void lm_ggml_compute_forward_mul_mat_id(
1477
+ const struct lm_ggml_compute_params * params,
1478
+ struct lm_ggml_tensor * dst) {
1479
+
1480
+ const struct lm_ggml_tensor * src0 = dst->src[0];
1481
+ const struct lm_ggml_tensor * src1 = dst->src[1];
1482
+ const struct lm_ggml_tensor * ids = dst->src[2];
1483
+
1484
+ LM_GGML_TENSOR_BINARY_OP_LOCALS
1485
+
1486
+ const int ith = params->ith;
1487
+ const int nth = params->nth;
1488
+
1489
+ const enum lm_ggml_type type = src0->type;
1490
+
1491
+ const bool src1_cont = lm_ggml_is_contiguous(src1);
1492
+
1493
+ enum lm_ggml_type const vec_dot_type = type_traits_cpu[type].vec_dot_type;
1494
+ lm_ggml_from_float_t const from_float = type_traits_cpu[vec_dot_type].from_float;
1495
+
1496
+ // we don't support permuted src0 or src1
1497
+ LM_GGML_ASSERT(nb00 == lm_ggml_type_size(type));
1498
+ LM_GGML_ASSERT(nb10 == lm_ggml_type_size(src1->type));
1499
+
1500
+ // dst cannot be transposed or permuted
1501
+ LM_GGML_ASSERT(nb0 == sizeof(float));
1502
+ LM_GGML_ASSERT(nb0 <= nb1);
1503
+ LM_GGML_ASSERT(nb1 <= nb2);
1504
+ LM_GGML_ASSERT(nb2 <= nb3);
1505
+
1506
+ // row groups
1507
+ const int n_ids = ids->ne[0]; // n_expert_used
1508
+ const int n_as = ne02; // n_expert
1509
+
1510
+ void * wdata_cur = params->wdata;
1511
+
1512
+ if (src1->type != vec_dot_type) {
1513
+ incr_ptr_aligned(&wdata_cur, lm_ggml_row_size(vec_dot_type, lm_ggml_nelements(src1)), sizeof(int64_t));
1514
+ }
1515
+
1516
+ int64_t * matrix_row_counts = // [n_as]
1517
+ incr_ptr_aligned(&wdata_cur, n_as*sizeof(int64_t), sizeof(int64_t));
1518
+
1519
+ struct mmid_row_mapping * matrix_rows = // [n_as][ids->ne[0]*ids->ne[1]]
1520
+ incr_ptr_aligned(&wdata_cur, n_as*ids->ne[0]*ids->ne[1]*sizeof(struct mmid_row_mapping), sizeof(int64_t));
1521
+
1522
+ char (*atomic_current_chunk)[CACHE_LINE_SIZE] = // [n_as]
1523
+ incr_ptr_aligned(&wdata_cur, CACHE_LINE_SIZE * n_as, CACHE_LINE_SIZE);
1524
+
1525
+ LM_GGML_ASSERT(params->wsize >= (size_t)((char *) wdata_cur - (char *) params->wdata));
1526
+
1527
+ if (src1->type != vec_dot_type) {
1528
+ char * wdata = params->wdata;
1529
+
1530
+ const size_t nbw0 = lm_ggml_type_size(vec_dot_type);
1531
+ const size_t nbw1 = lm_ggml_row_size(vec_dot_type, ne10);
1532
+ const size_t nbw2 = nbw1*ne11;
1533
+ const size_t nbw3 = nbw2*ne12;
1534
+
1535
+ assert(params->wsize >= ne13*nbw3);
1536
+ LM_GGML_ASSERT(src1->type == LM_GGML_TYPE_F32);
1537
+
1538
+ #if 0
1539
+ for (int64_t i13 = 0; i13 < ne13; ++i13) {
1540
+ for (int64_t i12 = ith; i12 < ne12; i12 += nth) {
1541
+ for (int64_t i11 = 0; i11 < ne11; ++i11) {
1542
+ from_float((float *)((char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11),
1543
+ (void *) (wdata + i13*nbw3 + i12*nbw2 + i11*nbw1),
1544
+ ne10);
1545
+ }
1546
+ }
1547
+ }
1548
+ #else
1549
+ for (int64_t i13 = 0; i13 < ne13; ++i13) {
1550
+ for (int64_t i12 = 0; i12 < ne12; ++i12) {
1551
+ for (int64_t i11 = 0; i11 < ne11; ++i11) {
1552
+ size_t bs = lm_ggml_blck_size(vec_dot_type);
1553
+ int64_t ne10_block_start = (ith * ne10/bs) / nth;
1554
+ int64_t ne10_block_end = ((ith + 1) * ne10/bs) / nth;
1555
+ from_float((float *)((char *) src1->data + i13*nb13 + i12*nb12 + i11*nb11 + ne10_block_start*bs*nb10),
1556
+ (void *) (wdata + i13*nbw3 + i12*nbw2 + i11*nbw1 + ne10_block_start*nbw0),
1557
+ (ne10_block_end - ne10_block_start) * bs);
1558
+ }
1559
+ }
1560
+ }
1561
+ #endif
1562
+ }
1563
+
1564
+ if (ith == 0) {
1565
+ // initialize matrix_row_counts
1566
+ memset(matrix_row_counts, 0, n_as*sizeof(int64_t));
1567
+
1568
+ // group rows by src0 matrix
1569
+ for (int64_t iid1 = 0; iid1 < ids->ne[1]; ++iid1) {
1570
+ for (int id = 0; id < n_ids; ++id) {
1571
+ const int32_t i02 = *(const int32_t *) ((const char *) ids->data + iid1*ids->nb[1] + id*ids->nb[0]);
1572
+
1573
+ assert(i02 >= 0 && i02 < n_as);
1574
+
1575
+ MMID_MATRIX_ROW(i02, matrix_row_counts[i02]) = (struct mmid_row_mapping) {id, iid1};
1576
+ matrix_row_counts[i02] += 1;
1577
+ }
1578
+ }
1579
+ }
1580
+
1581
+ // reset current_chunk
1582
+ for (int cur_a = ith; cur_a < n_as; cur_a += nth) {
1583
+ atomic_int * current_chunk_ctr = (atomic_int *)(atomic_current_chunk + cur_a);
1584
+ *current_chunk_ctr = nth;
1585
+ }
1586
+
1587
+ lm_ggml_barrier(params->threadpool);
1588
+
1589
+ for (int cur_a = 0; cur_a < n_as; ++cur_a) {
1590
+ const int64_t cne1 = matrix_row_counts[cur_a];
1591
+
1592
+ if (cne1 == 0) {
1593
+ continue;
1594
+ }
1595
+
1596
+ const char * src0_cur = (const char *) src0->data + cur_a * nb02;
1597
+ const void * wdata = (src1->type == vec_dot_type) ? src1->data : params->wdata;
1598
+ const size_t row_size = lm_ggml_row_size(vec_dot_type, ne10);
1599
+
1600
+ const int64_t nr0 = ne01;
1601
+ const int64_t nr1 = cne1;
1602
+
1603
+ int chunk_size = 16;
1604
+ if (nr0 == 1 || nr1 == 1) {
1605
+ chunk_size = 64;
1606
+ }
1607
+
1608
+ #if defined(__aarch64__)
1609
+ // disable for ARM
1610
+ const bool disable_chunking = true;
1611
+ #else
1612
+ // disable for NUMA
1613
+ const bool disable_chunking = lm_ggml_is_numa();
1614
+ #endif // defined(__aarch64__)
1615
+
1616
+ int64_t nchunk0 = (nr0 + chunk_size - 1) / chunk_size;
1617
+ int64_t nchunk1 = (nr1 + chunk_size - 1) / chunk_size;
1618
+
1619
+ if (nchunk0 * nchunk1 < nth * 4 || disable_chunking) {
1620
+ nchunk0 = nr0 > nr1 ? nth : 1;
1621
+ nchunk1 = nr0 > nr1 ? 1 : nth;
1622
+ }
1623
+
1624
+ const int64_t dr0 = (nr0 + nchunk0 - 1) / nchunk0;
1625
+ const int64_t dr1 = (nr1 + nchunk1 - 1) / nchunk1;
1626
+
1627
+ int current_chunk = ith;
1628
+
1629
+ atomic_int * current_chunk_ctr = (atomic_int *)(atomic_current_chunk + cur_a);
1630
+
1631
+ while (current_chunk < nchunk0 * nchunk1) {
1632
+ const int64_t ith0 = current_chunk % nchunk0;
1633
+ const int64_t ith1 = current_chunk / nchunk0;
1634
+
1635
+ const int64_t ir0_start = dr0 * ith0;
1636
+ const int64_t ir0_end = MIN(ir0_start + dr0, nr0);
1637
+
1638
+ const int64_t ir1_start = dr1 * ith1;
1639
+ const int64_t ir1_end = MIN(ir1_start + dr1, nr1);
1640
+
1641
+ lm_ggml_compute_forward_mul_mat_id_one_chunk(
1642
+ dst, src0, src1, ids, cur_a,
1643
+ ir0_start, ir0_end, ir1_start, ir1_end,
1644
+ src0_cur, matrix_rows, row_size, src1_cont, wdata
1645
+ );
1646
+
1647
+ if (nth >= nchunk0 * nchunk1) {
1648
+ break;
1649
+ }
1650
+
1651
+ current_chunk = atomic_fetch_add_explicit(current_chunk_ctr, 1, memory_order_relaxed);
1652
+ }
1653
+ }
1654
+ }
1655
+
1656
+ /////////////////////////////////
1657
+
1658
+ static void lm_ggml_compute_forward(struct lm_ggml_compute_params * params, struct lm_ggml_tensor * tensor) {
1659
+ LM_GGML_ASSERT(params);
1660
+
1661
+ if (tensor->op == LM_GGML_OP_NONE || lm_ggml_is_empty(tensor)) {
1662
+ return;
1663
+ }
1664
+
1665
+ // extra_buffer op?
1666
+ if (lm_ggml_cpu_extra_compute_forward(params, tensor)) {
1667
+ return;
1668
+ }
1669
+
1670
+ switch (tensor->op) {
1671
+ case LM_GGML_OP_DUP:
1672
+ {
1673
+ lm_ggml_compute_forward_dup(params, tensor);
1674
+ } break;
1675
+ case LM_GGML_OP_ADD:
1676
+ {
1677
+ lm_ggml_compute_forward_add(params, tensor);
1678
+ } break;
1679
+ case LM_GGML_OP_ADD_ID:
1680
+ {
1681
+ lm_ggml_compute_forward_add_id(params, tensor);
1682
+ } break;
1683
+ case LM_GGML_OP_ADD1:
1684
+ {
1685
+ lm_ggml_compute_forward_add1(params, tensor);
1686
+ } break;
1687
+ case LM_GGML_OP_ACC:
1688
+ {
1689
+ lm_ggml_compute_forward_acc(params, tensor);
1690
+ } break;
1691
+ case LM_GGML_OP_SUB:
1692
+ {
1693
+ lm_ggml_compute_forward_sub(params, tensor);
1694
+ } break;
1695
+ case LM_GGML_OP_MUL:
1696
+ {
1697
+ lm_ggml_compute_forward_mul(params, tensor);
1698
+ } break;
1699
+ case LM_GGML_OP_DIV:
1700
+ {
1701
+ lm_ggml_compute_forward_div(params, tensor);
1702
+ } break;
1703
+ case LM_GGML_OP_SQR:
1704
+ {
1705
+ lm_ggml_compute_forward_sqr(params, tensor);
1706
+ } break;
1707
+ case LM_GGML_OP_SQRT:
1708
+ {
1709
+ lm_ggml_compute_forward_sqrt(params, tensor);
1710
+ } break;
1711
+ case LM_GGML_OP_LOG:
1712
+ {
1713
+ lm_ggml_compute_forward_log(params, tensor);
1714
+ } break;
1715
+ case LM_GGML_OP_SIN:
1716
+ {
1717
+ lm_ggml_compute_forward_sin(params, tensor);
1718
+ } break;
1719
+ case LM_GGML_OP_COS:
1720
+ {
1721
+ lm_ggml_compute_forward_cos(params, tensor);
1722
+ } break;
1723
+ case LM_GGML_OP_SUM:
1724
+ {
1725
+ lm_ggml_compute_forward_sum(params, tensor);
1726
+ } break;
1727
+ case LM_GGML_OP_SUM_ROWS:
1728
+ {
1729
+ lm_ggml_compute_forward_sum_rows(params, tensor);
1730
+ } break;
1731
+ case LM_GGML_OP_MEAN:
1732
+ {
1733
+ lm_ggml_compute_forward_mean(params, tensor);
1734
+ } break;
1735
+ case LM_GGML_OP_ARGMAX:
1736
+ {
1737
+ lm_ggml_compute_forward_argmax(params, tensor);
1738
+ } break;
1739
+ case LM_GGML_OP_COUNT_EQUAL:
1740
+ {
1741
+ lm_ggml_compute_forward_count_equal(params, tensor);
1742
+ } break;
1743
+ case LM_GGML_OP_REPEAT:
1744
+ {
1745
+ lm_ggml_compute_forward_repeat(params, tensor);
1746
+ } break;
1747
+ case LM_GGML_OP_REPEAT_BACK:
1748
+ {
1749
+ lm_ggml_compute_forward_repeat_back(params, tensor);
1750
+ } break;
1751
+ case LM_GGML_OP_CONCAT:
1752
+ {
1753
+ lm_ggml_compute_forward_concat(params, tensor);
1754
+ } break;
1755
+ case LM_GGML_OP_SILU_BACK:
1756
+ {
1757
+ lm_ggml_compute_forward_silu_back(params, tensor);
1758
+ } break;
1759
+ case LM_GGML_OP_NORM:
1760
+ {
1761
+ lm_ggml_compute_forward_norm(params, tensor);
1762
+ } break;
1763
+ case LM_GGML_OP_RMS_NORM:
1764
+ {
1765
+ lm_ggml_compute_forward_rms_norm(params, tensor);
1766
+ } break;
1767
+ case LM_GGML_OP_RMS_NORM_BACK:
1768
+ {
1769
+ lm_ggml_compute_forward_rms_norm_back(params, tensor);
1770
+ } break;
1771
+ case LM_GGML_OP_GROUP_NORM:
1772
+ {
1773
+ lm_ggml_compute_forward_group_norm(params, tensor);
1774
+ } break;
1775
+ case LM_GGML_OP_L2_NORM:
1776
+ {
1777
+ lm_ggml_compute_forward_l2_norm(params, tensor);
1778
+ } break;
1779
+ case LM_GGML_OP_MUL_MAT:
1780
+ {
1781
+ lm_ggml_compute_forward_mul_mat(params, tensor);
1782
+ } break;
1783
+ case LM_GGML_OP_MUL_MAT_ID:
1784
+ {
1785
+ lm_ggml_compute_forward_mul_mat_id(params, tensor);
1786
+ } break;
1787
+ case LM_GGML_OP_OUT_PROD:
1788
+ {
1789
+ lm_ggml_compute_forward_out_prod(params, tensor);
1790
+ } break;
1791
+ case LM_GGML_OP_SCALE:
1792
+ {
1793
+ lm_ggml_compute_forward_scale(params, tensor);
1794
+ } break;
1795
+ case LM_GGML_OP_SET:
1796
+ {
1797
+ lm_ggml_compute_forward_set(params, tensor);
1798
+ } break;
1799
+ case LM_GGML_OP_CPY:
1800
+ {
1801
+ lm_ggml_compute_forward_cpy(params, tensor);
1802
+ } break;
1803
+ case LM_GGML_OP_CONT:
1804
+ {
1805
+ lm_ggml_compute_forward_cont(params, tensor);
1806
+ } break;
1807
+ case LM_GGML_OP_RESHAPE:
1808
+ {
1809
+ lm_ggml_compute_forward_reshape(params, tensor);
1810
+ } break;
1811
+ case LM_GGML_OP_VIEW:
1812
+ {
1813
+ lm_ggml_compute_forward_view(params, tensor);
1814
+ } break;
1815
+ case LM_GGML_OP_PERMUTE:
1816
+ {
1817
+ lm_ggml_compute_forward_permute(params, tensor);
1818
+ } break;
1819
+ case LM_GGML_OP_TRANSPOSE:
1820
+ {
1821
+ lm_ggml_compute_forward_transpose(params, tensor);
1822
+ } break;
1823
+ case LM_GGML_OP_GET_ROWS:
1824
+ {
1825
+ lm_ggml_compute_forward_get_rows(params, tensor);
1826
+ } break;
1827
+ case LM_GGML_OP_GET_ROWS_BACK:
1828
+ {
1829
+ lm_ggml_compute_forward_get_rows_back(params, tensor);
1830
+ } break;
1831
+ case LM_GGML_OP_SET_ROWS:
1832
+ {
1833
+ lm_ggml_compute_forward_set_rows(params, tensor);
1834
+ } break;
1835
+ case LM_GGML_OP_DIAG:
1836
+ {
1837
+ lm_ggml_compute_forward_diag(params, tensor);
1838
+ } break;
1839
+ case LM_GGML_OP_DIAG_MASK_INF:
1840
+ {
1841
+ lm_ggml_compute_forward_diag_mask_inf(params, tensor);
1842
+ } break;
1843
+ case LM_GGML_OP_DIAG_MASK_ZERO:
1844
+ {
1845
+ lm_ggml_compute_forward_diag_mask_zero(params, tensor);
1846
+ } break;
1847
+ case LM_GGML_OP_SOFT_MAX:
1848
+ {
1849
+ lm_ggml_compute_forward_soft_max(params, tensor);
1850
+ } break;
1851
+ case LM_GGML_OP_SOFT_MAX_BACK:
1852
+ {
1853
+ lm_ggml_compute_forward_soft_max_ext_back(params, tensor);
1854
+ } break;
1855
+ case LM_GGML_OP_ROPE:
1856
+ {
1857
+ lm_ggml_compute_forward_rope(params, tensor);
1858
+ } break;
1859
+ case LM_GGML_OP_ROPE_BACK:
1860
+ {
1861
+ lm_ggml_compute_forward_rope_back(params, tensor);
1862
+ } break;
1863
+ case LM_GGML_OP_CLAMP:
1864
+ {
1865
+ lm_ggml_compute_forward_clamp(params, tensor);
1866
+ } break;
1867
+ case LM_GGML_OP_CONV_TRANSPOSE_1D:
1868
+ {
1869
+ lm_ggml_compute_forward_conv_transpose_1d(params, tensor);
1870
+ } break;
1871
+ case LM_GGML_OP_IM2COL:
1872
+ {
1873
+ lm_ggml_compute_forward_im2col(params, tensor);
1874
+ } break;
1875
+ case LM_GGML_OP_IM2COL_BACK:
1876
+ {
1877
+ lm_ggml_compute_forward_im2col_back_f32(params, tensor);
1878
+ } break;
1879
+ case LM_GGML_OP_CONV_2D:
1880
+ {
1881
+ lm_ggml_compute_forward_conv_2d(params, tensor);
1882
+ } break;
1883
+ case LM_GGML_OP_CONV_3D:
1884
+ {
1885
+ lm_ggml_compute_forward_conv_3d(params, tensor);
1886
+ } break;
1887
+ case LM_GGML_OP_CONV_2D_DW:
1888
+ {
1889
+ lm_ggml_compute_forward_conv_2d_dw(params, tensor);
1890
+ } break;
1891
+ case LM_GGML_OP_CONV_TRANSPOSE_2D:
1892
+ {
1893
+ lm_ggml_compute_forward_conv_transpose_2d(params, tensor);
1894
+ } break;
1895
+ case LM_GGML_OP_POOL_1D:
1896
+ {
1897
+ lm_ggml_compute_forward_pool_1d(params, tensor);
1898
+ } break;
1899
+ case LM_GGML_OP_POOL_2D:
1900
+ {
1901
+ lm_ggml_compute_forward_pool_2d(params, tensor);
1902
+ } break;
1903
+ case LM_GGML_OP_POOL_2D_BACK:
1904
+ {
1905
+ lm_ggml_compute_forward_pool_2d_back(params, tensor);
1906
+ } break;
1907
+ case LM_GGML_OP_UPSCALE:
1908
+ {
1909
+ lm_ggml_compute_forward_upscale(params, tensor);
1910
+ } break;
1911
+ case LM_GGML_OP_PAD:
1912
+ {
1913
+ lm_ggml_compute_forward_pad(params, tensor);
1914
+ } break;
1915
+ case LM_GGML_OP_PAD_REFLECT_1D:
1916
+ {
1917
+ lm_ggml_compute_forward_pad_reflect_1d(params, tensor);
1918
+ } break;
1919
+ case LM_GGML_OP_ROLL:
1920
+ {
1921
+ lm_ggml_compute_forward_roll(params, tensor);
1922
+ } break;
1923
+ case LM_GGML_OP_ARANGE:
1924
+ {
1925
+ lm_ggml_compute_forward_arange(params, tensor);
1926
+ } break;
1927
+ case LM_GGML_OP_TIMESTEP_EMBEDDING:
1928
+ {
1929
+ lm_ggml_compute_forward_timestep_embedding(params, tensor);
1930
+ } break;
1931
+ case LM_GGML_OP_ARGSORT:
1932
+ {
1933
+ lm_ggml_compute_forward_argsort(params, tensor);
1934
+ } break;
1935
+ case LM_GGML_OP_LEAKY_RELU:
1936
+ {
1937
+ lm_ggml_compute_forward_leaky_relu(params, tensor);
1938
+ } break;
1939
+ case LM_GGML_OP_FLASH_ATTN_EXT:
1940
+ {
1941
+ lm_ggml_compute_forward_flash_attn_ext(params, tensor);
1942
+ } break;
1943
+ case LM_GGML_OP_FLASH_ATTN_BACK:
1944
+ {
1945
+ int32_t t = lm_ggml_get_op_params_i32(tensor, 0);
1946
+ LM_GGML_ASSERT(t == 0 || t == 1);
1947
+ bool masked = t != 0;
1948
+ lm_ggml_compute_forward_flash_attn_back(params, masked, tensor);
1949
+ } break;
1950
+ case LM_GGML_OP_SSM_CONV:
1951
+ {
1952
+ lm_ggml_compute_forward_ssm_conv(params, tensor);
1953
+ } break;
1954
+ case LM_GGML_OP_SSM_SCAN:
1955
+ {
1956
+ lm_ggml_compute_forward_ssm_scan(params, tensor);
1957
+ } break;
1958
+ case LM_GGML_OP_WIN_PART:
1959
+ {
1960
+ lm_ggml_compute_forward_win_part(params, tensor);
1961
+ } break;
1962
+ case LM_GGML_OP_WIN_UNPART:
1963
+ {
1964
+ lm_ggml_compute_forward_win_unpart(params, tensor);
1965
+ } break;
1966
+ case LM_GGML_OP_UNARY:
1967
+ {
1968
+ lm_ggml_compute_forward_unary(params, tensor);
1969
+ } break;
1970
+ case LM_GGML_OP_GLU:
1971
+ {
1972
+ lm_ggml_compute_forward_glu(params, tensor);
1973
+ } break;
1974
+ case LM_GGML_OP_GET_REL_POS:
1975
+ {
1976
+ lm_ggml_compute_forward_get_rel_pos(params, tensor);
1977
+ } break;
1978
+ case LM_GGML_OP_ADD_REL_POS:
1979
+ {
1980
+ lm_ggml_compute_forward_add_rel_pos(params, tensor);
1981
+ } break;
1982
+ case LM_GGML_OP_RWKV_WKV6:
1983
+ {
1984
+ lm_ggml_compute_forward_rwkv_wkv6(params, tensor);
1985
+ } break;
1986
+ case LM_GGML_OP_GATED_LINEAR_ATTN:
1987
+ {
1988
+ lm_ggml_compute_forward_gla(params, tensor);
1989
+ } break;
1990
+ case LM_GGML_OP_RWKV_WKV7:
1991
+ {
1992
+ lm_ggml_compute_forward_rwkv_wkv7(params, tensor);
1993
+ } break;
1994
+ case LM_GGML_OP_MAP_CUSTOM1:
1995
+ {
1996
+ lm_ggml_compute_forward_map_custom1(params, tensor);
1997
+ }
1998
+ break;
1999
+ case LM_GGML_OP_MAP_CUSTOM2:
2000
+ {
2001
+ lm_ggml_compute_forward_map_custom2(params, tensor);
2002
+ }
2003
+ break;
2004
+ case LM_GGML_OP_MAP_CUSTOM3:
2005
+ {
2006
+ lm_ggml_compute_forward_map_custom3(params, tensor);
2007
+ }
2008
+ break;
2009
+ case LM_GGML_OP_CUSTOM:
2010
+ {
2011
+ lm_ggml_compute_forward_custom(params, tensor);
2012
+ }
2013
+ break;
2014
+ case LM_GGML_OP_CROSS_ENTROPY_LOSS:
2015
+ {
2016
+ lm_ggml_compute_forward_cross_entropy_loss(params, tensor);
2017
+ }
2018
+ break;
2019
+ case LM_GGML_OP_CROSS_ENTROPY_LOSS_BACK:
2020
+ {
2021
+ lm_ggml_compute_forward_cross_entropy_loss_back(params, tensor);
2022
+ }
2023
+ break;
2024
+ case LM_GGML_OP_OPT_STEP_ADAMW:
2025
+ {
2026
+ lm_ggml_compute_forward_opt_step_adamw(params, tensor);
2027
+ }
2028
+ break;
2029
+ case LM_GGML_OP_OPT_STEP_SGD:
2030
+ {
2031
+ lm_ggml_compute_forward_opt_step_sgd(params, tensor);
2032
+ }
2033
+ break;
2034
+ case LM_GGML_OP_NONE:
2035
+ {
2036
+ // nop
2037
+ } break;
2038
+ case LM_GGML_OP_COUNT:
2039
+ {
2040
+ LM_GGML_ABORT("fatal error");
2041
+ }
2042
+ }
2043
+ }
2044
+
2045
+ // Android's libc implementation "bionic" does not support setting affinity
2046
+ #if defined(__gnu_linux__)
2047
+ static void set_numa_thread_affinity(int thread_n) {
2048
+ if (!lm_ggml_is_numa()) {
2049
+ return;
2050
+ }
2051
+
2052
+ int node_num;
2053
+ int rv;
2054
+ size_t setsize = CPU_ALLOC_SIZE(g_state.numa.total_cpus);
2055
+
2056
+ switch(g_state.numa.numa_strategy) {
2057
+ case LM_GGML_NUMA_STRATEGY_DISTRIBUTE:
2058
+ // run thread on node_num thread_n / (threads per node)
2059
+ node_num = thread_n % g_state.numa.n_nodes;
2060
+ break;
2061
+ case LM_GGML_NUMA_STRATEGY_ISOLATE:
2062
+ // run thread on current_node
2063
+ node_num = g_state.numa.current_node;
2064
+ break;
2065
+ case LM_GGML_NUMA_STRATEGY_NUMACTL:
2066
+ // use the cpuset that numactl gave us
2067
+ rv = pthread_setaffinity_np(pthread_self(), setsize, &g_state.numa.cpuset);
2068
+ if (rv) {
2069
+ fprintf(stderr, "warning: pthread_setaffinity_np() failed: %s\n",strerror(rv));
2070
+ }
2071
+ return;
2072
+ default:
2073
+ return;
2074
+ }
2075
+
2076
+ struct lm_ggml_numa_node * node = &g_state.numa.nodes[node_num];
2077
+
2078
+ cpu_set_t * cpus = CPU_ALLOC(g_state.numa.total_cpus);
2079
+ CPU_ZERO_S(setsize, cpus);
2080
+ for (size_t i = 0; i < node->n_cpus; ++i) {
2081
+ CPU_SET_S(node->cpus[i], setsize, cpus);
2082
+ }
2083
+
2084
+ rv = pthread_setaffinity_np(pthread_self(), setsize, cpus);
2085
+ if (rv) {
2086
+ fprintf(stderr, "warning: pthread_setaffinity_np() failed: %s\n", strerror(rv));
2087
+ }
2088
+
2089
+ CPU_FREE(cpus);
2090
+ }
2091
+
2092
+ static void clear_numa_thread_affinity(void) {
2093
+ if (!lm_ggml_is_numa()) {
2094
+ return;
2095
+ }
2096
+
2097
+ size_t setsize = CPU_ALLOC_SIZE(g_state.numa.total_cpus);
2098
+
2099
+ cpu_set_t * cpus = CPU_ALLOC(g_state.numa.total_cpus);
2100
+ CPU_ZERO_S(setsize, cpus);
2101
+ for (unsigned i = 0; i < g_state.numa.total_cpus; ++i) {
2102
+ CPU_SET_S(i, setsize, cpus);
2103
+ }
2104
+
2105
+ int rv = pthread_setaffinity_np(pthread_self(), setsize, cpus);
2106
+ if (rv) {
2107
+ fprintf(stderr, "warning: pthread_setaffinity_np() failed: %s\n", strerror(rv));
2108
+ }
2109
+
2110
+ CPU_FREE(cpus);
2111
+ }
2112
+ #else
2113
+ // TODO: Windows etc.
2114
+ // (the linux implementation may also work on BSD, someone should test)
2115
+ static void set_numa_thread_affinity(int thread_n) { UNUSED(thread_n); }
2116
+ static void clear_numa_thread_affinity(void) {}
2117
+ #endif
2118
+
2119
+ static int lm_ggml_get_n_tasks(struct lm_ggml_tensor * node, int n_threads) {
2120
+ int n_tasks = 0;
2121
+
2122
+ if (lm_ggml_is_empty(node)) {
2123
+ // no need to multi-thread a no-op
2124
+ n_tasks = 1;
2125
+ return n_tasks;
2126
+ }
2127
+
2128
+ switch (node->op) {
2129
+ case LM_GGML_OP_CPY:
2130
+ case LM_GGML_OP_DUP:
2131
+ case LM_GGML_OP_CONT:
2132
+ case LM_GGML_OP_ADD:
2133
+ case LM_GGML_OP_ADD_ID:
2134
+ case LM_GGML_OP_ADD1:
2135
+ case LM_GGML_OP_ACC:
2136
+ {
2137
+ n_tasks = n_threads;
2138
+ } break;
2139
+ case LM_GGML_OP_SUB:
2140
+ case LM_GGML_OP_SQR:
2141
+ case LM_GGML_OP_SQRT:
2142
+ case LM_GGML_OP_LOG:
2143
+ case LM_GGML_OP_SIN:
2144
+ case LM_GGML_OP_COS:
2145
+ case LM_GGML_OP_SUM:
2146
+ case LM_GGML_OP_SUM_ROWS:
2147
+ case LM_GGML_OP_MEAN:
2148
+ case LM_GGML_OP_ARGMAX:
2149
+ {
2150
+ n_tasks = 1;
2151
+ } break;
2152
+ case LM_GGML_OP_COUNT_EQUAL:
2153
+ {
2154
+ n_tasks = n_threads;
2155
+ } break;
2156
+ case LM_GGML_OP_REPEAT:
2157
+ case LM_GGML_OP_REPEAT_BACK:
2158
+ case LM_GGML_OP_LEAKY_RELU:
2159
+ {
2160
+ n_tasks = 1;
2161
+ } break;
2162
+ case LM_GGML_OP_UNARY:
2163
+ switch (lm_ggml_get_unary_op(node)) {
2164
+ case LM_GGML_UNARY_OP_ABS:
2165
+ case LM_GGML_UNARY_OP_SGN:
2166
+ case LM_GGML_UNARY_OP_NEG:
2167
+ case LM_GGML_UNARY_OP_STEP:
2168
+ case LM_GGML_UNARY_OP_TANH:
2169
+ case LM_GGML_UNARY_OP_ELU:
2170
+ case LM_GGML_UNARY_OP_RELU:
2171
+ case LM_GGML_UNARY_OP_SIGMOID:
2172
+ case LM_GGML_UNARY_OP_HARDSWISH:
2173
+ case LM_GGML_UNARY_OP_HARDSIGMOID:
2174
+ case LM_GGML_UNARY_OP_EXP:
2175
+ {
2176
+ n_tasks = 1;
2177
+ } break;
2178
+
2179
+ case LM_GGML_UNARY_OP_GELU:
2180
+ case LM_GGML_UNARY_OP_GELU_ERF:
2181
+ case LM_GGML_UNARY_OP_GELU_QUICK:
2182
+ case LM_GGML_UNARY_OP_SILU:
2183
+ {
2184
+ n_tasks = n_threads;
2185
+ } break;
2186
+ default:
2187
+ LM_GGML_ABORT("fatal error");
2188
+ }
2189
+ break;
2190
+ case LM_GGML_OP_GLU:
2191
+ switch (lm_ggml_get_glu_op(node)) {
2192
+ case LM_GGML_GLU_OP_REGLU:
2193
+ case LM_GGML_GLU_OP_GEGLU:
2194
+ case LM_GGML_GLU_OP_SWIGLU:
2195
+ case LM_GGML_GLU_OP_SWIGLU_OAI:
2196
+ case LM_GGML_GLU_OP_GEGLU_ERF:
2197
+ case LM_GGML_GLU_OP_GEGLU_QUICK:
2198
+ {
2199
+ n_tasks = n_threads;
2200
+ } break;
2201
+ default:
2202
+ LM_GGML_ABORT("fatal error");
2203
+ }
2204
+ break;
2205
+ case LM_GGML_OP_SILU_BACK:
2206
+ case LM_GGML_OP_MUL:
2207
+ case LM_GGML_OP_DIV:
2208
+ case LM_GGML_OP_NORM:
2209
+ case LM_GGML_OP_RMS_NORM:
2210
+ case LM_GGML_OP_RMS_NORM_BACK:
2211
+ case LM_GGML_OP_L2_NORM:
2212
+ case LM_GGML_OP_GROUP_NORM:
2213
+ case LM_GGML_OP_CONCAT:
2214
+ case LM_GGML_OP_MUL_MAT:
2215
+ case LM_GGML_OP_MUL_MAT_ID:
2216
+ case LM_GGML_OP_OUT_PROD:
2217
+ {
2218
+ n_tasks = n_threads;
2219
+ } break;
2220
+ case LM_GGML_OP_GET_ROWS:
2221
+ case LM_GGML_OP_SET_ROWS:
2222
+ {
2223
+ // FIXME: get_rows can use additional threads, but the cost of launching additional threads
2224
+ // decreases performance with GPU offloading
2225
+ //n_tasks = n_threads;
2226
+ n_tasks = 1;
2227
+ } break;
2228
+ case LM_GGML_OP_SCALE:
2229
+ case LM_GGML_OP_SET:
2230
+ case LM_GGML_OP_RESHAPE:
2231
+ case LM_GGML_OP_VIEW:
2232
+ case LM_GGML_OP_PERMUTE:
2233
+ case LM_GGML_OP_TRANSPOSE:
2234
+ case LM_GGML_OP_GET_ROWS_BACK:
2235
+ case LM_GGML_OP_DIAG:
2236
+ {
2237
+ n_tasks = 1;
2238
+ } break;
2239
+ case LM_GGML_OP_DIAG_MASK_ZERO:
2240
+ case LM_GGML_OP_DIAG_MASK_INF:
2241
+ case LM_GGML_OP_SOFT_MAX_BACK:
2242
+ case LM_GGML_OP_ROPE:
2243
+ case LM_GGML_OP_ROPE_BACK:
2244
+ case LM_GGML_OP_ADD_REL_POS:
2245
+ {
2246
+ n_tasks = n_threads;
2247
+ } break;
2248
+ case LM_GGML_OP_CLAMP:
2249
+ {
2250
+ n_tasks = 1; //TODO
2251
+ } break;
2252
+ case LM_GGML_OP_SOFT_MAX:
2253
+ {
2254
+ n_tasks = MIN(n_threads, lm_ggml_nrows(node->src[0]));
2255
+ } break;
2256
+ case LM_GGML_OP_IM2COL:
2257
+ case LM_GGML_OP_IM2COL_BACK:
2258
+ case LM_GGML_OP_CONV_2D:
2259
+ case LM_GGML_OP_CONV_3D:
2260
+ case LM_GGML_OP_CONV_2D_DW:
2261
+ case LM_GGML_OP_CONV_TRANSPOSE_1D:
2262
+ case LM_GGML_OP_CONV_TRANSPOSE_2D:
2263
+ {
2264
+ n_tasks = n_threads;
2265
+ } break;
2266
+ case LM_GGML_OP_POOL_1D:
2267
+ case LM_GGML_OP_POOL_2D:
2268
+ case LM_GGML_OP_POOL_2D_BACK:
2269
+ {
2270
+ n_tasks = 1;
2271
+ } break;
2272
+ case LM_GGML_OP_UPSCALE:
2273
+ case LM_GGML_OP_PAD:
2274
+ case LM_GGML_OP_PAD_REFLECT_1D:
2275
+ case LM_GGML_OP_ROLL:
2276
+ case LM_GGML_OP_ARANGE:
2277
+ case LM_GGML_OP_TIMESTEP_EMBEDDING:
2278
+ case LM_GGML_OP_ARGSORT:
2279
+ case LM_GGML_OP_FLASH_ATTN_EXT:
2280
+ case LM_GGML_OP_FLASH_ATTN_BACK:
2281
+ case LM_GGML_OP_SSM_CONV:
2282
+ case LM_GGML_OP_SSM_SCAN:
2283
+ case LM_GGML_OP_RWKV_WKV6:
2284
+ case LM_GGML_OP_GATED_LINEAR_ATTN:
2285
+ case LM_GGML_OP_RWKV_WKV7:
2286
+ {
2287
+ n_tasks = n_threads;
2288
+ } break;
2289
+ case LM_GGML_OP_WIN_PART:
2290
+ case LM_GGML_OP_WIN_UNPART:
2291
+ case LM_GGML_OP_GET_REL_POS:
2292
+ {
2293
+ n_tasks = 1;
2294
+ } break;
2295
+ case LM_GGML_OP_MAP_CUSTOM1:
2296
+ {
2297
+ struct lm_ggml_map_custom1_op_params p;
2298
+ memcpy(&p, node->op_params, sizeof(p));
2299
+ if (p.n_tasks == LM_GGML_N_TASKS_MAX) {
2300
+ n_tasks = n_threads;
2301
+ } else {
2302
+ n_tasks = MIN(p.n_tasks, n_threads);
2303
+ }
2304
+ } break;
2305
+ case LM_GGML_OP_MAP_CUSTOM2:
2306
+ {
2307
+ struct lm_ggml_map_custom2_op_params p;
2308
+ memcpy(&p, node->op_params, sizeof(p));
2309
+ if (p.n_tasks == LM_GGML_N_TASKS_MAX) {
2310
+ n_tasks = n_threads;
2311
+ } else {
2312
+ n_tasks = MIN(p.n_tasks, n_threads);
2313
+ }
2314
+ } break;
2315
+ case LM_GGML_OP_MAP_CUSTOM3:
2316
+ {
2317
+ struct lm_ggml_map_custom3_op_params p;
2318
+ memcpy(&p, node->op_params, sizeof(p));
2319
+ if (p.n_tasks == LM_GGML_N_TASKS_MAX) {
2320
+ n_tasks = n_threads;
2321
+ } else {
2322
+ n_tasks = MIN(p.n_tasks, n_threads);
2323
+ }
2324
+ } break;
2325
+ case LM_GGML_OP_CUSTOM:
2326
+ {
2327
+ struct lm_ggml_custom_op_params p;
2328
+ memcpy(&p, node->op_params, sizeof(p));
2329
+ if (p.n_tasks == LM_GGML_N_TASKS_MAX) {
2330
+ n_tasks = n_threads;
2331
+ } else {
2332
+ n_tasks = MIN(p.n_tasks, n_threads);
2333
+ }
2334
+ } break;
2335
+ case LM_GGML_OP_CROSS_ENTROPY_LOSS:
2336
+ case LM_GGML_OP_CROSS_ENTROPY_LOSS_BACK:
2337
+ case LM_GGML_OP_OPT_STEP_ADAMW:
2338
+ case LM_GGML_OP_OPT_STEP_SGD:
2339
+ {
2340
+ n_tasks = n_threads;
2341
+ } break;
2342
+ case LM_GGML_OP_NONE:
2343
+ {
2344
+ n_tasks = 1;
2345
+ } break;
2346
+ case LM_GGML_OP_COUNT:
2347
+ {
2348
+ LM_GGML_ABORT("fatal error");
2349
+ }
2350
+ default:
2351
+ {
2352
+ fprintf(stderr, "%s: op not implemented: ", __func__);
2353
+ if (node->op < LM_GGML_OP_COUNT) {
2354
+ fprintf(stderr, "%s\n", lm_ggml_op_name(node->op));
2355
+ } else {
2356
+ fprintf(stderr, "%d\n", node->op);
2357
+ }
2358
+ LM_GGML_ABORT("fatal error");
2359
+ }
2360
+ }
2361
+
2362
+ assert(n_tasks > 0);
2363
+
2364
+ return n_tasks;
2365
+ }
2366
+
2367
+ static thread_ret_t lm_ggml_graph_compute_secondary_thread(void* data);
2368
+
2369
+ #if defined(_WIN32)
2370
+ #include "windows.h"
2371
+
2372
+ // TODO: support > 64 CPUs
2373
+ static bool lm_ggml_thread_apply_affinity(bool * mask) {
2374
+ HANDLE h = GetCurrentThread();
2375
+ uint64_t bitmask = 0ULL;
2376
+
2377
+ assert(LM_GGML_MAX_N_THREADS >= 64);
2378
+
2379
+ for (int32_t i = 0; i < 8; i++) {
2380
+ int32_t idx = i * 8;
2381
+ uint8_t val = 0;
2382
+ val |= mask[idx + 0] << 0;
2383
+ val |= mask[idx + 1] << 1;
2384
+ val |= mask[idx + 2] << 2;
2385
+ val |= mask[idx + 3] << 3;
2386
+ val |= mask[idx + 4] << 4;
2387
+ val |= mask[idx + 5] << 5;
2388
+ val |= mask[idx + 6] << 6;
2389
+ val |= mask[idx + 7] << 7;
2390
+ bitmask |= (uint64_t)val << idx;
2391
+ }
2392
+
2393
+ for (int32_t i = 64; i < LM_GGML_MAX_N_THREADS; i++) {
2394
+ if (mask[i]) {
2395
+ fprintf(stderr, "warn: setting thread-affinity for > 64 CPUs isn't supported on windows!\n");
2396
+ break;
2397
+ }
2398
+ }
2399
+
2400
+ DWORD_PTR m = (DWORD_PTR)bitmask;
2401
+
2402
+ m = SetThreadAffinityMask(h, m);
2403
+
2404
+ return m != 0;
2405
+ }
2406
+
2407
+ static bool lm_ggml_thread_apply_priority(int32_t prio) {
2408
+ // Note that on Windows the Process Priority Class must be updated in order to set Thread priority.
2409
+ // This is up to the applications.
2410
+ DWORD p = THREAD_PRIORITY_NORMAL;
2411
+ switch (prio) {
2412
+ case LM_GGML_SCHED_PRIO_LOW: p = THREAD_PRIORITY_BELOW_NORMAL; break;
2413
+ case LM_GGML_SCHED_PRIO_NORMAL: p = THREAD_PRIORITY_NORMAL; break;
2414
+ case LM_GGML_SCHED_PRIO_MEDIUM: p = THREAD_PRIORITY_ABOVE_NORMAL; break;
2415
+ case LM_GGML_SCHED_PRIO_HIGH: p = THREAD_PRIORITY_HIGHEST; break;
2416
+ case LM_GGML_SCHED_PRIO_REALTIME: p = THREAD_PRIORITY_TIME_CRITICAL; break;
2417
+ }
2418
+
2419
+ if (prio != LM_GGML_SCHED_PRIO_LOW) {
2420
+ // Tell Windows that this thread should not be throttled (needs its own CPU core).
2421
+ // Newer Windows 11 versions aggresively park (offline) CPU cores and often place
2422
+ // all our threads onto the first 4 cores which results in terrible performance with
2423
+ // n_threads > 4
2424
+ #if _WIN32_WINNT >= 0x0602
2425
+ THREAD_POWER_THROTTLING_STATE t;
2426
+ ZeroMemory(&t, sizeof(t));
2427
+ t.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
2428
+ t.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
2429
+ t.StateMask = 0;
2430
+
2431
+ if (!SetThreadInformation(GetCurrentThread(), ThreadPowerThrottling, &t, sizeof(t))) {
2432
+ LM_GGML_LOG_DEBUG("failed to disable thread power throttling %d : (%d)\n", prio, (int) GetLastError());
2433
+ return false;
2434
+ }
2435
+ #endif
2436
+ }
2437
+
2438
+ if (prio == LM_GGML_SCHED_PRIO_NORMAL) {
2439
+ // Keep inherited policy/priority
2440
+ return true;
2441
+ }
2442
+
2443
+ if (!SetThreadPriority(GetCurrentThread(), p)) {
2444
+ fprintf(stderr, "warn: failed to set thread priority %d : (%d)\n", prio, (int) GetLastError());
2445
+ return false;
2446
+ }
2447
+
2448
+ return true;
2449
+ }
2450
+
2451
+ #elif defined(__APPLE__)
2452
+ #include <sys/types.h>
2453
+ #include <sys/resource.h>
2454
+
2455
+ static bool lm_ggml_thread_apply_affinity(const bool * mask) {
2456
+ // Not supported on Apple platforms
2457
+ UNUSED(mask);
2458
+ return true;
2459
+ }
2460
+
2461
+ static bool lm_ggml_thread_apply_priority(int32_t prio) {
2462
+ struct sched_param p;
2463
+ int32_t policy = SCHED_OTHER;
2464
+ switch (prio) {
2465
+ // TODO: there seems to be no way to set lower prio on Apple platforms
2466
+ case LM_GGML_SCHED_PRIO_LOW: policy = SCHED_OTHER; p.sched_priority = 0; break;
2467
+ case LM_GGML_SCHED_PRIO_NORMAL: policy = SCHED_OTHER; p.sched_priority = 0; break;
2468
+ case LM_GGML_SCHED_PRIO_MEDIUM: policy = SCHED_FIFO; p.sched_priority = 40; break;
2469
+ case LM_GGML_SCHED_PRIO_HIGH: policy = SCHED_FIFO; p.sched_priority = 80; break;
2470
+ case LM_GGML_SCHED_PRIO_REALTIME: policy = SCHED_FIFO; p.sched_priority = 90; break;
2471
+ }
2472
+
2473
+ if (prio == LM_GGML_SCHED_PRIO_NORMAL) {
2474
+ // Keep inherited policy/priority
2475
+ return true;
2476
+ }
2477
+
2478
+ int32_t err = pthread_setschedparam(pthread_self(), policy, &p);
2479
+ if (err != 0) {
2480
+ fprintf(stderr, "warn: failed to set thread priority %d : %s (%d)\n", prio, strerror(err), err);
2481
+ return false;
2482
+ }
2483
+
2484
+ return true;
2485
+ }
2486
+
2487
+ #elif defined(__gnu_linux__)
2488
+ // TODO: this may not work on BSD, to be verified
2489
+
2490
+ static bool lm_ggml_thread_apply_affinity(const bool * mask) {
2491
+ cpu_set_t cpuset;
2492
+ int err;
2493
+
2494
+ CPU_ZERO(&cpuset);
2495
+
2496
+ for (uint32_t i = 0; i < LM_GGML_MAX_N_THREADS; i++) {
2497
+ if (mask[i]) {
2498
+ LM_GGML_PRINT_DEBUG("Thread %lx: adding %d to cpuset\n", pthread_self(), i);
2499
+ CPU_SET(i, &cpuset);
2500
+ }
2501
+ }
2502
+
2503
+ #ifdef __ANDROID__
2504
+ err = sched_setaffinity(0, sizeof(cpuset), &cpuset);
2505
+ if (err < 0) {
2506
+ err = errno;
2507
+ }
2508
+ #else
2509
+ err = pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
2510
+ #endif
2511
+ if (err != 0) {
2512
+ fprintf(stderr, "warn: failed to set affinity mask 0x%llx : %s (%d)\n", (unsigned long long)mask, strerror(err), err);
2513
+ return false;
2514
+ }
2515
+
2516
+ return true;
2517
+ }
2518
+
2519
+ static bool lm_ggml_thread_apply_priority(int32_t prio) {
2520
+ struct sched_param p;
2521
+ int32_t policy = SCHED_OTHER;
2522
+ switch (prio) {
2523
+ case LM_GGML_SCHED_PRIO_LOW: policy = SCHED_BATCH; p.sched_priority = 0; break;
2524
+ case LM_GGML_SCHED_PRIO_NORMAL: policy = SCHED_OTHER; p.sched_priority = 0; break;
2525
+ case LM_GGML_SCHED_PRIO_MEDIUM: policy = SCHED_FIFO; p.sched_priority = 40; break;
2526
+ case LM_GGML_SCHED_PRIO_HIGH: policy = SCHED_FIFO; p.sched_priority = 80; break;
2527
+ case LM_GGML_SCHED_PRIO_REALTIME: policy = SCHED_FIFO; p.sched_priority = 90; break;
2528
+ }
2529
+
2530
+ if (prio == LM_GGML_SCHED_PRIO_NORMAL) {
2531
+ // Keep inherited policy/priority
2532
+ return true;
2533
+ }
2534
+
2535
+ int32_t err = pthread_setschedparam(pthread_self(), policy, &p);
2536
+ if (err != 0) {
2537
+ fprintf(stderr, "warn: failed to set thread priority %d : %s (%d)\n", prio, strerror(err), err);
2538
+ return false;
2539
+ }
2540
+
2541
+ return true;
2542
+ }
2543
+
2544
+ #else // unsupported platforms
2545
+
2546
+ static bool lm_ggml_thread_apply_affinity(const bool * mask) {
2547
+ UNUSED(mask);
2548
+ return true;
2549
+ }
2550
+
2551
+ static bool lm_ggml_thread_apply_priority(int32_t prio) {
2552
+ UNUSED(prio);
2553
+ return true;
2554
+ }
2555
+
2556
+ #endif
2557
+
2558
+ static bool lm_ggml_thread_cpumask_is_valid(const bool * mask) {
2559
+ for (int i = 0; i < LM_GGML_MAX_N_THREADS; i++) {
2560
+ if (mask[i]) { return true; }
2561
+ }
2562
+ return false;
2563
+ }
2564
+
2565
+ static void lm_ggml_thread_cpumask_next(const bool * global_mask, bool * local_mask, bool strict, int32_t* iter) {
2566
+ if (!strict) {
2567
+ memcpy(local_mask, global_mask, LM_GGML_MAX_N_THREADS);
2568
+ return;
2569
+ } else {
2570
+ memset(local_mask, 0, LM_GGML_MAX_N_THREADS);
2571
+ int32_t base_idx = *iter;
2572
+ for (int32_t i = 0; i < LM_GGML_MAX_N_THREADS; i++) {
2573
+ int32_t idx = base_idx + i;
2574
+ if (idx >= LM_GGML_MAX_N_THREADS) {
2575
+ // Just a cheaper modulo
2576
+ idx -= LM_GGML_MAX_N_THREADS;
2577
+ }
2578
+ if (global_mask[idx]) {
2579
+ local_mask[idx] = 1;
2580
+ *iter = idx + 1;
2581
+ return;
2582
+ }
2583
+ }
2584
+ }
2585
+ }
2586
+
2587
+ void lm_ggml_threadpool_free(struct lm_ggml_threadpool* threadpool) {
2588
+ if (!threadpool) return;
2589
+
2590
+ const int n_threads = threadpool->n_threads_max;
2591
+
2592
+ #ifndef LM_GGML_USE_OPENMP
2593
+ struct lm_ggml_compute_state* workers = threadpool->workers;
2594
+
2595
+ lm_ggml_mutex_lock(&threadpool->mutex);
2596
+
2597
+ threadpool->stop = true;
2598
+ threadpool->pause = false;
2599
+
2600
+ lm_ggml_cond_broadcast(&threadpool->cond);
2601
+ lm_ggml_mutex_unlock(&threadpool->mutex);
2602
+
2603
+ for (int j = 1; j < n_threads; j++) {
2604
+ int32_t rc = lm_ggml_thread_join(workers[j].thrd, NULL);
2605
+ LM_GGML_ASSERT(rc == LM_GGML_EXIT_SUCCESS || rc == LM_GGML_EXIT_ABORTED);
2606
+ UNUSED(rc);
2607
+ }
2608
+
2609
+ lm_ggml_mutex_destroy(&threadpool->mutex);
2610
+ lm_ggml_cond_destroy(&threadpool->cond);
2611
+ #endif // LM_GGML_USE_OPENMP
2612
+
2613
+ const size_t workers_size = sizeof(struct lm_ggml_compute_state) * n_threads;
2614
+ lm_ggml_aligned_free(threadpool->workers, workers_size);
2615
+ lm_ggml_aligned_free(threadpool, sizeof(struct lm_ggml_threadpool));
2616
+ }
2617
+
2618
+ #ifndef LM_GGML_USE_OPENMP
2619
+ // pause/resume must be called under mutex
2620
+ static void lm_ggml_threadpool_pause_locked(struct lm_ggml_threadpool * threadpool) {
2621
+ LM_GGML_PRINT_DEBUG("Pausing threadpool\n");
2622
+ threadpool->pause = true;
2623
+ lm_ggml_cond_broadcast(&threadpool->cond);
2624
+ }
2625
+
2626
+ static void lm_ggml_threadpool_resume_locked(struct lm_ggml_threadpool * threadpool) {
2627
+ LM_GGML_PRINT_DEBUG("Resuming threadpool\n");
2628
+ threadpool->pause = false;
2629
+ lm_ggml_cond_broadcast(&threadpool->cond);
2630
+ }
2631
+ #endif
2632
+
2633
+ void lm_ggml_threadpool_pause(struct lm_ggml_threadpool * threadpool) {
2634
+ #ifndef LM_GGML_USE_OPENMP
2635
+ lm_ggml_mutex_lock(&threadpool->mutex);
2636
+ if (!threadpool->pause) {
2637
+ lm_ggml_threadpool_pause_locked(threadpool);
2638
+ }
2639
+ lm_ggml_mutex_unlock(&threadpool->mutex);
2640
+ #else
2641
+ UNUSED(threadpool);
2642
+ #endif
2643
+ }
2644
+
2645
+ void lm_ggml_threadpool_resume(struct lm_ggml_threadpool * threadpool) {
2646
+ #ifndef LM_GGML_USE_OPENMP
2647
+ lm_ggml_mutex_lock(&threadpool->mutex);
2648
+ if (threadpool->pause) {
2649
+ lm_ggml_threadpool_resume_locked(threadpool);
2650
+ }
2651
+ lm_ggml_mutex_unlock(&threadpool->mutex);
2652
+ #else
2653
+ UNUSED(threadpool);
2654
+ #endif
2655
+ }
2656
+
2657
+ struct lm_ggml_cplan lm_ggml_graph_plan(
2658
+ const struct lm_ggml_cgraph * cgraph,
2659
+ int n_threads,
2660
+ struct lm_ggml_threadpool * threadpool) {
2661
+
2662
+ if (threadpool == NULL) {
2663
+ //LM_GGML_PRINT_DEBUG("Threadpool is not specified. Will create a disposable threadpool : n_threads %d\n", n_threads);
2664
+ }
2665
+ if (n_threads <= 0) {
2666
+ n_threads = threadpool ? threadpool->n_threads_max : LM_GGML_DEFAULT_N_THREADS;
2667
+ }
2668
+
2669
+ size_t work_size = 0;
2670
+
2671
+ struct lm_ggml_cplan cplan;
2672
+ memset(&cplan, 0, sizeof(struct lm_ggml_cplan));
2673
+
2674
+ int max_tasks = 1;
2675
+
2676
+ // thread scheduling for the different operations + work buffer size estimation
2677
+ for (int i = 0; i < cgraph->n_nodes; i++) {
2678
+ struct lm_ggml_tensor * node = cgraph->nodes[i];
2679
+
2680
+ const int n_tasks = lm_ggml_get_n_tasks(node, n_threads);
2681
+
2682
+ max_tasks = MAX(max_tasks, n_tasks);
2683
+
2684
+ size_t cur = 0;
2685
+
2686
+ if (!lm_ggml_cpu_extra_work_size(n_threads, node, &cur)) {
2687
+ switch (node->op) {
2688
+ case LM_GGML_OP_CPY:
2689
+ case LM_GGML_OP_DUP:
2690
+ {
2691
+ if (lm_ggml_is_quantized(node->type) ||
2692
+ // F16 -> BF16 and BF16 -> F16 copies go through intermediate F32
2693
+ (node->src[0]->type == LM_GGML_TYPE_F16 && node->src[1] && node->src[1]->type == LM_GGML_TYPE_BF16) ||
2694
+ (node->src[0]->type == LM_GGML_TYPE_BF16 && node->src[1] && node->src[1]->type == LM_GGML_TYPE_F16)) {
2695
+ cur = lm_ggml_type_size(LM_GGML_TYPE_F32) * node->ne[0] * n_tasks;
2696
+ }
2697
+ } break;
2698
+ case LM_GGML_OP_ADD:
2699
+ case LM_GGML_OP_ADD_ID:
2700
+ case LM_GGML_OP_ADD1:
2701
+ {
2702
+ if (lm_ggml_is_quantized(node->src[0]->type)) {
2703
+ cur = lm_ggml_type_size(LM_GGML_TYPE_F32) * node->src[0]->ne[0] * n_tasks;
2704
+ }
2705
+ } break;
2706
+ case LM_GGML_OP_ACC:
2707
+ {
2708
+ if (lm_ggml_is_quantized(node->src[0]->type)) {
2709
+ cur = lm_ggml_type_size(LM_GGML_TYPE_F32) * node->src[1]->ne[0] * n_tasks;
2710
+ }
2711
+ } break;
2712
+ case LM_GGML_OP_COUNT_EQUAL:
2713
+ {
2714
+ cur = lm_ggml_type_size(node->type)*n_tasks;
2715
+ } break;
2716
+ case LM_GGML_OP_MUL_MAT:
2717
+ {
2718
+ const enum lm_ggml_type vec_dot_type = type_traits_cpu[node->src[0]->type].vec_dot_type;
2719
+
2720
+ if (node->src[1]->type != vec_dot_type) {
2721
+ cur = lm_ggml_row_size(vec_dot_type, lm_ggml_nelements(node->src[1]));
2722
+ }
2723
+ } break;
2724
+ case LM_GGML_OP_MUL_MAT_ID:
2725
+ {
2726
+ cur = 0;
2727
+ const struct lm_ggml_tensor * src0 = node->src[0];
2728
+ const struct lm_ggml_tensor * src1 = node->src[1];
2729
+ const struct lm_ggml_tensor * ids = node->src[2];
2730
+ const enum lm_ggml_type vec_dot_type = type_traits_cpu[src0->type].vec_dot_type;
2731
+ const int n_as = src0->ne[2];
2732
+ // src1
2733
+ if (src1->type != vec_dot_type) {
2734
+ cur += lm_ggml_row_size(vec_dot_type, lm_ggml_nelements(src1)) + sizeof(int64_t);
2735
+ }
2736
+ // matrix_row_counts
2737
+ cur += n_as * sizeof(int64_t) + sizeof(int64_t);
2738
+ // matrix_rows
2739
+ cur += n_as*ids->ne[0]*ids->ne[1]*sizeof(struct mmid_row_mapping) + sizeof(int64_t);
2740
+ // atomic_current_chunk
2741
+ cur += CACHE_LINE_SIZE*n_as + CACHE_LINE_SIZE;
2742
+ } break;
2743
+ case LM_GGML_OP_OUT_PROD:
2744
+ {
2745
+ if (lm_ggml_is_quantized(node->src[0]->type)) {
2746
+ cur = lm_ggml_type_size(LM_GGML_TYPE_F32) * node->src[0]->ne[0] * n_tasks;
2747
+ }
2748
+ } break;
2749
+ case LM_GGML_OP_SOFT_MAX:
2750
+ case LM_GGML_OP_ROPE:
2751
+ case LM_GGML_OP_ROPE_BACK:
2752
+ {
2753
+ cur = lm_ggml_type_size(LM_GGML_TYPE_F32) * node->ne[0] * n_tasks;
2754
+ } break;
2755
+ case LM_GGML_OP_CONV_TRANSPOSE_1D:
2756
+ {
2757
+ LM_GGML_ASSERT(node->src[0]->ne[3] == 1);
2758
+ LM_GGML_ASSERT(node->src[1]->ne[2] == 1);
2759
+ LM_GGML_ASSERT(node->src[1]->ne[3] == 1);
2760
+
2761
+ const int64_t ne00 = node->src[0]->ne[0]; // K
2762
+ const int64_t ne01 = node->src[0]->ne[1]; // Cout
2763
+ const int64_t ne02 = node->src[0]->ne[2]; // Cin
2764
+ const int64_t ne10 = node->src[1]->ne[0]; // L
2765
+ const int64_t ne11 = node->src[1]->ne[1]; // Cin
2766
+
2767
+ if ((node->src[0]->type == LM_GGML_TYPE_F16 ||
2768
+ node->src[0]->type == LM_GGML_TYPE_BF16) &&
2769
+ node->src[1]->type == LM_GGML_TYPE_F32) {
2770
+ cur += sizeof(lm_ggml_fp16_t)*ne00*ne01*ne02;
2771
+ cur += sizeof(lm_ggml_fp16_t)*ne10*ne11;
2772
+ } else if (node->src[0]->type == LM_GGML_TYPE_F32 &&
2773
+ node->src[1]->type == LM_GGML_TYPE_F32) {
2774
+ cur += sizeof(float)*ne00*ne01*ne02;
2775
+ cur += sizeof(float)*ne10*ne11;
2776
+ } else {
2777
+ LM_GGML_ABORT("fatal error");
2778
+ }
2779
+ } break;
2780
+ case LM_GGML_OP_CONV_2D:
2781
+ case LM_GGML_OP_CONV_3D:
2782
+ {
2783
+ cur = LM_GGML_IM2COL_WORK_SIZE;
2784
+ } break;
2785
+ case LM_GGML_OP_CONV_TRANSPOSE_2D:
2786
+ {
2787
+ const int64_t ne00 = node->src[0]->ne[0]; // W
2788
+ const int64_t ne01 = node->src[0]->ne[1]; // H
2789
+ const int64_t ne02 = node->src[0]->ne[2]; // Channels Out
2790
+ const int64_t ne03 = node->src[0]->ne[3]; // Channels In
2791
+
2792
+ const int64_t ne10 = node->src[1]->ne[0]; // W
2793
+ const int64_t ne11 = node->src[1]->ne[1]; // H
2794
+ const int64_t ne12 = node->src[1]->ne[2]; // Channels In
2795
+
2796
+ cur += sizeof(lm_ggml_fp16_t)*ne00*ne01*ne02*ne03;
2797
+ cur += sizeof(lm_ggml_fp16_t)*ne10*ne11*ne12;
2798
+ } break;
2799
+ case LM_GGML_OP_FLASH_ATTN_EXT:
2800
+ {
2801
+ const int64_t ne10 = node->src[1]->ne[0]; // DK
2802
+ const int64_t ne20 = node->src[2]->ne[0]; // DV
2803
+
2804
+ cur = sizeof(float)*(1*ne10 + 2*ne20)*n_tasks; // 1x head size K + 2x head size V (per thread)
2805
+ } break;
2806
+ case LM_GGML_OP_FLASH_ATTN_BACK:
2807
+ {
2808
+ const int64_t D = node->src[0]->ne[0];
2809
+ const int64_t ne11 = lm_ggml_up(node->src[1]->ne[1], LM_GGML_SOFT_MAX_UNROLL);
2810
+ const int64_t mxDn = MAX(D, ne11) * 2; // *2 because of S and SM in lm_ggml_compute_forward_flash_attn_back
2811
+ if (node->src[1]->type == LM_GGML_TYPE_F32) {
2812
+ cur = sizeof(float)*mxDn*n_tasks; // TODO: this can become (n_tasks-1)
2813
+ cur += sizeof(float)*mxDn*n_tasks; // this is overestimated by x2
2814
+ } else if (node->src[1]->type == LM_GGML_TYPE_F16) {
2815
+ cur = sizeof(float)*mxDn*n_tasks; // TODO: this can become (n_tasks-1)
2816
+ cur += sizeof(float)*mxDn*n_tasks; // this is overestimated by x2
2817
+ } else if (node->src[1]->type == LM_GGML_TYPE_BF16) {
2818
+ cur = sizeof(float)*mxDn*n_tasks; // TODO: this can become (n_tasks-1)
2819
+ cur += sizeof(float)*mxDn*n_tasks; // this is overestimated by x2
2820
+ }
2821
+ } break;
2822
+
2823
+ case LM_GGML_OP_CROSS_ENTROPY_LOSS:
2824
+ {
2825
+ cur = lm_ggml_type_size(node->type)*(n_tasks + node->src[0]->ne[0]*n_tasks);
2826
+ } break;
2827
+ case LM_GGML_OP_COUNT:
2828
+ {
2829
+ LM_GGML_ABORT("fatal error");
2830
+ }
2831
+ default:
2832
+ break;
2833
+ }
2834
+ }
2835
+
2836
+ work_size = MAX(work_size, cur);
2837
+ }
2838
+
2839
+ if (work_size > 0) {
2840
+ work_size += CACHE_LINE_SIZE*(n_threads);
2841
+ }
2842
+
2843
+ cplan.threadpool = threadpool;
2844
+ cplan.n_threads = MIN(max_tasks, n_threads);
2845
+ cplan.work_size = work_size;
2846
+ cplan.work_data = NULL;
2847
+
2848
+ return cplan;
2849
+ }
2850
+
2851
+ static thread_ret_t lm_ggml_graph_compute_thread(void * data) {
2852
+ struct lm_ggml_compute_state * state = (struct lm_ggml_compute_state *) data;
2853
+ struct lm_ggml_threadpool * tp = state->threadpool;
2854
+
2855
+ const struct lm_ggml_cgraph * cgraph = tp->cgraph;
2856
+ const struct lm_ggml_cplan * cplan = tp->cplan;
2857
+
2858
+ set_numa_thread_affinity(state->ith);
2859
+
2860
+ struct lm_ggml_compute_params params = {
2861
+ /*.ith =*/ state->ith,
2862
+ /*.nth =*/ atomic_load_explicit(&tp->n_threads_cur, memory_order_relaxed),
2863
+ /*.wsize =*/ cplan->work_size,
2864
+ /*.wdata =*/ cplan->work_data,
2865
+ /*.threadpool=*/ tp,
2866
+ };
2867
+
2868
+ for (int node_n = 0; node_n < cgraph->n_nodes && atomic_load_explicit(&tp->abort, memory_order_relaxed) != node_n; node_n++) {
2869
+ struct lm_ggml_tensor * node = cgraph->nodes[node_n];
2870
+
2871
+ lm_ggml_compute_forward(&params, node);
2872
+
2873
+ if (state->ith == 0 && cplan->abort_callback &&
2874
+ cplan->abort_callback(cplan->abort_callback_data)) {
2875
+ atomic_store_explicit(&tp->abort, node_n + 1, memory_order_relaxed);
2876
+ tp->ec = LM_GGML_STATUS_ABORTED;
2877
+ }
2878
+
2879
+ if (node_n + 1 < cgraph->n_nodes) {
2880
+ lm_ggml_barrier(state->threadpool);
2881
+ }
2882
+ }
2883
+
2884
+ lm_ggml_barrier(state->threadpool);
2885
+
2886
+ return 0;
2887
+ }
2888
+
2889
+ #ifndef LM_GGML_USE_OPENMP
2890
+
2891
+ // check if thread is active
2892
+ static inline bool lm_ggml_graph_compute_thread_active(struct lm_ggml_compute_state * state) {
2893
+ struct lm_ggml_threadpool * threadpool = state->threadpool;
2894
+ int n_threads = atomic_load_explicit(&threadpool->n_threads_cur, memory_order_relaxed);
2895
+ return (state->ith < n_threads);
2896
+ }
2897
+
2898
+ // check if thread is ready to proceed (exit from polling or sleeping)
2899
+ static inline bool lm_ggml_graph_compute_thread_ready(struct lm_ggml_compute_state * state) {
2900
+ struct lm_ggml_threadpool * threadpool = state->threadpool;
2901
+
2902
+ if (state->pending || threadpool->stop || threadpool->pause) { return true; }
2903
+
2904
+ // check for new graph/work
2905
+ int new_graph = atomic_load_explicit(&threadpool->n_graph, memory_order_relaxed);
2906
+ if (new_graph != state->last_graph) {
2907
+ state->pending = lm_ggml_graph_compute_thread_active(state);
2908
+ state->last_graph = new_graph;
2909
+ }
2910
+
2911
+ return state->pending;
2912
+ }
2913
+
2914
+ // sync thread state after polling
2915
+ static inline void lm_ggml_graph_compute_thread_sync(struct lm_ggml_compute_state * state) {
2916
+ // TSAN doesn't support standalone fence yet, we use a dummy read-modify-write instead
2917
+ #ifdef LM_GGML_TSAN_ENABLED
2918
+ atomic_fetch_add_explicit(&state->threadpool->n_graph, 0, memory_order_seq_cst);
2919
+ #else
2920
+ atomic_thread_fence(memory_order_seq_cst);
2921
+ #endif
2922
+ UNUSED(state);
2923
+ }
2924
+
2925
+ static inline bool lm_ggml_graph_compute_poll_for_work(struct lm_ggml_compute_state * state) {
2926
+ struct lm_ggml_threadpool * threadpool = state->threadpool;
2927
+
2928
+ // Skip polling for unused threads
2929
+ if (!lm_ggml_graph_compute_thread_active(state)) {
2930
+ return state->pending;
2931
+ }
2932
+
2933
+ // This seems to make 0 ... 100 a decent range for polling level across modern processors.
2934
+ // Perhaps, we can adjust it dynamically based on load and things.
2935
+ const uint64_t n_rounds = 1024UL * 128 * threadpool->poll;
2936
+
2937
+ for (uint64_t i=0; !lm_ggml_graph_compute_thread_ready(state) && i < n_rounds; i++) {
2938
+ // No new work. Keep polling.
2939
+ lm_ggml_thread_cpu_relax();
2940
+ }
2941
+
2942
+ return state->pending;
2943
+ }
2944
+
2945
+ static inline bool lm_ggml_graph_compute_check_for_work(struct lm_ggml_compute_state * state) {
2946
+ struct lm_ggml_threadpool * threadpool = state->threadpool;
2947
+
2948
+ if (lm_ggml_graph_compute_poll_for_work(state)) {
2949
+ lm_ggml_graph_compute_thread_sync(state);
2950
+ return state->pending;
2951
+ }
2952
+
2953
+ lm_ggml_mutex_lock_shared(&threadpool->mutex);
2954
+ while (!lm_ggml_graph_compute_thread_ready(state)) {
2955
+ // No new work. Wait for the signal.
2956
+ LM_GGML_PRINT_DEBUG("thread #%d waiting for work (sleeping)\n", state->ith);
2957
+ lm_ggml_cond_wait(&threadpool->cond, &threadpool->mutex);
2958
+ }
2959
+ lm_ggml_mutex_unlock_shared(&threadpool->mutex);
2960
+
2961
+ return state->pending;
2962
+ }
2963
+
2964
+ static thread_ret_t lm_ggml_graph_compute_secondary_thread(void* data) {
2965
+ struct lm_ggml_compute_state * state = (struct lm_ggml_compute_state *) data;
2966
+ struct lm_ggml_threadpool * threadpool = state->threadpool;
2967
+
2968
+ lm_ggml_thread_apply_priority(threadpool->prio);
2969
+ if (lm_ggml_thread_cpumask_is_valid(state->cpumask)) {
2970
+ lm_ggml_thread_apply_affinity(state->cpumask);
2971
+ }
2972
+
2973
+ while (true) {
2974
+ // Check if we need to sleep
2975
+ while (threadpool->pause) {
2976
+ LM_GGML_PRINT_DEBUG("thread #%d inside pause loop\n", state->ith);
2977
+ lm_ggml_mutex_lock_shared(&threadpool->mutex);
2978
+ if (threadpool->pause) {
2979
+ lm_ggml_cond_wait(&threadpool->cond, &threadpool->mutex);
2980
+ }
2981
+ LM_GGML_PRINT_DEBUG("thread #%d resuming after wait\n", state->ith);
2982
+ lm_ggml_mutex_unlock_shared(&threadpool->mutex);
2983
+ }
2984
+
2985
+ // This needs to be checked for after the cond_wait
2986
+ if (threadpool->stop) break;
2987
+
2988
+ // Check if there is new work
2989
+ // The main thread is the only one that can dispatch new work
2990
+
2991
+ lm_ggml_graph_compute_check_for_work(state);
2992
+ if (state->pending) {
2993
+ state->pending = false;
2994
+
2995
+ lm_ggml_graph_compute_thread(state);
2996
+ }
2997
+ }
2998
+
2999
+ return (thread_ret_t) 0;
3000
+ }
3001
+
3002
+ // Start processing new graph
3003
+ static void lm_ggml_graph_compute_kickoff(struct lm_ggml_threadpool * threadpool, int n_threads)
3004
+ {
3005
+ // Always take the mutex here because the worker threads are doing hybrid poll/wait
3006
+
3007
+ lm_ggml_mutex_lock(&threadpool->mutex);
3008
+
3009
+ LM_GGML_PRINT_DEBUG("threadpool: n_threads_cur %d n_threads %d\n", threadpool->n_threads_cur, n_threads);
3010
+
3011
+ // Update the number of active threads
3012
+ atomic_store_explicit(&threadpool->n_threads_cur, n_threads, memory_order_relaxed);
3013
+
3014
+ // Indicate the graph is ready to be processed
3015
+ // We need the full seq-cst fence here because of the polling threads (used in thread_sync)
3016
+ atomic_fetch_add_explicit(&threadpool->n_graph, 1, memory_order_seq_cst);
3017
+
3018
+ if (threadpool->pause) {
3019
+ // Update main thread prio and affinity to match the threadpool settings
3020
+ lm_ggml_thread_apply_priority(threadpool->prio);
3021
+ if (lm_ggml_thread_cpumask_is_valid(threadpool->workers[0].cpumask)) {
3022
+ lm_ggml_thread_apply_affinity(threadpool->workers[0].cpumask);
3023
+ }
3024
+
3025
+ // resume does cond broadcast
3026
+ lm_ggml_threadpool_resume_locked(threadpool);
3027
+ } else {
3028
+ lm_ggml_cond_broadcast(&threadpool->cond);
3029
+ }
3030
+
3031
+ lm_ggml_mutex_unlock(&threadpool->mutex);
3032
+ }
3033
+
3034
+ #endif // LM_GGML_USE_OPENMP
3035
+
3036
+ static struct lm_ggml_threadpool * lm_ggml_threadpool_new_impl(
3037
+ struct lm_ggml_threadpool_params * tpp,
3038
+ struct lm_ggml_cgraph * cgraph,
3039
+ struct lm_ggml_cplan * cplan) {
3040
+
3041
+ struct lm_ggml_threadpool * threadpool =
3042
+ lm_ggml_aligned_malloc(sizeof(struct lm_ggml_threadpool));
3043
+ {
3044
+ threadpool->cgraph = cgraph;
3045
+ threadpool->cplan = cplan;
3046
+ threadpool->n_graph = 0;
3047
+ threadpool->n_barrier = 0;
3048
+ threadpool->n_barrier_passed = 0;
3049
+ threadpool->current_chunk = 0;
3050
+ threadpool->stop = false;
3051
+ threadpool->pause = tpp->paused;
3052
+ threadpool->abort = -1;
3053
+ threadpool->workers = NULL;
3054
+ threadpool->n_threads_max = tpp->n_threads;
3055
+ threadpool->n_threads_cur = tpp->n_threads;
3056
+ threadpool->poll = tpp->poll;
3057
+ threadpool->prio = tpp->prio;
3058
+ threadpool->ec = LM_GGML_STATUS_SUCCESS;
3059
+ }
3060
+
3061
+ // Allocate and init workers state
3062
+ const size_t workers_size = sizeof(struct lm_ggml_compute_state) * tpp->n_threads;
3063
+ struct lm_ggml_compute_state * workers = lm_ggml_aligned_malloc(workers_size);
3064
+
3065
+ memset(workers, 0, workers_size);
3066
+ for (int j = 0; j < tpp->n_threads; j++) {
3067
+ workers[j].threadpool = threadpool;
3068
+ workers[j].ith = j;
3069
+ }
3070
+
3071
+ threadpool->workers = workers;
3072
+
3073
+ #ifndef LM_GGML_USE_OPENMP
3074
+ lm_ggml_mutex_init(&threadpool->mutex);
3075
+ lm_ggml_cond_init(&threadpool->cond);
3076
+
3077
+ // Spin the threads for all workers, and update CPU placements.
3078
+ // Place the main thread last (towards the higher numbered CPU cores).
3079
+
3080
+ int32_t cpumask_iter = 0;
3081
+
3082
+ for (int j = 1; j < tpp->n_threads; j++) {
3083
+ lm_ggml_thread_cpumask_next(tpp->cpumask, workers[j].cpumask, tpp->strict_cpu, &cpumask_iter);
3084
+
3085
+ int32_t rc = lm_ggml_thread_create(&workers[j].thrd, NULL, lm_ggml_graph_compute_secondary_thread, &workers[j]);
3086
+ LM_GGML_ASSERT(rc == 0);
3087
+ }
3088
+
3089
+ lm_ggml_thread_cpumask_next(tpp->cpumask, workers[0].cpumask, tpp->strict_cpu, &cpumask_iter);
3090
+
3091
+ if (!threadpool->pause) {
3092
+ // Update main thread prio and affinity at the start, otherwise we'll do it in resume
3093
+ lm_ggml_thread_apply_priority(threadpool->prio);
3094
+ if (lm_ggml_thread_cpumask_is_valid(threadpool->workers[0].cpumask)) {
3095
+ lm_ggml_thread_apply_affinity(threadpool->workers[0].cpumask);
3096
+ }
3097
+ }
3098
+ #endif // LM_GGML_USE_OPENMP
3099
+
3100
+ return threadpool;
3101
+ }
3102
+
3103
+ struct lm_ggml_threadpool * lm_ggml_threadpool_new(struct lm_ggml_threadpool_params * tpp) {
3104
+ return lm_ggml_threadpool_new_impl(tpp, NULL, NULL);
3105
+ }
3106
+
3107
+ enum lm_ggml_status lm_ggml_graph_compute(struct lm_ggml_cgraph * cgraph, struct lm_ggml_cplan * cplan) {
3108
+ lm_ggml_cpu_init();
3109
+
3110
+ LM_GGML_ASSERT(cplan);
3111
+ LM_GGML_ASSERT(cplan->n_threads > 0);
3112
+ LM_GGML_ASSERT(cplan->work_size == 0 || cplan->work_data != NULL);
3113
+
3114
+ int n_threads = cplan->n_threads;
3115
+ struct lm_ggml_threadpool * threadpool = cplan->threadpool;
3116
+
3117
+ bool disposable_threadpool = false;
3118
+
3119
+ if (threadpool == NULL) {
3120
+ //LM_GGML_PRINT_DEBUG("Threadpool is not specified. Will create a disposable threadpool : n_threads %d\n", n_threads);
3121
+ disposable_threadpool = true;
3122
+
3123
+ struct lm_ggml_threadpool_params ttp = lm_ggml_threadpool_params_default(n_threads);
3124
+ threadpool = lm_ggml_threadpool_new_impl(&ttp, cgraph, cplan);
3125
+ } else {
3126
+ // Reset some of the parameters that need resetting
3127
+ // No worker threads should be accessing the parameters below at this stage
3128
+ threadpool->cgraph = cgraph;
3129
+ threadpool->cplan = cplan;
3130
+ threadpool->current_chunk = 0;
3131
+ threadpool->abort = -1;
3132
+ threadpool->ec = LM_GGML_STATUS_SUCCESS;
3133
+ }
3134
+
3135
+ #ifdef LM_GGML_USE_OPENMP
3136
+ if (n_threads > 1) {
3137
+ #pragma omp parallel num_threads(n_threads)
3138
+ {
3139
+ #pragma omp single
3140
+ {
3141
+ // update the number of threads from the actual number of threads that we got from OpenMP
3142
+ n_threads = omp_get_num_threads();
3143
+ atomic_store_explicit(&threadpool->n_threads_cur, n_threads, memory_order_relaxed);
3144
+ }
3145
+
3146
+ lm_ggml_graph_compute_thread(&threadpool->workers[omp_get_thread_num()]);
3147
+ }
3148
+ } else {
3149
+ atomic_store_explicit(&threadpool->n_threads_cur, 1, memory_order_relaxed);
3150
+ lm_ggml_graph_compute_thread(&threadpool->workers[0]);
3151
+ }
3152
+ #else
3153
+ if (n_threads > threadpool->n_threads_max) {
3154
+ LM_GGML_LOG_WARN("cplan requested more threads (%d) than available (%d)\n", n_threads, threadpool->n_threads_max);
3155
+ n_threads = threadpool->n_threads_max;
3156
+ }
3157
+
3158
+ // Kick all threads to start the new graph
3159
+ lm_ggml_graph_compute_kickoff(threadpool, n_threads);
3160
+
3161
+ // This is a work thread too
3162
+ lm_ggml_graph_compute_thread(&threadpool->workers[0]);
3163
+ #endif
3164
+
3165
+ // don't leave affinity set on the main thread
3166
+ clear_numa_thread_affinity();
3167
+
3168
+ enum lm_ggml_status ret = threadpool->ec;
3169
+
3170
+ if (disposable_threadpool) {
3171
+ lm_ggml_threadpool_free(threadpool);
3172
+ }
3173
+
3174
+ return ret;
3175
+ }
3176
+
3177
+ enum lm_ggml_status lm_ggml_graph_compute_with_ctx(struct lm_ggml_context * ctx, struct lm_ggml_cgraph * cgraph, int n_threads) {
3178
+ struct lm_ggml_cplan cplan = lm_ggml_graph_plan(cgraph, n_threads, NULL);
3179
+
3180
+ cplan.work_data = (uint8_t *)lm_ggml_new_buffer(ctx, cplan.work_size);
3181
+
3182
+ return lm_ggml_graph_compute(cgraph, &cplan);
3183
+ }
3184
+
3185
+ void lm_ggml_cpu_fp32_to_fp32(const float * x, float * y, int64_t n) {
3186
+ memcpy(y, x, n * sizeof(float));
3187
+ }
3188
+
3189
+ void lm_ggml_cpu_fp32_to_fp16(const float * x, lm_ggml_fp16_t * y, int64_t n) {
3190
+ int64_t i = 0;
3191
+ #if defined(__F16C__)
3192
+ #if defined(__AVX512F__)
3193
+ for (; i + 15 < n; i += 16) {
3194
+ __m512 x_vec = _mm512_loadu_ps(x + i);
3195
+ __m256i y_vec = _mm512_cvtps_ph(x_vec, _MM_FROUND_TO_NEAREST_INT);
3196
+ _mm256_storeu_si256((__m256i *)(y + i), y_vec);
3197
+ }
3198
+ #endif
3199
+ for (; i + 7 < n; i += 8) {
3200
+ __m256 x_vec = _mm256_loadu_ps(x + i);
3201
+ __m128i y_vec = _mm256_cvtps_ph(x_vec, _MM_FROUND_TO_NEAREST_INT);
3202
+ _mm_storeu_si128((__m128i *)(y + i), y_vec);
3203
+ }
3204
+ for (; i + 3 < n; i += 4) {
3205
+ __m128 x_vec = _mm_loadu_ps(x + i);
3206
+ __m128i y_vec = _mm_cvtps_ph(x_vec, _MM_FROUND_TO_NEAREST_INT);
3207
+ _mm_storel_epi64((__m128i *)(y + i), y_vec);
3208
+ }
3209
+ #elif defined(__NNPA__)
3210
+ for (; i + 7 < n; i += 8) {
3211
+ float32x4_t v_xh = vec_xl(0, (const float *)(x + i + 0));
3212
+ float32x4_t v_xl = vec_xl(0, (const float *)(x + i + 4));
3213
+ uint16x8_t v_yd = vec_round_from_fp32(v_xh, v_xl, 0);
3214
+ uint16x8_t v_y = vec_convert_to_fp16(v_yd, 0);
3215
+ vec_xst(v_y, 0, (lm_ggml_fp16_t *)(y + i));
3216
+ }
3217
+ for (; i + 3 < n; i += 4) {
3218
+ float32x4_t v_x = vec_xl(0, (const float *)(x + i));
3219
+ float32x4_t v_zero = vec_splats(0.0f);
3220
+ uint16x8_t v_yd = vec_round_from_fp32(v_x, v_zero, 0);
3221
+ uint16x8_t v_y = vec_convert_to_fp16(v_yd, 0);
3222
+ vec_xst(v_y, 0, (lm_ggml_fp16_t *)(y + i));
3223
+ }
3224
+ #endif
3225
+ for (; i < n; ++i) {
3226
+ y[i] = LM_GGML_CPU_FP32_TO_FP16(x[i]);
3227
+ }
3228
+ }
3229
+
3230
+ void lm_ggml_cpu_fp16_to_fp32(const lm_ggml_fp16_t * x, float * y, int64_t n) {
3231
+ int64_t i = 0;
3232
+ #if defined(__F16C__)
3233
+ #if defined(__AVX512F__)
3234
+ for (; i + 15 < n; i += 16) {
3235
+ __m256i x_vec = _mm256_loadu_si256((const __m256i *)(x + i));
3236
+ __m512 y_vec = _mm512_cvtph_ps(x_vec);
3237
+ _mm512_storeu_ps(y + i, y_vec);
3238
+ }
3239
+ #endif
3240
+ for (; i + 7 < n; i += 8) {
3241
+ __m128i x_vec = _mm_loadu_si128((const __m128i *)(x + i));
3242
+ __m256 y_vec = _mm256_cvtph_ps(x_vec);
3243
+ _mm256_storeu_ps(y + i, y_vec);
3244
+ }
3245
+ for (; i + 3 < n; i += 4) {
3246
+ __m128i x_vec = _mm_loadl_epi64((const __m128i *)(x + i));
3247
+ __m128 y_vec = _mm_cvtph_ps(x_vec);
3248
+ _mm_storeu_ps(y + i, y_vec);
3249
+ }
3250
+ #elif defined(__NNPA__)
3251
+ for (; i + 7 < n; i += 8) {
3252
+ uint16x8_t v_x = vec_xl(0, (const lm_ggml_fp16_t *)(x + i));
3253
+ uint16x8_t v_yd = vec_convert_from_fp16(v_x, 0);
3254
+ float32x4_t v_yh = vec_extend_to_fp32_hi(v_yd, 0);
3255
+ float32x4_t v_yl = vec_extend_to_fp32_lo(v_yd, 0);
3256
+ vec_xst(v_yh, 0, (float *)(y + i + 0));
3257
+ vec_xst(v_yl, 0, (float *)(y + i + 4));
3258
+ }
3259
+ for (; i + 3 < n; i += 4) {
3260
+ uint16x8_t v_x = vec_xl(0, (const lm_ggml_fp16_t *)(x + i));
3261
+ uint16x8_t v_yd = vec_convert_from_fp16(v_x, 0);
3262
+ float32x4_t v_yh = vec_extend_to_fp32_hi(v_yd, 0);
3263
+ vec_xst(v_yh, 0, (float *)(y + i));
3264
+ }
3265
+ #endif
3266
+
3267
+ for (; i < n; ++i) {
3268
+ y[i] = LM_GGML_CPU_FP16_TO_FP32(x[i]);
3269
+ }
3270
+ }
3271
+
3272
+ void lm_ggml_cpu_fp32_to_bf16(const float * x, lm_ggml_bf16_t * y, int64_t n) {
3273
+ int64_t i = 0;
3274
+ for (; i < n; ++i) {
3275
+ y[i] = LM_GGML_FP32_TO_BF16(x[i]);
3276
+ }
3277
+ }
3278
+
3279
+ void lm_ggml_cpu_bf16_to_fp32(const lm_ggml_bf16_t * x, float * y, int64_t n) {
3280
+ int64_t i = 0;
3281
+ #if defined(__AVX2__)
3282
+ #if defined(__AVX512F__)
3283
+ for (; i + 15 < n; i += 16) {
3284
+ _mm512_storeu_ps(y + i,
3285
+ _mm512_castsi512_ps(
3286
+ _mm512_slli_epi32(
3287
+ _mm512_cvtepu16_epi32(
3288
+ _mm256_loadu_si256(
3289
+ (const __m256i *)(x + i))),
3290
+ 16)));
3291
+ }
3292
+ #endif
3293
+ for (; i + 7 < n; i += 8) {
3294
+ _mm256_storeu_ps(y + i,
3295
+ _mm256_castsi256_ps(
3296
+ _mm256_slli_epi32(
3297
+ _mm256_cvtepu16_epi32(
3298
+ _mm_loadu_si128(
3299
+ (const __m128i *)(x + i))),
3300
+ 16)));
3301
+ }
3302
+ #endif
3303
+ for (; i < n; i++) {
3304
+ y[i] = LM_GGML_BF16_TO_FP32(x[i]);
3305
+ }
3306
+ }
3307
+
3308
+ int lm_ggml_cpu_has_avx(void) {
3309
+ #if defined(__AVX__)
3310
+ return 1;
3311
+ #else
3312
+ return 0;
3313
+ #endif
3314
+ }
3315
+
3316
+ int lm_ggml_cpu_has_avx_vnni(void) {
3317
+ #if defined(__AVXVNNI__)
3318
+ return 1;
3319
+ #else
3320
+ return 0;
3321
+ #endif
3322
+ }
3323
+
3324
+ int lm_ggml_cpu_has_avx2(void) {
3325
+ #if defined(__AVX2__)
3326
+ return 1;
3327
+ #else
3328
+ return 0;
3329
+ #endif
3330
+ }
3331
+
3332
+ int lm_ggml_cpu_has_avx512(void) {
3333
+ #if defined(__AVX512F__)
3334
+ return 1;
3335
+ #else
3336
+ return 0;
3337
+ #endif
3338
+ }
3339
+
3340
+ int lm_ggml_cpu_has_avx512_vbmi(void) {
3341
+ #if defined(__AVX512VBMI__)
3342
+ return 1;
3343
+ #else
3344
+ return 0;
3345
+ #endif
3346
+ }
3347
+
3348
+ int lm_ggml_cpu_has_avx512_vnni(void) {
3349
+ #if defined(__AVX512VNNI__)
3350
+ return 1;
3351
+ #else
3352
+ return 0;
3353
+ #endif
3354
+ }
3355
+
3356
+ int lm_ggml_cpu_has_avx512_bf16(void) {
3357
+ #if defined(__AVX512BF16__)
3358
+ return 1;
3359
+ #else
3360
+ return 0;
3361
+ #endif
3362
+ }
3363
+
3364
+ int lm_ggml_cpu_has_amx_int8(void) {
3365
+ #if defined(__AMX_INT8__)
3366
+ return 1;
3367
+ #else
3368
+ return 0;
3369
+ #endif
3370
+ }
3371
+
3372
+ int lm_ggml_cpu_has_bmi2(void) {
3373
+ #if defined(__BMI2__)
3374
+ return 1;
3375
+ #else
3376
+ return 0;
3377
+ #endif
3378
+ }
3379
+
3380
+ int lm_ggml_cpu_has_fma(void) {
3381
+ #if defined(__FMA__)
3382
+ return 1;
3383
+ #else
3384
+ return 0;
3385
+ #endif
3386
+ }
3387
+
3388
+ int lm_ggml_cpu_has_arm_fma(void) {
3389
+ #if defined(__ARM_FEATURE_FMA)
3390
+ return 1;
3391
+ #else
3392
+ return 0;
3393
+ #endif
3394
+ }
3395
+
3396
+ int lm_ggml_cpu_has_riscv_v(void) {
3397
+ #if defined(__riscv_v_intrinsic)
3398
+ return 1;
3399
+ #else
3400
+ return 0;
3401
+ #endif
3402
+ }
3403
+
3404
+ int lm_ggml_cpu_has_f16c(void) {
3405
+ #if defined(__F16C__)
3406
+ return 1;
3407
+ #else
3408
+ return 0;
3409
+ #endif
3410
+ }
3411
+
3412
+ int lm_ggml_cpu_has_fp16_va(void) {
3413
+ #if defined(__ARM_FEATURE_FP16_VECTOR_ARITHMETIC)
3414
+ return 1;
3415
+ #else
3416
+ return 0;
3417
+ #endif
3418
+ }
3419
+
3420
+ int lm_ggml_cpu_has_wasm_simd(void) {
3421
+ #if defined(__wasm_simd128__)
3422
+ return 1;
3423
+ #else
3424
+ return 0;
3425
+ #endif
3426
+ }
3427
+
3428
+ int lm_ggml_cpu_has_llamafile(void) {
3429
+ #if defined(LM_GGML_USE_LLAMAFILE)
3430
+ return 1;
3431
+ #else
3432
+ return 0;
3433
+ #endif
3434
+ }
3435
+
3436
+ int lm_ggml_cpu_has_sse3(void) {
3437
+ #if defined(__SSE3__)
3438
+ return 1;
3439
+ #else
3440
+ return 0;
3441
+ #endif
3442
+ }
3443
+
3444
+ int lm_ggml_cpu_has_ssse3(void) {
3445
+ #if defined(__SSSE3__)
3446
+ return 1;
3447
+ #else
3448
+ return 0;
3449
+ #endif
3450
+ }
3451
+
3452
+ int lm_ggml_cpu_has_vsx(void) {
3453
+ #if defined(__POWER9_VECTOR__)
3454
+ return 1;
3455
+ #else
3456
+ return 0;
3457
+ #endif
3458
+ }
3459
+
3460
+ int lm_ggml_cpu_has_vxe(void) {
3461
+ #if defined(__VXE__) || defined(__VXE2__)
3462
+ return 1;
3463
+ #else
3464
+ return 0;
3465
+ #endif
3466
+ }
3467
+
3468
+ int lm_ggml_cpu_has_nnpa(void) {
3469
+ #if defined(LM_GGML_NNPA)
3470
+ return 1;
3471
+ #else
3472
+ return 0;
3473
+ #endif
3474
+ }
3475
+
3476
+ int lm_ggml_cpu_has_neon(void) {
3477
+ #if defined(__ARM_ARCH) && defined(__ARM_NEON)
3478
+ return 1;
3479
+ #else
3480
+ return 0;
3481
+ #endif
3482
+ }
3483
+
3484
+ int lm_ggml_cpu_has_dotprod(void) {
3485
+ #if defined(__ARM_ARCH) && defined(__ARM_FEATURE_DOTPROD)
3486
+ return 1;
3487
+ #else
3488
+ return 0;
3489
+ #endif
3490
+ }
3491
+
3492
+ int lm_ggml_cpu_has_sve(void) {
3493
+ #if defined(__ARM_ARCH) && defined(__ARM_FEATURE_SVE)
3494
+ return 1;
3495
+ #else
3496
+ return 0;
3497
+ #endif
3498
+ }
3499
+
3500
+ int lm_ggml_cpu_has_matmul_int8(void) {
3501
+ #if defined(__ARM_ARCH) && defined(__ARM_FEATURE_MATMUL_INT8)
3502
+ return 1;
3503
+ #else
3504
+ return 0;
3505
+ #endif
3506
+ }
3507
+
3508
+ int lm_ggml_cpu_get_sve_cnt(void) {
3509
+ #if defined(__ARM_ARCH) && defined(__ARM_FEATURE_SVE)
3510
+ return lm_ggml_arm_arch_features.sve_cnt;
3511
+ #else
3512
+ return 0;
3513
+ #endif
3514
+ }
3515
+
3516
+ int lm_ggml_cpu_has_sme(void) {
3517
+ #if defined(__ARM_ARCH) && defined(__ARM_FEATURE_SME)
3518
+ return 1;
3519
+ #else
3520
+ return 0;
3521
+ #endif
3522
+ }
3523
+
3524
+ void lm_ggml_cpu_init(void) {
3525
+ // needed to initialize lm_ggml_time
3526
+ {
3527
+ struct lm_ggml_init_params params = { 0, NULL, false };
3528
+ struct lm_ggml_context * ctx = lm_ggml_init(params);
3529
+ lm_ggml_free(ctx);
3530
+ }
3531
+
3532
+ lm_ggml_critical_section_start();
3533
+
3534
+ static bool is_first_call = true;
3535
+
3536
+ if (is_first_call) {
3537
+ // initialize GELU, Quick GELU, SILU and EXP F32 tables
3538
+ {
3539
+ const uint64_t t_start = lm_ggml_time_us(); UNUSED(t_start);
3540
+
3541
+ for (int i = 0; i < (1 << 16); ++i) {
3542
+ union {
3543
+ uint16_t u16;
3544
+ lm_ggml_fp16_t fp16;
3545
+ } u = {i};
3546
+ float f = LM_GGML_COMPUTE_FP16_TO_FP32(u.fp16);
3547
+ lm_ggml_table_f32_f16[i] = f;
3548
+ lm_ggml_table_gelu_f16[i] = LM_GGML_CPU_FP32_TO_FP16(lm_ggml_gelu_f32(f));
3549
+ lm_ggml_table_gelu_quick_f16[i] = LM_GGML_CPU_FP32_TO_FP16(lm_ggml_gelu_quick_f32(f));
3550
+ }
3551
+
3552
+ const uint64_t t_end = lm_ggml_time_us(); UNUSED(t_end);
3553
+
3554
+ LM_GGML_PRINT_DEBUG("%s: GELU, Quick GELU, SILU and EXP tables initialized in %f ms\n", __func__, (t_end - t_start)/1000.0);
3555
+
3556
+ #ifdef LM_GGML_USE_OPENMP
3557
+ //if (!getenv("OMP_WAIT_POLICY")) {
3558
+ // // set the wait policy to active, so that OpenMP threads don't sleep
3559
+ // putenv("OMP_WAIT_POLICY=active");
3560
+ //}
3561
+
3562
+ if (!getenv("KMP_BLOCKTIME")) {
3563
+ // set the time to wait before sleeping a thread
3564
+ // this is less aggressive than setting the wait policy to active, but should achieve similar results in most cases
3565
+ putenv("KMP_BLOCKTIME=200"); // 200ms
3566
+ }
3567
+ #endif
3568
+ }
3569
+
3570
+ #if defined(__ARM_ARCH)
3571
+ lm_ggml_init_arm_arch_features();
3572
+ #endif
3573
+
3574
+ is_first_call = false;
3575
+ }
3576
+
3577
+ lm_ggml_critical_section_end();
3578
+ }