Skip to content

Commit 0db758f

Browse files
committed
ggml-hexagon: add HTP unary ops for ABS and LOG
Add HVX-accelerated implementations for GGML_OP_LOG and GGML_UNARY_OP_ABS on the HTP backend. - Register HTP_OP_UNARY_ABS and HTP_OP_UNARY_LOG in op_remap_to_htp() - Add ABS and LOG to ggml_backend_hexagon_device_supports_op() - Implement hvx_abs_f32_aa() in hvx-arith.h using hvx_vec_abs_f32() - Implement hvx_log_f32_aa() in hvx-log.h using hvx_vec_log_f32() - Add abs_f32() and log_f32() row-wise dispatch in unary-ops.c - Define tiled and non-tiled task functions via DEFINE_UNARY_TASK and DEFINE_UNARY_TILED_TASK macros - Route HTP_OP_UNARY_ABS and HTP_OP_UNARY_LOG through execute_op() in main.c
1 parent a130532 commit 0db758f

8 files changed

Lines changed: 215 additions & 7 deletions

File tree

ggml/src/ggml-hexagon/ggml-hexagon.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3453,6 +3453,7 @@ static htp_op_code op_remap_to_htp(const ggml_tensor * t) {
34533453
case GGML_OP_CLAMP: return HTP_OP_CLAMP;
34543454
case GGML_OP_SQR: return HTP_OP_SQR;
34553455
case GGML_OP_SQRT: return HTP_OP_SQRT;
3456+
case GGML_OP_LOG: return HTP_OP_UNARY_LOG;
34563457
case GGML_OP_SOFT_MAX: return HTP_OP_SOFTMAX;
34573458
case GGML_OP_SSM_CONV: return HTP_OP_SSM_CONV;
34583459
case GGML_OP_GATED_DELTA_NET: return HTP_OP_GATED_DELTA_NET;
@@ -3476,6 +3477,7 @@ static htp_op_code op_remap_to_htp(const ggml_tensor * t) {
34763477
case GGML_UNARY_OP_EXP: return HTP_OP_UNARY_EXP;
34773478
case GGML_UNARY_OP_SOFTPLUS: return HTP_OP_UNARY_SOFTPLUS;
34783479
case GGML_UNARY_OP_TANH: return HTP_OP_UNARY_TANH;
3480+
case GGML_UNARY_OP_ABS: return HTP_OP_UNARY_ABS;
34793481
default:
34803482
break;
34813483
}
@@ -4112,6 +4114,7 @@ static bool ggml_backend_hexagon_device_supports_op(ggml_backend_dev_t dev, cons
41124114

41134115
case GGML_OP_SQR:
41144116
case GGML_OP_SQRT:
4117+
case GGML_OP_LOG:
41154118
supp = ggml_hexagon_supported_unary(sess, op);
41164119
break;
41174120

@@ -4130,6 +4133,7 @@ static bool ggml_backend_hexagon_device_supports_op(ggml_backend_dev_t dev, cons
41304133
case GGML_UNARY_OP_SIGMOID:
41314134
case GGML_UNARY_OP_SOFTPLUS:
41324135
case GGML_UNARY_OP_TANH:
4136+
case GGML_UNARY_OP_ABS:
41334137
case GGML_UNARY_OP_SILU:
41344138
case GGML_UNARY_OP_GELU:
41354139
case GGML_UNARY_OP_GELU_QUICK:

ggml/src/ggml-hexagon/htp/htp-ops.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ enum htp_op_code {
7070
HTP_OP_UNARY_NEG,
7171
HTP_OP_UNARY_SOFTPLUS,
7272
HTP_OP_UNARY_TANH,
73+
HTP_OP_UNARY_ABS,
74+
HTP_OP_UNARY_LOG,
7375
HTP_OP_GLU_SWIGLU,
7476
HTP_OP_GLU_SWIGLU_OAI,
7577
HTP_OP_GLU_GEGLU,

ggml/src/ggml-hexagon/htp/hvx-arith.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,34 @@ static inline void hvx_clamp_scalar_f32(uint8_t * restrict dst, const uint8_t *
358358
}
359359
}
360360

361+
//
362+
// Abs
363+
//
364+
365+
static inline void hvx_abs_f32_aa(uint8_t * restrict dst, const uint8_t * restrict src, uint32_t n) {
366+
assert((unsigned long) dst % 128 == 0);
367+
assert((unsigned long) src % 128 == 0);
368+
369+
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
370+
HVX_Vector * restrict vsrc = (HVX_Vector *) src;
371+
372+
const uint32_t elem_size = sizeof(float);
373+
const uint32_t epv = 128 / elem_size;
374+
const uint32_t nvec = n / epv;
375+
const uint32_t nloe = n % epv;
376+
377+
uint32_t i = 0;
378+
379+
_Pragma("unroll(4)")
380+
for (; i < nvec; i++) {
381+
vdst[i] = hvx_vec_abs_f32(vsrc[i]);
382+
}
383+
if (nloe) {
384+
HVX_Vector v = hvx_vec_abs_f32(vsrc[i]);
385+
hvx_vec_store_a((void *) &vdst[i], nloe * elem_size, v);
386+
}
387+
}
388+
361389
//
362390
// Square
363391
//

ggml/src/ggml-hexagon/htp/hvx-log.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,28 @@ static inline HVX_Vector hvx_vec_log_f32(HVX_Vector x) {
6262
return hvx_vec_add_f32_f32(term_e, res);
6363
}
6464

65+
static inline void hvx_log_f32_aa(uint8_t * restrict dst, const uint8_t * restrict src, uint32_t n) {
66+
assert((unsigned long) dst % 128 == 0);
67+
assert((unsigned long) src % 128 == 0);
68+
69+
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
70+
HVX_Vector * restrict vsrc = (HVX_Vector *) src;
71+
72+
const uint32_t elem_size = sizeof(float);
73+
const uint32_t epv = 128 / elem_size;
74+
const uint32_t nvec = n / epv;
75+
const uint32_t nloe = n % epv;
76+
77+
uint32_t i = 0;
78+
79+
_Pragma("unroll(4)")
80+
for (; i < nvec; i++) {
81+
vdst[i] = hvx_vec_log_f32(vsrc[i]);
82+
}
83+
if (nloe) {
84+
HVX_Vector v = hvx_vec_log_f32(vsrc[i]);
85+
hvx_vec_store_a((void *) &vdst[i], nloe * elem_size, v);
86+
}
87+
}
88+
6589
#endif /* HVX_LOG_H */

ggml/src/ggml-hexagon/htp/main.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,8 @@ static int execute_op(struct htp_ops_context * octx) {
728728
case HTP_OP_UNARY_NEG:
729729
case HTP_OP_UNARY_EXP:
730730
case HTP_OP_UNARY_TANH:
731+
case HTP_OP_UNARY_ABS:
732+
case HTP_OP_UNARY_LOG:
731733
case HTP_OP_L2_NORM:
732734
return op_unary(octx);
733735

ggml/src/ggml-hexagon/htp/unary-ops.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,34 @@ static void tanh_f32(const float * restrict src,
443443
}
444444
}
445445

446+
static void abs_f32(const float * restrict src,
447+
float * restrict dst,
448+
const uint32_t num_rows,
449+
const struct htp_unary_context * uctx) {
450+
htp_unary_op_preamble;
451+
452+
for (uint32_t ir = 0; ir < num_rows; ir++) {
453+
const uint8_t * restrict src_local = (const uint8_t *)src + (ir * src0_row_size_aligned);
454+
uint8_t * restrict dst_local = (uint8_t *)dst + (ir * dst_row_size_aligned);
455+
456+
hvx_abs_f32_aa(dst_local, src_local, ne0);
457+
}
458+
}
459+
460+
static void log_f32(const float * restrict src,
461+
float * restrict dst,
462+
const uint32_t num_rows,
463+
const struct htp_unary_context * uctx) {
464+
htp_unary_op_preamble;
465+
466+
for (uint32_t ir = 0; ir < num_rows; ir++) {
467+
const uint8_t * restrict src_local = (const uint8_t *)src + (ir * src0_row_size_aligned);
468+
uint8_t * restrict dst_local = (uint8_t *)dst + (ir * dst_row_size_aligned);
469+
470+
hvx_log_f32_aa(dst_local, src_local, ne0);
471+
}
472+
}
473+
446474
#define DEFINE_UNARY_TASK(NAME, IS_RMS_NORM_MUL, IS_TRI, CORE_EXPR) \
447475
static void unary_task_f32_##NAME(unsigned int nth, unsigned int ith, void * data) { \
448476
const struct htp_unary_context * uctx = (const struct htp_unary_context *) data; \
@@ -603,6 +631,8 @@ DEFINE_UNARY_TASK(unary_silu, false, false, silu_f32(src0_vtcm, dst_vtcm, bl
603631
DEFINE_UNARY_TASK(unary_gelu, false, false, gelu_f32(src0_vtcm, dst_vtcm, block_size, uctx))
604632
DEFINE_UNARY_TASK(unary_softplus, false, false, softplus_f32(src0_vtcm, dst_vtcm, block_size, uctx))
605633
DEFINE_UNARY_TASK(unary_tanh, false, false, tanh_f32(src0_vtcm, dst_vtcm, block_size, uctx))
634+
DEFINE_UNARY_TASK(unary_abs, false, false, abs_f32(src0_vtcm, dst_vtcm, block_size, uctx))
635+
DEFINE_UNARY_TASK(unary_log, false, false, log_f32(src0_vtcm, dst_vtcm, block_size, uctx))
606636
DEFINE_UNARY_TASK(l2_norm, false, false, l2_norm_f32(src0_vtcm, dst_vtcm, block_size, uctx))
607637
DEFINE_UNARY_TASK(tri, false, true, tri_f32(src0_vtcm, dst_vtcm, block_size, ir, uctx))
608638

@@ -850,6 +880,8 @@ DEFINE_UNARY_TILED_TASK(unary_silu, false, tile_silu_f32(dst_vtcm, src_vtcm,
850880
DEFINE_UNARY_TILED_TASK(unary_gelu, false, tile_gelu_f32(dst_vtcm, src_vtcm, tw))
851881
DEFINE_UNARY_TILED_TASK(unary_softplus, false, tile_unary_softplus_f32(dst_vtcm, src_vtcm, tw))
852882
DEFINE_UNARY_TILED_TASK(unary_tanh, false, hvx_tanh_f32_aa(dst_vtcm, src_vtcm, tw))
883+
DEFINE_UNARY_TILED_TASK(unary_abs, false, hvx_abs_f32_aa(dst_vtcm, src_vtcm, tw))
884+
DEFINE_UNARY_TILED_TASK(unary_log, false, hvx_log_f32_aa(dst_vtcm, src_vtcm, tw))
853885
DEFINE_UNARY_TILED_TASK(tri, true, tri_apply_tile_f32(src_vtcm, dst_vtcm, tw, col, i01, ne0, tri_ttype))
854886

855887
static int execute_op_unary_f32(struct htp_ops_context * octx) {
@@ -875,6 +907,8 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
875907
case HTP_OP_UNARY_GELU: op_type = "gelu-f32"; break;
876908
case HTP_OP_UNARY_SOFTPLUS: op_type = "softplus-f32"; break;
877909
case HTP_OP_UNARY_TANH: op_type = "tanh-f32"; break;
910+
case HTP_OP_UNARY_ABS: op_type = "abs-f32"; break;
911+
case HTP_OP_UNARY_LOG: op_type = "log-f32"; break;
878912
case HTP_OP_L2_NORM: op_type = "l2norm-f32"; break;
879913
case HTP_OP_TRI: op_type = "tri-f32"; break;
880914

@@ -973,6 +1007,8 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
9731007
case HTP_OP_UNARY_GELU: task_func = unary_task_f32_tiled_unary_gelu; break;
9741008
case HTP_OP_UNARY_SOFTPLUS: task_func = unary_task_f32_tiled_unary_softplus; break;
9751009
case HTP_OP_UNARY_TANH: task_func = unary_task_f32_tiled_unary_tanh; break;
1010+
case HTP_OP_UNARY_ABS: task_func = unary_task_f32_tiled_unary_abs; break;
1011+
case HTP_OP_UNARY_LOG: task_func = unary_task_f32_tiled_unary_log; break;
9761012
case HTP_OP_TRI: task_func = unary_task_f32_tiled_tri; break;
9771013
default: break;
9781014
}
@@ -992,6 +1028,8 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
9921028
case HTP_OP_UNARY_GELU: task_func = unary_task_f32_unary_gelu; break;
9931029
case HTP_OP_UNARY_SOFTPLUS: task_func = unary_task_f32_unary_softplus; break;
9941030
case HTP_OP_UNARY_TANH: task_func = unary_task_f32_unary_tanh; break;
1031+
case HTP_OP_UNARY_ABS: task_func = unary_task_f32_unary_abs; break;
1032+
case HTP_OP_UNARY_LOG: task_func = unary_task_f32_unary_log; break;
9951033
case HTP_OP_L2_NORM: task_func = unary_task_f32_l2_norm; break;
9961034
case HTP_OP_TRI: task_func = unary_task_f32_tri; break;
9971035
default: break;

ggml/src/ggml-hexagon/htp/unary-ops.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ static inline bool htp_op_is_unary(uint32_t opcode) {
5555
case HTP_OP_UNARY_GELU:
5656
case HTP_OP_UNARY_SOFTPLUS:
5757
case HTP_OP_UNARY_TANH:
58+
case HTP_OP_UNARY_ABS:
59+
case HTP_OP_UNARY_LOG:
5860
case HTP_OP_L2_NORM:
5961
case HTP_OP_TRI:
6062
return true;

tests/test-backend-ops.cpp

Lines changed: 115 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2469,8 +2469,13 @@ struct test_set_rows : public test_case {
24692469
// See dicussion here: https://github.com/ggml-org/llama.cpp/pull/23760#issuecomment-4566312209
24702470
double max_nmse_err(ggml_backend_t backend) override {
24712471
ggml_backend_reg_t reg = ggml_backend_dev_backend_reg(ggml_backend_get_device(backend));
2472-
if (type_dst == GGML_TYPE_Q8_0 && strcmp(ggml_backend_reg_name(reg), "WebGPU") == 0) {
2473-
return std::max(test_case::max_nmse_err(backend), 2e-7);
2472+
if (type_dst == GGML_TYPE_Q8_0) {
2473+
if (strcmp(ggml_backend_reg_name(reg), "WebGPU") == 0) {
2474+
return std::max(test_case::max_nmse_err(backend), 2e-7);
2475+
}
2476+
if (strcmp(ggml_backend_reg_name(reg), "HTP") == 0) {
2477+
return std::max(test_case::max_nmse_err(backend), 5e-6);
2478+
}
24742479
}
24752480
return test_case::max_nmse_err(backend);
24762481
}
@@ -4120,9 +4125,10 @@ struct test_ssm_scan : public test_case {
41204125
const int64_t n_seqs;
41214126
const bool xbc_overlap;
41224127
const int64_t K;
4128+
const bool weak_decay;
41234129

41244130
std::string vars() override {
4125-
return VARS_TO_STR9(type, d_state, head_dim, n_head, n_group, n_seq_tokens, n_seqs, xbc_overlap, K);
4131+
return VARS_TO_STR10(type, d_state, head_dim, n_head, n_group, n_seq_tokens, n_seqs, xbc_overlap, K, weak_decay);
41264132
}
41274133

41284134
test_ssm_scan(ggml_type type = GGML_TYPE_F32,
@@ -4133,8 +4139,9 @@ struct test_ssm_scan : public test_case {
41334139
int64_t n_seq_tokens = 32,
41344140
int64_t n_seqs = 32,
41354141
bool xbc_overlap = false,
4136-
int64_t K = 1)
4137-
: type(type), d_state(d_state), head_dim(head_dim), n_head(n_head), n_group(n_group), n_seq_tokens(n_seq_tokens), n_seqs(n_seqs), xbc_overlap(xbc_overlap), K(K) {}
4142+
int64_t K = 1,
4143+
bool weak_decay = false)
4144+
: type(type), d_state(d_state), head_dim(head_dim), n_head(n_head), n_group(n_group), n_seq_tokens(n_seq_tokens), n_seqs(n_seqs), xbc_overlap(xbc_overlap), K(K), weak_decay(weak_decay) {}
41384145

41394146
double max_nmse_err() override {
41404147
// SSD path (head_dim > 1) uses FP16 intermediates (M matrix, X_dt); Mamba-1 is pure FP32.
@@ -4187,7 +4194,7 @@ struct test_ssm_scan : public test_case {
41874194
continue;
41884195
} else if (t->ne[1] == n_head && t->ne[2] == 1) {
41894196
// A {1 or d_state, n_head}: negative decay (2-D tensor, ne[2]==1 distinguishes from 3-D/4-D tensors)
4190-
init_tensor_uniform(t, -1.0f, -0.5f);
4197+
init_tensor_uniform(t, weak_decay ? -0.02f : -1.0f, weak_decay ? -0.005f : -0.5f);
41914198
} else {
41924199
init_tensor_uniform(t);
41934200
}
@@ -9111,6 +9118,10 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
91119118
test_cases.emplace_back(new test_ssm_scan(GGML_TYPE_F32, 128, 64, 16, 2, 4, 2, false, /*K=*/4)); // Mamba-2 rollback snapshots
91129119
test_cases.emplace_back(new test_ssm_scan(GGML_TYPE_F32, 128, 64, 16, 2, 8, 2, false, /*K=*/3)); // Mamba-2 rollback overflow
91139120
test_cases.emplace_back(new test_ssm_scan_rollback(GGML_TYPE_F32, 128, 64, 16, 2, 8, 2, /*K=*/3)); // rollback snapshots match prefix states
9121+
test_cases.emplace_back(new test_ssm_scan(GGML_TYPE_F32, 128, 64, 16, 2, 64, 4)); // Metal SSD one chunk MMA only, no seq tail
9122+
test_cases.emplace_back(new test_ssm_scan(GGML_TYPE_F32, 128, 64, 16, 2, 65, 2)); // SSD one chunk + 1-token sequential tail
9123+
test_cases.emplace_back(new test_ssm_scan(GGML_TYPE_F32, 128, 64, 16, 2, 128, 2)); // SSD multi-chunk, no tail (exercises the chunk-to-chunk state handoff)
9124+
test_cases.emplace_back(new test_ssm_scan(GGML_TYPE_F32, 128, 64, 16, 2, 128, 2, false, /*K=*/1, /*weak_decay=*/true)); // SSD multi-chunk, carried state not numerically negligible
91149125

91159126
test_cases.emplace_back(new test_rwkv_wkv6(GGML_TYPE_F32, 32, 64, 1, 1));
91169127
test_cases.emplace_back(new test_rwkv_wkv6(GGML_TYPE_F32, 32, 64, 32, 1));
@@ -10573,6 +10584,101 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_from_file(const c
1057310584
return test_cases;
1057410585
}
1057510586

10587+
// ---- FA vec (Q,NE): forced-config numerical slice (Metal only) ----
10588+
using set_fa_vec_override_t = void (*)(int, int);
10589+
using clear_fa_vec_override_t = void (*)(void);
10590+
10591+
// NL = 32/NE must divide both dk/4 and dv/4.
10592+
static std::vector<int> fa_vec_legal_ne(int dk, int dv) {
10593+
std::vector<int> r;
10594+
for (int ne : {1, 2, 4}) {
10595+
const int nl = 32 / ne;
10596+
if ((dk/4) % nl == 0 && (dv/4) % nl == 0) {
10597+
r.push_back(ne);
10598+
}
10599+
}
10600+
return r;
10601+
}
10602+
10603+
static bool op_names_filter_selects(const char * op_names_filter, const char * op_name) {
10604+
if (!op_names_filter) {
10605+
return true;
10606+
}
10607+
std::string_view filter(op_names_filter);
10608+
while (!filter.empty()) {
10609+
auto comma_pos = filter.find_first_of(',');
10610+
const auto lparen_pos = filter.find_first_of('(');
10611+
std::string_view entry;
10612+
if (lparen_pos < comma_pos) {
10613+
const auto rparen_pos = filter.find_first_of(')');
10614+
comma_pos = filter.find_first_of(',', rparen_pos);
10615+
entry = filter.substr(0, lparen_pos);
10616+
} else {
10617+
entry = filter.substr(0, comma_pos);
10618+
}
10619+
if (entry == op_name) {
10620+
return true;
10621+
}
10622+
filter = comma_pos != std::string_view::npos ? filter.substr(comma_pos + 1) : "";
10623+
}
10624+
return false;
10625+
}
10626+
10627+
// Covers padded rows, sinks, kvpad, multi-SIMDgroup reduction, quantized K/V, and MLA views.
10628+
// The override is backend-global, so this runs after all parallel workers have joined.
10629+
static bool run_fa_vec_slice(ggml_backend_t backend, ggml_backend_t backend_cpu, const char * op_names_filter) {
10630+
if (!op_names_filter_selects(op_names_filter, "FLASH_ATTN_EXT")) {
10631+
return true;
10632+
}
10633+
10634+
auto * reg = ggml_backend_dev_backend_reg(ggml_backend_get_device(backend));
10635+
10636+
auto set_ov = (set_fa_vec_override_t) ggml_backend_reg_get_proc_address(reg, "ggml_backend_metal_tuning_set_fa_vec_override");
10637+
auto clear_ov = (clear_fa_vec_override_t) ggml_backend_reg_get_proc_address(reg, "ggml_backend_metal_tuning_clear_fa_vec_override");
10638+
if (!set_ov || !clear_ov) {
10639+
return true; // not the Metal backend: nothing to force
10640+
}
10641+
10642+
struct shape_t { int dk, dv; };
10643+
const shape_t shapes[] = { { 128, 128 }, { 576, 512 } }; // mainstream head size + MLA shared K/V view
10644+
const int ne01_pts[] = { 1, 3 }; // decode, and padded rows for Q=2 and Q=4
10645+
const int ne11_pts[] = { 512, 4097 }; // nsg=1, and nsg>=2 together with kvpad
10646+
const ggml_type types[] = { GGML_TYPE_F16, GGML_TYPE_Q4_0 };
10647+
10648+
int n_run = 0, n_fail = 0;
10649+
for (auto s : shapes) {
10650+
for (int ne : fa_vec_legal_ne(s.dk, s.dv)) {
10651+
for (int Q : { 1, 2, 4 }) {
10652+
for (ggml_type type_kv : types) {
10653+
for (bool sinks : { false, true }) {
10654+
for (int ne01 : ne01_pts) {
10655+
for (int ne11 : ne11_pts) {
10656+
set_ov(Q, ne);
10657+
test_flash_attn_ext tc(s.dk, s.dv, /*nh=*/4, { 1, 1 }, /*kv=*/ne11, /*nb=*/ne01,
10658+
/*mask=*/true, sinks, 0.0f, 0.0f, GGML_PREC_F32,
10659+
type_kv, type_kv);
10660+
auto st = tc.eval(backend, backend_cpu, "FLASH_ATTN_EXT", nullptr);
10661+
clear_ov();
10662+
10663+
if (st == test_status_t::FAIL) {
10664+
printf(" FAIL fa_vec slice: dk=%d dv=%d Q=%d ne=%d type=%s ne01=%d ne11=%d sinks=%d\n",
10665+
s.dk, s.dv, Q, ne, ggml_type_name(type_kv), ne01, ne11, (int) sinks);
10666+
n_fail++;
10667+
}
10668+
n_run++;
10669+
}
10670+
}
10671+
}
10672+
}
10673+
}
10674+
}
10675+
}
10676+
10677+
printf(" fa_vec (Q,NE) slice: %d cases run, %d failed\n", n_run, n_fail);
10678+
10679+
return n_fail == 0;
10680+
}
10681+
1057610682
static bool test_backend(ggml_backend_t backend, ggml_backend_dev_t dev, test_mode mode, const char * op_names_filter, const char * params_filter,
1057710683
printer * output_printer, const char * test_file_path, int parallel_workers) {
1057810684
auto filter_test_cases = [](std::vector<std::unique_ptr<test_case>> & test_cases, const char * params_filter) {
@@ -10710,7 +10816,9 @@ static bool test_backend(ggml_backend_t backend, ggml_backend_dev_t dev, test_mo
1071010816
output_printer->print_summary(test_summary_info(n_ok, tests_run, false));
1071110817
output_printer->print_failed_tests(failed_tests);
1071210818

10713-
return n_ok == tests_run;
10819+
const bool slice_ok = run_fa_vec_slice(backend, backend_cpu.get(), op_names_filter);
10820+
10821+
return n_ok == tests_run && slice_ok;
1071410822
}
1071510823

1071610824
if (mode == MODE_GRAD) {

0 commit comments

Comments
 (0)