Compare commits

...
5 Commits
Author SHA1 Message Date
Raul Torres f5027fb213 CANN: missing const qualifiers added for consistency (#30933) 2026-10-23 15:34:20 +08:00
Titaniumtown f64a49819c sycl : pass device into mul_mat_uses_onednn (#31014) 2026-10-23 08:37:53 +02:00
Pranesh GonegandlaandPranesh Gonegandla 1ab09d632e Extend probabilistic sampling for DFlash2 drafts (#30663)
* spec : add probabilistic sampling for DFlash2 drafts

* spec : apply review suggestions

---------

Co-authored-by: Pranesh Gonegandla <pgonegandla@nvidia.com>
2026-10-23 11:15:36 +05:30
f9599d0cc8 vocab : fix Nemotron-3.5-Embed tokenization (#30974)
* vocab : fix Nemotron-3.5-Embed tokenization

* Update src/llama-vocab.h

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>

* rename

* Update src/llama-vocab.cpp

Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>

---------

Co-authored-by: Sigbjørn Skjæret <sigbjorn.skjaeret@huggingface.co>
Co-authored-by: Daniel Bevenius <daniel.bevenius@gmail.com>
2026-10-23 07:31:30 +02:00
Max Krasnyansky 643b0cdacb hexagon: Op Fusion refactoring, optimizations and new fusions like BINARY_NX (back-to-back ADDs, etc) (#30843)
* hex-fusion: support for GELU+MUL, REPEAT+GET_ROWS and BINARY_NX (back-to-back ADD/MUL/...)

* hex-fusion: factor out fusion logic into separate .h and .cpp and update all related code

* hex-fusion: allow for RMS_NORM+MUL fusions for non-contig tensors

* hex-fusion: streamline fusion eligibility checks and cover missing corner cases

* hex-fusion: streamline fusion flow

* hex-opbatch: make n_tensors limit more scalable

* hex-bufs: adjust the trace buff sizing

* hex-glu: cleanup glu-ops interfaces and add kernel_params

* hex-kparams: clean up kparams handling in unary, ssm-conv, and other ops

* hex-kparams: update the rest of the ops PAD,DIAG,... to use kparams

* hex-unary: add support for collapsing dims

* hex-ops: cleanup redundant runtime checks

* hex-ops: consistent use of kernel_type in all kparams

* hex-fusion: remove redundant check in gdn+cpy

* hex-fusion: further streamlining of fusion rules and code

* hex-fusion: cleanup naming

* hex-opfmt: cleanup op formatting

* hex-fusion: bump fusion lookahead to 64

* hex-fusion: fuse SSM_CONV+SILU

* hex-fusion: fix hvx register spills in fused ssm_conv+silu

* hex-fusion: add more GLU fusions

* hex-fusion: remove duplicate checks and use ggml-common helpers

* hex-kparams: refactor kparams into htp-kparams.h/cpp

* hex-fusion: fix binary-nx fusion regression

* hex-kparams: another pass at cleaning up kparams (removing unused, etc)

* hex-kparams: streamling nameing and move _check_ wrappers into .h

* hex-kparams: templetize htp_kparams_check_<op> to reduce code bloat

* hex-ops: de-duplicate op dispatch switches

* hex-kparams: trim down exposed kparams calls

* hex-kparams: simplify type casting of kparams structs

* hex-fence: de-dup fence tensor construction

* hex-opbatch: simplify tensor shape init/checks

* hex-mm: cleanup leftovers of the original QK defines

* hex-fa: fix stack overflow on older npu firmware

* hex-ctx: move dma_caches into ops_ctx
2026-10-22 21:05:44 -07:00
78 changed files with 7253 additions and 7238 deletions
+60 -3
View File
@@ -19,6 +19,7 @@
#include <fstream>
#include <iomanip>
#include <map>
#include <random>
#include <cinttypes>
#define SPC_DBG(fmt, ...) LOG_DBG("spec %12.*s: " fmt, 12, __func__, __VA_ARGS__)
@@ -1010,6 +1011,10 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
bool is_mrope = false;
int32_t selector_top_k = 0;
// DFlash2 probabilistic drafting: one generator per sequence and the seed it was last seeded with (-1: reseed)
std::vector<std::mt19937> dflash2_rng;
std::vector<int64_t> dflash2_seed;
// draft-dspark: the draft carries a Markov head and uses an anchor-first block layout
const bool is_dspark;
@@ -1060,6 +1065,8 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
selector_top_k = llama_model_dflash_selector_top_k(model_dft);
is_dflash2 = selector_top_k > 0;
dflash2_rng.resize(n_seq);
dflash2_seed.assign(n_seq, -1);
char lilicorr_meta[32] = {};
lilicorr_top_k = llama_model_meta_val_str(model_dft, "lilicorr.candidate_topk", lilicorr_meta, sizeof(lilicorr_meta)) >= 0
? std::atoi(lilicorr_meta) : 0;
@@ -1158,6 +1165,9 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
return;
}
// reseed per request rather than per round, or two identical requests differ
dflash2_seed[seq_id] = -1;
const int32_t N = (int32_t) prompt.size();
if (N <= 0) {
return;
@@ -1338,6 +1348,21 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
const float * lattice = llama_get_embeddings_nextn(ctx_dft);
GGML_ASSERT(lattice && "DFlash2 selector produced no lattice");
// DFlash2 can instead sample each step and hand q to the verifier for rejection sampling
const bool sample = is_dflash2 && params.probabilistic && dp.result_q;
// greedy keeps temperature 1, sampling uses the target's
const float temp = sample ? dp.temp : 1.0f;
if (sample && dflash2_seed[seq_id] != dp.seed) {
dflash2_seed[seq_id] = dp.seed;
// the default seed means random; mixed so it differs from the target's, as in spec_retune
dflash2_rng[seq_id].seed(dp.seed == LLAMA_DEFAULT_SEED ? std::random_device{}() : dp.seed ^ 0x85ebca6bu);
}
std::vector<float> probs;
std::vector<int32_t> sorted_idx;
int32_t predecessor = 0;
for (int32_t i = 1; i < (is_dflash2 ? n_block_tokens : params.n_max + 1); ++i) {
const float * row = lattice + (size_t) (beg + i) * n_embd_dec;
@@ -1346,21 +1371,53 @@ struct common_speculative_impl_draft_dflash : public common_speculative_impl {
predecessor = (int32_t) std::distance(scores,
std::max_element(scores, scores + top_k));
if (params.p_min > 0.0f) {
// softmax(scores) at the argmax, i.e. 1 / sum(exp(s_k - s_max))
if (params.p_min > 0.0f || sample) {
// softmax(scores / temp) at the argmax, i.e. 1 / sum(exp((s_k - s_max) / temp))
probs.resize(top_k);
float sum = 0.0f;
for (int32_t k = 0; k < top_k; ++k) {
sum += std::exp(scores[k] - scores[predecessor]);
probs[k] = std::exp((scores[k] - scores[predecessor]) / temp);
sum += probs[k];
}
if (1.0f / sum < params.p_min) {
break;
}
for (int32_t k = 0; k < top_k; ++k) {
probs[k] /= sum;
}
}
if (sample) {
// ggml_top_k leaves candidates unordered, so walk them by token id to keep a seed's draft stable
sorted_idx.resize(top_k);
for (int32_t k = 0; k < top_k; ++k) {
sorted_idx[k] = k;
}
std::sort(sorted_idx.begin(), sorted_idx.end(), [row](int32_t a, int32_t b) { return row[a] < row[b]; });
// a round-off overshoot keeps the argmax, which has q > 0
double u = std::uniform_real_distribution<double>(0.0, 1.0)(dflash2_rng[seq_id]);
for (const int32_t k : sorted_idx) {
u -= probs[k];
if (u < 0.0) {
predecessor = k;
break;
}
}
auto & q = dp.result_q->emplace_back();
q.reserve(top_k);
for (int32_t k = 0; k < top_k; ++k) {
q.push_back({ (llama_token) row[k], scores[k], probs[k] });
}
}
result.push_back((llama_token) row[predecessor]);
}
if (result.size() < (size_t) params.n_min) {
result.clear();
if (sample) {
dp.result_q->clear();
}
}
continue;
}
+1 -1
View File
@@ -73,7 +73,7 @@ struct common_speculative_draft_params {
// the generated draft from the last _draft() call
llama_tokens * result;
// candidate distribution per drafted token; set it to make draft-simple and draft-mtp sample
// candidate distribution per drafted token; set it to make draft-simple, draft-mtp and draft-dflash (DFlash2 only) sample
std::vector<std::vector<llama_token_data>> * result_q = nullptr;
// the target's temp and seed, read only when the drafter samples probabilistically
+5
View File
@@ -39,6 +39,11 @@ class Mistral3Model(TextModel):
self.gguf_writer.add_add_bos_token(False)
self.gguf_writer.add_add_eos_token(False)
def get_vocab_base_pre(self, tokenizer) -> str:
if self.origin_hf_arch == "Mistral3Model":
return "nemotron-3.5-embed"
return super().get_vocab_base_pre(tokenizer)
def set_gguf_parameters(self):
super().set_gguf_parameters()
self._try_set_pooling_type()
+3 -3
View File
@@ -920,7 +920,7 @@ static void * ggml_backend_cann_buffer_get_base(ggml_backend_buffer_t buffer) {
* @param dst Pointer to the destination buffer where transformed data will be
* stored.
*/
static void ggml_backend_cann_transform_q4_0(ggml_tensor * tensor, const void * src, void * dst) {
static void ggml_backend_cann_transform_q4_0(const ggml_tensor * tensor, const void * src, void * dst) {
int64_t n_elems = ggml_nelements(tensor);
int64_t groups = n_elems / QK4_0;
size_t quant_bytes = n_elems * sizeof(uint8_t) / 2;
@@ -1014,7 +1014,7 @@ static void ggml_backend_cann_transform_back_q4_0(const ggml_tensor * tensor, vo
* @param dst Pointer to the destination buffer where transformed data will be
* stored.
*/
static void ggml_backend_cann_transform_q8_0(ggml_tensor * tensor, const void * src, void * dst) {
static void ggml_backend_cann_transform_q8_0(const ggml_tensor * tensor, const void * src, void * dst) {
int64_t n_elems = ggml_nelements(tensor);
int64_t groups = n_elems / QK8_0;
size_t quant_bytes = n_elems * sizeof(uint8_t);
@@ -1075,7 +1075,7 @@ static void ggml_backend_cann_transform_back_q8_0(const ggml_tensor * tensor, co
* @param dst Pointer to the destination buffer where transformed data will be
* stored.
*/
static void ggml_backend_cann_transform(ggml_tensor * tensor, const void * src, void * dst) {
static void ggml_backend_cann_transform(const ggml_tensor * tensor, const void * src, void * dst) {
switch (tensor->type) {
case GGML_TYPE_Q4_0:
ggml_backend_cann_transform_q4_0(tensor, src, dst);
+7
View File
@@ -51,6 +51,13 @@ endif()
set(TARGET_NAME ggml-hexagon)
ggml_add_backend_library(${TARGET_NAME}
ggml-hexagon.cpp
htp-common.h
htp-kparams.cpp
htp-kparams.h
htp-opnode.cpp
htp-opnode.h
htp-fusion.cpp
htp-fusion.h
htp-repack.cpp
htp-repack.h
htp-drv.cpp
File diff suppressed because it is too large Load Diff
+106
View File
@@ -0,0 +1,106 @@
#ifndef HTP_COMMON_H
#define HTP_COMMON_H
#include "htp-opnode.h"
#include "htp-repack.h"
struct htp_tensor_extra {
std::vector<uint8_t> shadow_buf;
size_t shadow_size { 0 };
uint32_t flags { 0 };
};
extern int opt_arch;
extern size_t opt_ndev;
extern size_t opt_nhvx;
extern int opt_nhmx;
extern size_t opt_vmem;
extern int opt_etm;
extern int opt_verbose;
extern int opt_profile;
extern bool opt_hostbuf;
extern bool opt_dma64;
extern int opt_power_mode;
extern size_t opt_mbuf_dyn;
extern size_t opt_mbuf_static;
extern size_t opt_mbuf_total;
extern int opt_mm_select;
extern int opt_fa_select;
extern int opt_fa_head_split;
extern int opt_gdn_select;
extern int opt_ar_select;
extern int opt_ar_scatter;
extern int opt_opbatch;
extern int opt_opqueue;
extern int opt_optrace;
extern int opt_oppoll;
extern int opt_opfusion;
extern int opt_rt_repack;
#ifndef HEX_VERBOSE
#define HEX_VERBOSE(...) \
if (opt_verbose) GGML_LOG_DEBUG(__VA_ARGS__)
#endif
static inline bool htp_tensor_is_fuseable(const struct ggml_tensor * t) {
if (!t || !t->extra) return false;
const auto * extra = (const struct htp_tensor_extra *) t->extra;
return (extra->flags & HTP_TENSOR_FUSEABLE) != 0;
}
static inline bool htp_can_rt_repack(const struct ggml_tensor * t) {
if (opt_rt_repack == 0 || !htp_is_tiled_weight_tensor(t)) {
return false;
}
if (t->buffer && ggml_backend_buft_is_host(t->buffer->buft)) {
return false;
}
return opt_rt_repack > 1 || ggml_is_quantized(t->type);
}
static inline bool htp_tensor_is_tiled(const struct ggml_tensor * t) {
const auto * extra = (const struct htp_tensor_extra *) t->extra;
if (extra && (extra->flags & HTP_TENSOR_TILED)) {
return true;
}
return htp_can_rt_repack(t);
}
static inline bool htp_needs_repack(const struct ggml_tensor * t) {
const auto * extra = (const struct htp_tensor_extra *) t->extra;
if (extra && (extra->flags & HTP_TENSOR_TILED)) {
return false;
}
return htp_can_rt_repack(t);
}
static inline bool htp_tensors_overlap(const struct ggml_tensor * a, const struct ggml_tensor * b) {
const uintptr_t a0 = (uintptr_t) a->data;
const uintptr_t b0 = (uintptr_t) b->data;
const uintptr_t a1 = a0 + ggml_nbytes(a);
const uintptr_t b1 = b0 + ggml_nbytes(b);
return a0 < b1 && b0 < a1;
}
static inline bool htp_can_row_partition(const struct ggml_tensor * t) {
if (t->ne[1] > 1 && (t->nb[1] & 127) != 0) return false;
if (t->ne[2] > 1 && (t->nb[2] & 127) != 0) return false;
if (t->ne[3] > 1 && (t->nb[3] & 127) != 0) return false;
return true;
}
struct ggml_hexagon_session;
const char * htp_session_name(const struct ggml_hexagon_session * sess);
size_t htp_session_vtcm_size(const struct ggml_hexagon_session * sess);
uint32_t htp_session_n_threads(const struct ggml_hexagon_session * sess);
uint32_t htp_session_n_hmx(const struct ggml_hexagon_session * sess);
uint32_t htp_session_mdev_count(const struct ggml_hexagon_session * sess);
htp_op_code htp_op_remap(const struct ggml_tensor * t);
#endif // HTP_COMMON_H
+650
View File
@@ -0,0 +1,650 @@
#include "htp-fusion.h"
#include "htp-kparams.h"
#include "ggml-impl.h"
#include <algorithm>
#include <cstring>
static inline bool htp_same_tensor_data(const ggml_tensor * a, const ggml_tensor * b) {
return a && b && (a == b || a->data == b->data);
}
static inline bool htp_same_shape_and_contiguity(const ggml_tensor * a, const ggml_tensor * b) {
return ggml_are_same_shape(a, b) && (ggml_is_contiguous(a) == ggml_is_contiguous(b));
}
static inline bool htp_inplace_overlap_unsafe(const ggml_tensor * dst, const ggml_tensor * in) {
return htp_tensors_overlap(dst, in) && (dst->data != in->data || !ggml_are_same_stride(dst, in));
}
static inline bool htp_inputs_overlap_unsafe(const htp_opnode & prev, const ggml_tensor * dst, const ggml_tensor * extra = nullptr) {
if (extra && htp_inplace_overlap_unsafe(dst, extra)) return true;
for (const auto * in : prev.inputs) {
if (htp_inplace_overlap_unsafe(dst, in)) return true;
}
return false;
}
static inline bool htp_match_consumer(
const htp_opnode & prev,
const htp_opnode & cur,
bool commutative,
const ggml_tensor ** other_src = nullptr
) {
if (prev.outputs.size() != 1) {
return false;
}
const ggml_tensor * prev_out = prev.dst();
if (!htp_tensor_is_fuseable(prev_out)) {
return false;
}
if (htp_same_tensor_data(cur.src0(), prev_out)) {
if (other_src) *other_src = cur.src1();
return true;
}
if (commutative && htp_same_tensor_data(cur.src1(), prev_out)) {
if (other_src) *other_src = cur.src0();
return true;
}
return false;
}
static bool is_supported_mul_mat_nx_kernel(const ggml_tensor * src0, const struct htp_mm_kernel_params * kparams) {
if (kparams->n_hmx) {
return kparams->kernel_type == HTP_MM_KERNEL_HMX_2D;
}
return htp_tensor_is_tiled(src0) && (kparams->kernel_type == HTP_MM_KERNEL_HVX_QUANT_ROW);
}
static bool is_supported_mul_mat_id_nx_kernel(const ggml_tensor * src0, const struct htp_mm_kernel_params * kparams) {
if (kparams->n_hmx) {
return kparams->kernel_type == HTP_MM_KERNEL_HMX_2D;
}
return htp_tensor_is_tiled(src0) &&
(kparams->kernel_type == HTP_MM_KERNEL_HVX_QUANT_ROW || kparams->kernel_type == HTP_MM_KERNEL_HVX_QUANT_BLOCK);
}
// --- Fusion rules ---
static bool fuse_allreduce_add(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (opt_ar_select != 2 || prev.opcode != HTP_OP_ALLREDUCE) return false;
const auto * ar_kparams = prev.kparams<htp_allreduce_kernel_params>();
const uint32_t rank = (uint32_t) ar_kparams->rank;
const uint32_t n_ranks = (uint32_t) ar_kparams->n_ranks;
const ggml_tensor * ar_local = prev.inputs[rank];
if (!htp_tensor_is_fuseable(ar_local)) return false;
const ggml_tensor * add_dst = cur.dst();
const ggml_tensor * res_tensor = nullptr;
if (htp_same_tensor_data(cur.src0(), ar_local)) {
res_tensor = cur.src1();
} else if (htp_same_tensor_data(cur.src1(), ar_local)) {
res_tensor = cur.src0();
} else {
return false;
}
if (ar_local->type != res_tensor->type) return false;
const bool is_same_shape = ggml_are_same_shape(ar_local, res_tensor);
const bool is_row_bcast = !is_same_shape && (ar_local->ne[0] == res_tensor->ne[0] &&
res_tensor->ne[1] == 1 && res_tensor->ne[2] == 1 && res_tensor->ne[3] == 1);
if (!is_same_shape && !is_row_bcast) return false;
if (is_same_shape && !ggml_are_same_stride(ar_local, res_tensor)) {
return false;
}
if (ggml_is_contiguous(ar_local) != ggml_is_contiguous(add_dst)) return false;
const bool is_shard_ok = n_ranks <= HTP_OP_MAX_OUTPUTS && add_dst->data == ar_local->data;
struct htp_allreduce_kernel_params kparams;
if (!htp_kparams_solve_allreduce(sess, add_dst, rank, n_ranks, true, is_row_bcast, is_shard_ok, &kparams)) {
HEX_VERBOSE("ggml-hex: %s skip ALLREDUCE_ADD fusion: solver failed\n", htp_session_name(sess));
return false;
}
const bool scatter_ok = kparams.n_dsts > 1;
kparams.mode = scatter_ok ? HTP_ALLREDUCE_SHARDED_FANOUT : HTP_ALLREDUCE_FULL;
for (uint32_t r = 0; r < n_ranks; r++) {
const ggml_tensor * ar_src = prev.inputs[r];
if (!htp_tensors_overlap(add_dst, ar_src)) continue;
if (scatter_ok && r == rank) continue;
HEX_VERBOSE("ggml-hex: %s skip ALLREDUCE_ADD fusion: dst overlaps allreduce src %u\n", htp_session_name(sess), r);
return false;
}
prev.opcode = HTP_OP_ALLREDUCE_ADD;
prev.inputs.push_back(res_tensor);
if (kparams.mode != HTP_ALLREDUCE_SHARDED_FANOUT) {
prev.outputs = { add_dst };
}
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
static bool fuse_rms_norm_mul(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != HTP_OP_RMS_NORM) return false;
const ggml_tensor * weight = nullptr;
if (!htp_match_consumer(prev, cur, /*commutative=*/ true, &weight)) return false;
const ggml_tensor * src0 = prev.src0();
const ggml_tensor * dst = cur.dst();
if (src0->type != GGML_TYPE_F32 || src0->ne[0] != weight->ne[0] || !htp_same_shape_and_contiguity(prev.dst(), dst)) return false;
if (htp_inputs_overlap_unsafe(prev, dst, weight)) return false;
const bool is_row_bcast = (weight->ne[1] == 1 && weight->ne[2] == 1 && weight->ne[3] == 1);
const bool is_same_shape = ggml_are_same_shape(src0, weight);
if (!is_row_bcast && !is_same_shape) return false;
struct htp_unary_kernel_params kparams;
if (!htp_kparams_solve_rms_norm_mul(sess, src0, weight, dst, &kparams)) {
HEX_VERBOSE("ggml-hex: %s skip RMS_NORM_MUL fusion: VTCM needed (%d) > budget (%zu)\n",
htp_session_name(sess), kparams.vtcm_size, htp_session_vtcm_size(sess));
return false;
}
prev.opcode = HTP_OP_RMS_NORM_MUL;
prev.inputs = { src0, weight };
prev.outputs = { dst };
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
static bool fuse_rms_norm_scale(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
GGML_UNUSED(sess);
if (prev.opcode != HTP_OP_RMS_NORM && prev.opcode != HTP_OP_RMS_NORM_MUL) return false;
if (!htp_match_consumer(prev, cur, /*commutative=*/ false)) return false;
const ggml_tensor * src0 = prev.src0();
const ggml_tensor * dst = cur.dst();
if (src0->type != GGML_TYPE_F32 || !htp_same_shape_and_contiguity(prev.dst(), dst)) return false;
if (htp_inputs_overlap_unsafe(prev, dst)) return false;
float scale = 0.0f;
float bias = 0.0f;
memcpy(&scale, (const float *) cur.params + 0, sizeof(float));
memcpy(&bias, (const float *) cur.params + 1, sizeof(float));
if (bias != 0.0f || scale == 0.0f) return false;
float prev_scale = 0.0f;
memcpy(&prev_scale, &prev.params[1], sizeof(float));
if (prev_scale != 0.0f) {
scale *= prev_scale;
}
memcpy(&prev.params[1], &scale, sizeof(float));
prev.outputs[0] = dst;
prev.fused.push_back(cur.node);
return true;
}
static bool fuse_mul_mat_add(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != HTP_OP_MUL_MAT) return false;
const ggml_tensor * src2 = nullptr;
if (!htp_match_consumer(prev, cur, /*commutative=*/ true, &src2)) return false;
if (src2->type != GGML_TYPE_F32) return false;
const ggml_tensor * src0 = prev.src0();
const ggml_tensor * src1 = prev.src1();
const ggml_tensor * dst = cur.dst();
if (!ggml_are_same_shape(prev.dst(), dst)) return false;
const auto * orig_kparams = prev.kparams<htp_mm_kernel_params>();
struct htp_mm_kernel_params kparams;
if (!htp_kparams_solve_matmul_add(sess, src0, src1, src2, dst, &kparams) ||
orig_kparams->collapse != kparams.collapse) {
return false;
}
const int src1_nrows = src1->ne[1] * src1->ne[2] * src1->ne[3];
if (kparams.n_hmx == 0 && src1_nrows != 1) return false;
if (kparams.n_hmx > 0 && orig_kparams->n_hmx > 0) {
if (kparams.m_chunk < orig_kparams->m_chunk ||
kparams.n_chunk < orig_kparams->n_chunk ||
kparams.n_act_threads < orig_kparams->n_act_threads) {
HEX_VERBOSE("ggml-hex: %s skip MUL_MAT_ADD fusion: HMX efficiency reduced (m %d->%d, n %d->%d, th %d->%d)\n",
htp_session_name(sess), orig_kparams->m_chunk, kparams.m_chunk,
orig_kparams->n_chunk, kparams.n_chunk,
orig_kparams->n_act_threads, kparams.n_act_threads);
return false;
}
}
prev.opcode = HTP_OP_MUL_MAT_ADD;
prev.inputs = { src0, src1, src2 };
prev.outputs = { dst };
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
static bool fuse_mul_mat_nx(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != HTP_OP_MUL_MAT && prev.opcode != HTP_OP_MUL_MAT_NX) return false;
const uint32_t curr_n = (uint32_t) prev.outputs.size();
if (curr_n >= HTP_OP_MAX_OUTPUTS || curr_n + 1 >= HTP_OP_MAX_INPUTS) return false;
const ggml_tensor * w0 = prev.inputs[0];
const ggml_tensor * x = prev.inputs[curr_n];
const ggml_tensor * w_in = cur.src0();
const ggml_tensor * x_in = cur.src1();
const ggml_tensor * d_in = cur.dst();
auto * orig_kparams = prev.kparams<htp_mm_kernel_params>();
const auto * cur_kparams = cur.kparams<htp_mm_kernel_params>();
if (x_in != x || w_in->type != w0->type || w_in->ne[0] != w0->ne[0] ||
w0->ne[2] != 1 || w0->ne[3] != 1 || w_in->ne[2] != 1 || w_in->ne[3] != 1 ||
htp_tensor_is_tiled(w_in) != htp_tensor_is_tiled(w0) ||
orig_kparams->n_hmx != cur_kparams->n_hmx) {
return false;
}
const bool collapse = orig_kparams->collapse && htp_matmul_can_collapse(w_in, x, d_in);
if ((x->ne[2] > 1 || x->ne[3] > 1) && !collapse) return false;
if (prev.opcode == HTP_OP_MUL_MAT_NX) {
orig_kparams->n_weights = curr_n + 1;
} else {
struct htp_mm_kernel_params kparams;
if (collapse) {
const ggml_tensor x_collapsed = htp_tensor_collapse_rows(x);
if (!htp_kparams_solve_mmnx(sess, w0, &x_collapsed, curr_n + 1, &kparams)) return false;
kparams.collapse = 1;
} else if (!htp_kparams_solve_mmnx(sess, w0, x, curr_n + 1, &kparams)) {
return false;
}
if (!is_supported_mul_mat_nx_kernel(w0, &kparams)) return false;
prev.set_kparams(kparams);
prev.opcode = HTP_OP_MUL_MAT_NX;
}
prev.inputs.insert(prev.inputs.begin() + curr_n, w_in);
prev.outputs.push_back(d_in);
prev.fused.push_back(cur.node);
return true;
}
static bool fuse_mul_mat_id_nx(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != HTP_OP_MUL_MAT_ID && prev.opcode != HTP_OP_MUL_MAT_ID_NX) return false;
const uint32_t curr_n = (uint32_t) prev.outputs.size();
if (curr_n >= HTP_OP_MAX_OUTPUTS || curr_n + 2 >= HTP_OP_MAX_INPUTS) return false;
const ggml_tensor * w0 = prev.inputs[0];
const ggml_tensor * x = prev.inputs[curr_n];
const ggml_tensor * ids = prev.inputs[curr_n + 1];
const ggml_tensor * w_in = cur.src0();
const ggml_tensor * x_in = cur.src1();
const ggml_tensor * ids_in = cur.node->src[2];
const ggml_tensor * d_in = cur.dst();
auto * orig_kparams = prev.kparams<htp_mm_kernel_params>();
const auto * cur_kparams = cur.kparams<htp_mm_kernel_params>();
if (x_in != x || ids_in != ids || w_in->type != w0->type ||
w_in->ne[0] != w0->ne[0] || w_in->ne[2] != w0->ne[2] ||
htp_tensor_is_tiled(w_in) != htp_tensor_is_tiled(w0) ||
orig_kparams->n_hmx != cur_kparams->n_hmx) {
return false;
}
struct htp_mm_kernel_params kparams;
if (d_in->nb[1] == prev.node->nb[1]) {
kparams = *orig_kparams;
kparams.n_weights = curr_n + 1;
} else if (!htp_kparams_solve_mmidnx(sess, w0, x, d_in, curr_n + 1, &kparams)) {
return false;
}
if (!is_supported_mul_mat_id_nx_kernel(w0, &kparams)) return false;
prev.opcode = HTP_OP_MUL_MAT_ID_NX;
prev.inputs.insert(prev.inputs.begin() + curr_n, w_in);
prev.outputs.push_back(d_in);
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
static bool fuse_gdn_cpy(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
GGML_UNUSED(sess);
if (prev.opcode != HTP_OP_GATED_DELTA_NET || prev.outputs.size() != 1) return false;
const ggml_tensor * gdn_out = prev.dst();
const ggml_tensor * cpy_node = cur.node;
const ggml_tensor * cpy_src = cur.src0();
const ggml_tensor * cpy_dst = cur.dst();
if (gdn_out->type != GGML_TYPE_F32 || cpy_src->type != GGML_TYPE_F32 || cpy_dst->type != GGML_TYPE_F32) return false;
if ((gdn_out->flags & GGML_TENSOR_FLAG_OUTPUT) || (cpy_node->flags & GGML_TENSOR_FLAG_OUTPUT)) return false;
const ggml_tensor * v = prev.node->src[2];
if (!v) return false;
const int64_t S_v = v->ne[0];
const int64_t H = v->ne[1];
const int64_t n_tokens = v->ne[2];
const int64_t n_seqs = v->ne[3];
const int64_t K = ggml_get_op_params_i32(prev.node, 0);
const size_t tail_off = (size_t) S_v * H * n_tokens * n_seqs * sizeof(float);
const int64_t D = S_v * S_v * H;
const int64_t n_written = std::min<int64_t>(n_tokens, K);
if (cpy_src->op != GGML_OP_VIEW || !htp_same_tensor_data(cpy_src->view_src, gdn_out) ||
cpy_src->view_offs != tail_off || !ggml_is_contiguous(cpy_src)) {
return false;
}
if (cpy_dst->ne[0] != D || cpy_dst->ne[1] != n_seqs || cpy_dst->ne[2] != n_written || !ggml_is_contiguous(cpy_dst)) {
return false;
}
prev.outputs.push_back(cpy_dst);
prev.fused.push_back(cur.node);
return true;
}
static bool fuse_ssm_conv_silu(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
GGML_UNUSED(sess);
if (prev.opcode != HTP_OP_SSM_CONV) return false;
auto * kparams = prev.kparams<htp_ssm_conv_kernel_params>();
if (kparams->silu) return false;
if (!htp_match_consumer(prev, cur, /*commutative=*/ false)) return false;
const ggml_tensor * conv_dst = prev.dst();
const ggml_tensor * dst = cur.dst();
if (!ggml_are_same_layout(conv_dst, dst)) return false;
if (htp_tensors_overlap(dst, prev.src0()) || htp_tensors_overlap(dst, prev.src1())) return false;
kparams->silu = 1;
prev.outputs[0] = dst;
prev.fused.push_back(cur.node);
return true;
}
static bool fuse_repeat_get_rows(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != HTP_OP_REPEAT) return false;
if (!htp_match_consumer(prev, cur, /*commutative=*/ false)) return false;
const ggml_tensor * repeat_out = prev.dst();
const ggml_tensor * repeat_src0 = prev.src0();
const ggml_tensor * gr_src1 = cur.src1();
const ggml_tensor * gr_dst = cur.dst();
if (repeat_src0->ne[0] != repeat_out->ne[0] || repeat_src0->ne[1] != repeat_out->ne[1]) return false;
if (repeat_src0->type != repeat_out->type) return false;
struct htp_get_rows_kernel_params kparams;
if (!htp_kparams_solve_repeat_get_rows(sess, repeat_src0, gr_src1, gr_dst, &kparams) || kparams.vtcm_size == 0) return false;
prev.opcode = HTP_OP_GET_ROWS;
prev.inputs = { repeat_src0, gr_src1 };
prev.outputs = { gr_dst };
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
static bool fuse_unary_mul_glu(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
htp_op_code glu_op = HTP_OP_INVALID;
switch (prev.opcode) {
case HTP_OP_UNARY_SILU: glu_op = HTP_OP_GLU_SWIGLU; break;
case HTP_OP_UNARY_GELU: glu_op = HTP_OP_GLU_GEGLU; break;
case HTP_OP_UNARY_GELU_QUICK: glu_op = HTP_OP_GLU_GEGLU_QUICK; break;
case HTP_OP_UNARY_GELU_ERF: glu_op = HTP_OP_GLU_GEGLU_ERF; break;
case HTP_OP_UNARY_RELU: glu_op = HTP_OP_GLU_REGLU; break;
case HTP_OP_UNARY_SIGMOID: glu_op = HTP_OP_GLU_SIGMOID; break;
default: return false;
}
const ggml_tensor * up = nullptr;
if (!htp_match_consumer(prev, cur, /*commutative=*/ true, &up)) return false;
const ggml_tensor * gate = prev.src0();
const ggml_tensor * dst = cur.dst();
if (htp_inputs_overlap_unsafe(prev, dst, up)) return false;
struct htp_glu_kernel_params kparams;
if (!htp_kparams_solve_unary_mul_glu(sess, glu_op, gate, up, dst, &kparams)) return false;
prev.opcode = glu_op;
prev.inputs = { gate, up };
prev.outputs = { dst };
prev.fused.push_back(cur.node);
memset(prev.params, 0, sizeof(prev.params));
prev.set_kparams(kparams);
return true;
}
static bool fuse_mul_mul_scalar(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != HTP_OP_MUL || prev.inputs.size() != 2) return false;
const auto * k0 = prev.kparams<htp_binary_kernel_params>();
const auto * k1 = cur.kparams<htp_binary_kernel_params>();
if (k0->kernel_type != HTP_BINARY_KERNEL_SCALAR || k1->kernel_type != HTP_BINARY_KERNEL_SCALAR) return false;
if (k0->src1_strided || k1->src1_strided) return false;
const ggml_tensor * src2 = nullptr;
if (!htp_match_consumer(prev, cur, /*commutative=*/ false, &src2)) return false;
const ggml_tensor * src1 = prev.src1();
const ggml_tensor * dst = cur.dst();
if (!ggml_are_same_shape(src1, src2) || !htp_same_shape_and_contiguity(prev.dst(), dst)) return false;
if (htp_inputs_overlap_unsafe(prev, dst, src2)) return false;
const size_t vtcm_size = htp_session_vtcm_size(sess);
struct htp_binary_kernel_params kparams = *k0;
kparams.src2_size = kparams.src1_size;
kparams.rows_per_buffer = 0;
if (kparams.src1_size > 65536 || kparams.src1_size + kparams.src2_size > vtcm_size) return false;
struct htp_binary_vtcm_layout L;
htp_binary_vtcm_layout_build(&L, &kparams, vtcm_size);
if (L.rows_per_buffer == 0 || L.total_bytes > vtcm_size) return false;
kparams.rows_per_buffer = L.rows_per_buffer;
kparams.vtcm_size = L.total_bytes;
prev.inputs.push_back(src2);
prev.outputs[0] = dst;
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
static bool fuse_binary_nx(const ggml_hexagon_session * sess, htp_opnode & prev, const htp_opnode & cur) {
if (prev.opcode != cur.opcode) return false;
const uint32_t curr_n = (uint32_t) prev.inputs.size();
if (curr_n < 2 || curr_n >= HTP_OP_MAX_INPUTS) return false;
const auto * k0 = prev.kparams<htp_binary_kernel_params>();
const auto * k1 = cur.kparams<htp_binary_kernel_params>();
const bool k0_ok = (k0->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE) ||
(k0->kernel_type == HTP_BINARY_KERNEL_CHUNKED && !k0->is_scalar);
const bool k1_ok = (k1->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE) ||
(k1->kernel_type == HTP_BINARY_KERNEL_CHUNKED && !k1->is_scalar);
if (!k0_ok || !k1_ok) return false;
const bool is_comm = (cur.opcode == HTP_OP_ADD || cur.opcode == HTP_OP_MUL);
const ggml_tensor * new_src = nullptr;
if (!htp_match_consumer(prev, cur, is_comm, &new_src)) return false;
const ggml_tensor * src0 = prev.inputs[0];
const ggml_tensor * dst = cur.dst();
if (!ggml_are_same_shape(src0, prev.inputs[1]) ||
!ggml_are_same_shape(src0, new_src) ||
!htp_same_shape_and_contiguity(prev.dst(), dst)) {
return false;
}
if (htp_inputs_overlap_unsafe(prev, dst, new_src)) return false;
const size_t vtcm_size = htp_session_vtcm_size(sess);
struct htp_binary_kernel_params kparams = *k0;
struct htp_binary_vtcm_layout L;
memset(&L, 0, sizeof(L));
const uint32_t n_srcs = curr_n + 1;
if (k0->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE || k1->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE) {
if (k0->kernel_type != HTP_BINARY_KERNEL_SAME_SHAPE) {
kparams = *k1;
}
kparams.n_srcs = (uint8_t) n_srcs;
kparams.rows_per_buffer = 0;
auto check_split = [&](const ggml_tensor * t) {
if (src0->ne[2] > 1 && t->nb[2] != t->ne[1] * t->nb[1]) kparams.split_at_ne01 = 1;
if (src0->ne[3] > 1 && t->nb[3] != t->ne[2] * t->nb[2]) kparams.split_at_ne02 = 1;
};
for (const auto * in : prev.inputs) check_split(in);
check_split(new_src);
check_split(dst);
htp_binary_vtcm_layout_build(&L, &kparams, vtcm_size);
}
if (L.rows_per_buffer == 0 || L.total_bytes == 0 || L.total_bytes > vtcm_size) {
bool all_contig = ggml_is_contiguous(new_src) && ggml_is_contiguous(dst);
for (const auto * in : prev.inputs) {
all_contig = all_contig && ggml_is_contiguous(in);
}
if (!all_contig) return false;
const uint32_t total_elems = (uint32_t) ggml_nelements(src0);
const uint32_t elem_size = (uint32_t) ggml_type_size(src0->type);
const uint32_t max_threads = htp_session_n_threads(sess);
if (!htp_binary_solve_chunked(&L, &kparams, total_elems, elem_size, max_threads, n_srcs, false, vtcm_size)) {
return false;
}
}
kparams.rows_per_buffer = L.rows_per_buffer;
kparams.vtcm_size = (uint32_t) L.total_bytes;
prev.inputs.push_back(new_src);
prev.outputs[0] = dst;
prev.fused.push_back(cur.node);
prev.set_kparams(kparams);
return true;
}
bool htp_fusion_can_stack(const struct ggml_tensor * a) {
if (!a || !a->src[0] || !a->src[1]) return false;
switch (a->op) {
case GGML_OP_MUL_MAT:
if (!htp_fusion_enabled(HTP_FUSE_MUL_MAT_NX)) return false;
if (htp_is_hadamard(a)) return false;
if (a->src[0]->ne[2] != 1 || a->src[0]->ne[3] != 1) return false;
return ggml_is_quantized(a->src[0]->type);
case GGML_OP_MUL_MAT_ID:
if (!htp_fusion_enabled(HTP_FUSE_MUL_MAT_ID_NX)) return false;
return a->src[2] != nullptr && ggml_is_quantized(a->src[0]->type);
default:
return false;
}
}
bool htp_fusion_can_stack(const struct ggml_tensor * a, const struct ggml_tensor * b) {
if (!htp_fusion_can_stack(b) || a->op != b->op || a->src[1] != b->src[1]) {
return false;
}
if (a->op == GGML_OP_MUL_MAT_ID && a->src[2] != b->src[2]) {
return false;
}
const ggml_tensor * w0 = a->src[0];
const ggml_tensor * w1 = b->src[0];
return w0->type == w1->type && w0->ne[0] == w1->ne[0] && w0->ne[2] == w1->ne[2];
}
int htp_fusion_max(const struct ggml_cgraph * graph, int idx) {
const int n = graph->n_nodes;
const ggml_op op0 = graph->nodes[idx]->op;
if (op0 != GGML_OP_ADD && op0 != GGML_OP_NORM && op0 != GGML_OP_RMS_NORM) {
return 1;
}
enum ggml_op ops[HTP_OP_MAX_FUSED];
ops[0] = op0;
int f = idx + 1;
while (f < n && f < idx + HTP_OP_MAX_FUSED) {
const ggml_op op = graph->nodes[f]->op;
if (op != GGML_OP_ADD && op != GGML_OP_MUL && op != GGML_OP_SCALE &&
op != GGML_OP_NORM && op != GGML_OP_RMS_NORM) {
break;
}
ops[f - idx] = op;
f++;
}
f -= idx;
for (; f > 1; f--) {
if (ggml_can_fuse(graph, idx, ops, f)) {
break;
}
}
return f;
}
void htp_fusion_tag_graph(struct ggml_cgraph * graph) {
for (int i = 0; i < graph->n_nodes; i++) {
auto * extra = (htp_tensor_extra *) graph->nodes[i]->extra;
if (!extra) continue;
extra->flags &= ~HTP_TENSOR_FUSEABLE;
const ggml_op op = graph->nodes[i]->op;
if ((op == GGML_OP_RMS_NORM || op == GGML_OP_SCALE || op == GGML_OP_REPEAT ||
op == GGML_OP_UNARY || op == GGML_OP_ADD || op == GGML_OP_SUB ||
op == GGML_OP_MUL || op == GGML_OP_DIV || op == GGML_OP_MUL_MAT_ID ||
op == GGML_OP_SSM_CONV ||
(op == GGML_OP_MUL_MAT && !htp_is_hadamard(graph->nodes[i]))) &&
ggml_node_has_n_uses(graph, i, 1)) {
extra->flags |= HTP_TENSOR_FUSEABLE;
}
}
}
bool htp_fusion_try_fuse(const struct ggml_hexagon_session * sess, struct htp_opnode & prev, const struct htp_opnode & cur) {
if (!opt_opfusion) return false;
switch (cur.opcode) {
case HTP_OP_ADD:
return (htp_fusion_enabled(HTP_FUSE_ALLREDUCE_ADD) && fuse_allreduce_add(sess, prev, cur)) ||
(htp_fusion_enabled(HTP_FUSE_MUL_MAT_ADD) && fuse_mul_mat_add(sess, prev, cur)) ||
(htp_fusion_enabled(HTP_FUSE_BINARY_NX) && fuse_binary_nx(sess, prev, cur));
case HTP_OP_MUL:
return (htp_fusion_enabled(HTP_FUSE_RMS_NORM_MUL) && fuse_rms_norm_mul(sess, prev, cur)) ||
(htp_fusion_enabled(HTP_FUSE_UNARY_MUL_GLU) && fuse_unary_mul_glu(sess, prev, cur)) ||
(htp_fusion_enabled(HTP_FUSE_MUL_MUL_SCALAR) && fuse_mul_mul_scalar(sess, prev, cur)) ||
(htp_fusion_enabled(HTP_FUSE_BINARY_NX) && fuse_binary_nx(sess, prev, cur));
case HTP_OP_SUB:
case HTP_OP_DIV:
return htp_fusion_enabled(HTP_FUSE_BINARY_NX) && fuse_binary_nx(sess, prev, cur);
case HTP_OP_SCALE:
return htp_fusion_enabled(HTP_FUSE_RMS_NORM_SCALE) && fuse_rms_norm_scale(sess, prev, cur);
case HTP_OP_UNARY_SILU:
return htp_fusion_enabled(HTP_FUSE_SSM_CONV_SILU) && fuse_ssm_conv_silu(sess, prev, cur);
case HTP_OP_GET_ROWS:
return htp_fusion_enabled(HTP_FUSE_REPEAT_GET_ROWS) && fuse_repeat_get_rows(sess, prev, cur);
case HTP_OP_CPY:
return htp_fusion_enabled(HTP_FUSE_GDN_CPY) && fuse_gdn_cpy(sess, prev, cur);
case HTP_OP_MUL_MAT:
return htp_fusion_enabled(HTP_FUSE_MUL_MAT_NX) && fuse_mul_mat_nx(sess, prev, cur);
case HTP_OP_MUL_MAT_ID:
return htp_fusion_enabled(HTP_FUSE_MUL_MAT_ID_NX) && fuse_mul_mat_id_nx(sess, prev, cur);
default:
return false;
}
}
+33
View File
@@ -0,0 +1,33 @@
#ifndef HTP_FUSION_H
#define HTP_FUSION_H
#include "htp-common.h"
enum htp_fusion_flags {
HTP_FUSE_ALLREDUCE_ADD = (1 << 1), // 2
HTP_FUSE_RMS_NORM_MUL = (1 << 2), // 4
HTP_FUSE_MUL_MAT_ADD = (1 << 3), // 8
HTP_FUSE_MUL_MAT_NX = (1 << 4), // 16
HTP_FUSE_MUL_MAT_ID_NX = (1 << 5), // 32
HTP_FUSE_GDN_CPY = (1 << 6), // 64
HTP_FUSE_REPEAT_GET_ROWS = (1 << 7), // 128
HTP_FUSE_UNARY_MUL_GLU = (1 << 8), // 256
HTP_FUSE_MUL_MUL_SCALAR = (1 << 9), // 512
HTP_FUSE_BINARY_NX = (1 << 10), // 1024
HTP_FUSE_RMS_NORM_SCALE = (1 << 11), // 2048
HTP_FUSE_SSM_CONV_SILU = (1 << 12), // 4096
};
static inline bool htp_fusion_enabled(int flag) {
if (opt_opfusion <= 0) return false;
if (opt_opfusion == 1) return true; // 1 enables all
return (opt_opfusion & flag) != 0;
}
bool htp_fusion_can_stack(const struct ggml_tensor * a);
bool htp_fusion_can_stack(const struct ggml_tensor * a, const struct ggml_tensor * b);
int htp_fusion_max(const struct ggml_cgraph * graph, int idx);
void htp_fusion_tag_graph(struct ggml_cgraph * graph);
bool htp_fusion_try_fuse(const struct ggml_hexagon_session * sess, struct htp_opnode & prev, const struct htp_opnode & cur);
#endif // HTP_FUSION_H
File diff suppressed because it is too large Load Diff
+123
View File
@@ -0,0 +1,123 @@
#ifndef HTP_KPARAMS_H
#define HTP_KPARAMS_H
#include "htp-common.h"
#include "htp/allreduce-ops.h"
#include "htp/argsort-ops.h"
#include "htp/binary-ops.h"
#include "htp/concat-ops.h"
#include "htp/cpy-ops.h"
#include "htp/cumsum-ops.h"
#include "htp/diag-ops.h"
#include "htp/fill-ops.h"
#include "htp/flash-attn-ops.h"
#include "htp/gated-delta-net-ops.h"
#include "htp/get-rows-ops.h"
#include "htp/glu-ops.h"
#include "htp/im2col-ops.h"
#include "htp/matmul-ops.h"
#include "htp/pad-ops.h"
#include "htp/pool-ops.h"
#include "htp/repeat-ops.h"
#include "htp/roll-ops.h"
#include "htp/rope-ops.h"
#include "htp/set-rows-ops.h"
#include "htp/softmax-ops.h"
#include "htp/solve-tri-ops.h"
#include "htp/ssm-conv.h"
#include "htp/sum-rows-ops.h"
#include "htp/unary-ops.h"
#include <type_traits>
#include <utility>
bool htp_rows_stride(const int64_t * ne, const size_t * nb, size_t * stride);
bool htp_matmul_can_collapse(const struct ggml_tensor * src0, const struct ggml_tensor * src1, const struct ggml_tensor * dst);
ggml_tensor htp_tensor_collapse_rows(const struct ggml_tensor * t);
template <typename... Args>
auto htp_kparams_type(bool (*)(Args...)) -> std::remove_pointer_t<std::remove_reference_t<decltype((std::declval<Args>(), ...))>>;
template <auto SolveFn, typename... Args>
static inline bool htp_kparams_check(Args &&... args) {
decltype(htp_kparams_type(SolveFn)) kparams;
return SolveFn(std::forward<Args>(args)..., &kparams);
}
bool htp_kparams_solve(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * op,
void * kparams = nullptr
);
static inline bool htp_kparams_check(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * op
) {
return htp_kparams_solve(sess, op, nullptr);
}
bool htp_kparams_solve_allreduce(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * dst,
uint32_t rank,
uint32_t n_ranks,
bool has_add,
bool is_row_bcast,
bool is_shard_ok,
struct htp_allreduce_kernel_params * kparams
);
bool htp_kparams_solve_rms_norm_mul(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * src0,
const struct ggml_tensor * src1,
const struct ggml_tensor * dst,
struct htp_unary_kernel_params * kparams
);
bool htp_kparams_solve_matmul_add(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * src0,
const struct ggml_tensor * src1,
const struct ggml_tensor * src2,
const struct ggml_tensor * dst,
struct htp_mm_kernel_params * kparams
);
bool htp_kparams_solve_mmnx(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * src0,
const struct ggml_tensor * act,
int32_t n_weights,
struct htp_mm_kernel_params * kparams
);
bool htp_kparams_solve_mmidnx(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * src0,
const struct ggml_tensor * act,
const struct ggml_tensor * dst,
int32_t n_weights,
struct htp_mm_kernel_params * kparams
);
bool htp_kparams_solve_repeat_get_rows(
const struct ggml_hexagon_session * sess,
const struct ggml_tensor * src0,
const struct ggml_tensor * src1,
const struct ggml_tensor * dst,
struct htp_get_rows_kernel_params * kparams
);
bool htp_kparams_solve_unary_mul_glu(
const struct ggml_hexagon_session * sess,
uint32_t op,
const struct ggml_tensor * src0,
const struct ggml_tensor * src1,
const struct ggml_tensor * dst,
struct htp_glu_kernel_params * kparams
);
#endif // HTP_KPARAMS_H
+260
View File
@@ -0,0 +1,260 @@
#include "htp-opnode.h"
#include "htp/allreduce-ops.h"
#include "htp/argsort-ops.h"
#include "htp/binary-ops.h"
#include "htp/cumsum-ops.h"
#include "htp/diag-ops.h"
#include "htp/fill-ops.h"
#include "htp/flash-attn-ops.h"
#include "htp/gated-delta-net-ops.h"
#include "htp/get-rows-ops.h"
#include "htp/glu-ops.h"
#include "htp/matmul-ops.h"
#include "htp/pad-ops.h"
#include "htp/repeat-ops.h"
#include "htp/roll-ops.h"
#include "htp/softmax-ops.h"
#include "htp/solve-tri-ops.h"
#include "htp/ssm-conv.h"
#include "htp/sum-rows-ops.h"
#include "htp/unary-ops.h"
#include <stdio.h>
std::string htp_opnode::name() const {
switch (opcode) {
case HTP_OP_MDEV_GROUP: return "MDEV_GROUP";
case HTP_OP_CPY_FENCE: return "CPY+FENCE";
case HTP_OP_FENCE: return (node && node->op_params[1] == 0) ? "FENCE_WAIT" : "FENCE_SIGNAL";
case HTP_OP_ALLREDUCE: return "ALLREDUCE";
case HTP_OP_ALLREDUCE_ADD: return "ALLREDUCE+ADD";
case HTP_OP_HADAMARD: return "MUL_MAT_HADAMARD";
case HTP_OP_MUL_MAT_NX: return "MUL_MAT_NX";
case HTP_OP_MUL_MAT_ID_NX: return "MUL_MAT_ID_NX";
case HTP_OP_ADD:
case HTP_OP_SUB:
case HTP_OP_MUL:
case HTP_OP_DIV:
if (!fused.empty()) {
const auto * kp = kparams<htp_binary_kernel_params>();
if (kp->kernel_type != HTP_BINARY_KERNEL_SCALAR) {
switch (opcode) {
case HTP_OP_ADD: return "ADD_NX";
case HTP_OP_SUB: return "SUB_NX";
case HTP_OP_MUL: return "MUL_NX";
case HTP_OP_DIV: return "DIV_NX";
default: break;
}
}
}
break;
default:
break;
}
if (!node) {
return "";
}
if (htp_is_hadamard(node)) {
return "MUL_MAT_HADAMARD";
}
std::string res = ggml_op_desc(node);
for (const auto * t : fused) {
res += "+";
res += ggml_op_desc(t);
}
return res;
}
static const char * format_tensor_name(const struct ggml_tensor * t) {
return t ? t->name : "NONE";
}
static std::string format_tensor_dims(const struct ggml_tensor * t) {
if (!t) {
return "NONE";
}
char buf[64];
if (t->ne[2] == 1 && t->ne[3] == 1) {
snprintf(buf, sizeof(buf), "%d:%d", (int) t->ne[0], (int) t->ne[1]);
} else {
snprintf(buf, sizeof(buf), "%d:%d:%d:%d", (int) t->ne[0], (int) t->ne[1], (int) t->ne[2], (int) t->ne[3]);
}
return buf;
}
static const char * format_tensor_type(const struct ggml_tensor * t) {
return t ? ggml_type_name(t->type) : "NONE";
}
static std::string format_tensor_strides(const struct ggml_tensor * t) {
if (!t) {
return "NONE";
}
char buf[64];
const char * c = ggml_is_contiguous(t) ? "" : "!";
if (t->ne[2] == 1 && t->ne[3] == 1) {
snprintf(buf, sizeof(buf), "%zu:%zu%s", (size_t) t->nb[0], (size_t) t->nb[1], c);
} else {
snprintf(buf, sizeof(buf), "%zu:%zu:%zu:%zu%s", (size_t) t->nb[0], (size_t) t->nb[1], (size_t) t->nb[2], (size_t) t->nb[3], c);
}
return buf;
}
static const char * format_tensor_buff(const struct ggml_tensor * t) {
if (t && t->buffer) {
return ggml_backend_buffer_name(t->buffer);
}
return "NONE";
}
template <typename Fn>
static std::string format_op_tensors(const htp_opnode & node, Fn fn) {
std::string res;
const auto & inputs = node.get_inputs();
const auto & outputs = node.get_outputs();
if (!inputs.empty()) {
for (size_t i = 0; i < inputs.size(); i++) {
if (i > 0) res += " x ";
res += fn(inputs[i]);
}
res += " -> ";
}
if (outputs.empty()) {
res += fn(node.dst());
} else {
for (size_t i = 0; i < outputs.size(); i++) {
if (i > 0) res += " x ";
res += fn(outputs[i]);
}
}
return res;
}
static std::string format_kernel_params(const htp_opnode & node) {
char str[128];
const size_t max_size = sizeof(str);
if (node.opcode == HTP_OP_MUL_MAT || node.opcode == HTP_OP_MUL_MAT_ID ||
node.opcode == HTP_OP_MUL_MAT_NX || node.opcode == HTP_OP_MUL_MAT_ID_NX ||
node.opcode == HTP_OP_MUL_MAT_ADD) {
const auto * kparams = node.kparams<htp_mm_kernel_params>();
const char * path = "unknown";
int32_t type = kparams->kernel_type;
if (type == HTP_MM_KERNEL_HMX_2D || type == HTP_MM_KERNEL_HMX_BATCHED) {
path = (kparams->tile_size > 0) ? "hmx-tiled" : "hmx-flat";
} else if (type == HTP_MM_KERNEL_HVX_F16_F16_VTCM || type == HTP_MM_KERNEL_HVX_F32_F32_VTCM ||
type == HTP_MM_KERNEL_HVX_BF16_F32_VTCM) {
path = "hvx-flat";
} else if (type == HTP_MM_KERNEL_HVX_QUANT_ROW || type == HTP_MM_KERNEL_HVX_QUANT_BLOCK) {
path = "hvx-tiled";
}
snprintf(str, max_size, "%s vtcm %d", path, (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_FLASH_ATTN_EXT) {
const auto * kparams = node.kparams<htp_fa_kernel_params>();
const char * path = "unknown";
int32_t type = kparams->kernel_type;
if (type == HTP_FA_KERNEL_HMX) {
path = kparams->u.hmx.pipeline ? "hmx-pipe" : "hmx-seq";
} else if (type == HTP_FA_KERNEL_HVX) {
path = "hvx";
}
snprintf(str, max_size, "%s vtcm %d", path, (int) kparams->vtcm_size);
} else if (htp_op_is_unary(node.opcode)) {
const auto * kparams = node.kparams<htp_unary_kernel_params>();
snprintf(str, max_size, "%s vtcm %d", kparams->col_tile ? "wide-row" : "row-block", (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_MDEV_GROUP && node.node) {
snprintf(str, max_size, "idx %d count %d", (int) node.node->op_params[0], (int) node.dst()->ne[1]);
} else if ((node.opcode == HTP_OP_FENCE || node.opcode == HTP_OP_CPY_FENCE) && node.node) {
snprintf(str, max_size, "seq 0x%x", (uint32_t) node.node->op_params[0]);
} else if (node.opcode == HTP_OP_ALLREDUCE && node.node) {
snprintf(str, max_size, "seq 0x%x -> 0x%x", (uint32_t) node.node->op_params[0], (uint32_t) node.node->op_params[1]);
} else if (node.opcode == HTP_OP_SSM_CONV) {
const auto * kparams = node.kparams<htp_ssm_conv_kernel_params>();
snprintf(str, max_size, "%s vtcm %d", kparams->n_t == 1 ? "decode" : "prefill", (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_SOFTMAX) {
const auto * kparams = node.kparams<htp_softmax_kernel_params>();
snprintf(str, max_size, "k%d nth %d vtcm %d", (int) kparams->kernel_type, (int) kparams->n_threads, (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_GATED_DELTA_NET) {
const auto * kparams = node.kparams<htp_gdn_kernel_params>();
const char * path = (kparams->kernel_type == HTP_GDN_KERNEL_HMX_CHUNKED) ? "hmx-chunked" : "hvx-recurrent";
snprintf(str, max_size, "%s-%s vtcm %u", path, kparams->kda ? "kda" : "scalar",
(unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_MUL || node.opcode == HTP_OP_ADD || node.opcode == HTP_OP_ADD_ID ||
node.opcode == HTP_OP_SUB || node.opcode == HTP_OP_DIV) {
const auto * kparams = node.kparams<htp_binary_kernel_params>();
snprintf(str, max_size, "vtcm %u", (unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_ARGSORT || node.opcode == HTP_OP_TOP_K) {
const auto * kparams = node.kparams<htp_sort_kernel_params>();
snprintf(str, max_size, "%s nth %d nchk %d chk %d vtcm %d",
node.opcode == HTP_OP_TOP_K ? "top_k" : "argsort",
(int) kparams->n_threads, (int) kparams->n_chunks,
(int) kparams->chunk_elems, (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_GET_ROWS) {
const auto * kparams = node.kparams<htp_get_rows_kernel_params>();
const char * ktype_str = "unknown";
switch (kparams->kernel_type) {
case HTP_GET_ROWS_KERNEL_SAMETYPE: ktype_str = "sametype"; break;
case HTP_GET_ROWS_KERNEL_TILED: ktype_str = "tiled"; break;
case HTP_GET_ROWS_KERNEL_FLAT: ktype_str = "flat"; break;
}
snprintf(str, max_size, "%s%s vtcm %u", ktype_str, kparams->n_threads > 1 ? "-multi" : "", (unsigned int) kparams->vtcm_size);
} else if (htp_op_is_glu(node.opcode)) {
const auto * kparams = node.kparams<htp_glu_kernel_params>();
snprintf(str, max_size, "nth %d vtcm %u", (int) kparams->n_threads, (unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_PAD) {
const auto * kparams = node.kparams<htp_pad_kernel_params>();
snprintf(str, max_size, "k%d nth %d vtcm %u", (int) kparams->kernel_type, (int) kparams->n_threads, (unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_CUMSUM) {
const auto * kparams = node.kparams<htp_cumsum_kernel_params>();
snprintf(str, max_size, "%s nth %d vtcm %u", kparams->use_dma ? "dma" : "hvx", (int) kparams->n_threads, (unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_FILL) {
const auto * kparams = node.kparams<htp_fill_kernel_params>();
snprintf(str, max_size, "%s nth %d", kparams->kernel_type == HTP_FILL_KERNEL_CONTIGUOUS ? "contig" : "strided", (int) kparams->n_threads);
} else if (node.opcode == HTP_OP_ROLL) {
const auto * kparams = node.kparams<htp_roll_kernel_params>();
snprintf(str, max_size, "k%d nth %d", (int) kparams->kernel_type, (int) kparams->n_threads);
} else if (node.opcode == HTP_OP_DIAG) {
const auto * kparams = node.kparams<htp_diag_kernel_params>();
snprintf(str, max_size, "%s nth %d vtcm %u", kparams->use_dma ? "dma" : "hvx", (int) kparams->n_threads, (unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_SOLVE_TRI) {
const auto * kparams = node.kparams<htp_solve_tri_kernel_params>();
snprintf(str, max_size, "%s nth %d", kparams->batched ? "batched" : "chunked", (int) kparams->n_threads);
} else {
snprintf(str, max_size, "----");
}
return str;
}
static void append_section(std::string & res, const std::string & sec) {
if (!res.empty()) {
res += "|";
}
res += sec;
}
std::string htp_format_tensor(const ggml_tensor * t, uint32_t flags) {
std::string res;
if (flags & HTP_OPFMT_NAMES) append_section(res, format_tensor_name(t));
if (flags & HTP_OPFMT_DIMS) append_section(res, format_tensor_dims(t));
if (flags & HTP_OPFMT_TYPES) append_section(res, format_tensor_type(t));
if (flags & HTP_OPFMT_STRIDES) append_section(res, format_tensor_strides(t));
if (flags & HTP_OPFMT_BUFFS) append_section(res, format_tensor_buff(t));
return res;
}
std::string htp_format_op(const htp_opnode & node, uint32_t flags) {
std::string res;
if (flags & HTP_OPFMT_OP) append_section(res, node.name());
if (flags & HTP_OPFMT_NAMES) append_section(res, format_op_tensors(node, format_tensor_name));
if (flags & HTP_OPFMT_DIMS) append_section(res, format_op_tensors(node, format_tensor_dims));
if (flags & HTP_OPFMT_TYPES) append_section(res, format_op_tensors(node, format_tensor_type));
if (flags & HTP_OPFMT_STRIDES) append_section(res, format_op_tensors(node, format_tensor_strides));
if (flags & HTP_OPFMT_BUFFS) append_section(res, format_op_tensors(node, format_tensor_buff));
if (flags & HTP_OPFMT_KPARAMS) append_section(res, format_kernel_params(node));
return res;
}
+114 -365
View File
@@ -1,38 +1,74 @@
#ifndef HTP_OPNODE_H
#define HTP_OPNODE_H
#define GGML_COMMON_IMPL_CPP
#include "ggml-backend-impl.h"
#include "ggml-common.h"
#include "ggml-impl.h"
#include "htp/htp-ops.h"
#include <algorithm>
#include <cstring>
#include <initializer_list>
#include <memory>
#include <string>
#include <vector>
#include <memory>
#include <stdio.h>
#include "htp-ops.h"
#include "htp/matmul-ops.h"
#include "htp/flash-attn-ops.h"
#include "htp/unary-ops.h"
#include "htp/binary-ops.h"
#include "htp/allreduce-ops.h"
#include "htp/ssm-conv.h"
#include "htp/gated-delta-net-ops.h"
#include "htp/softmax-ops.h"
#include "htp/argsort-ops.h"
#include "htp/get-rows-ops.h"
#define HTP_OP_MAX_FUSED 16
// local std::inplace_vector replacement
template <typename T, size_t MAX_N>
struct htp_opvec {
T data[MAX_N] {};
size_t n = 0;
htp_opvec() = default;
htp_opvec(std::initializer_list<T> init) {
GGML_ASSERT(init.size() <= MAX_N);
for (const auto & v : init) {
data[n++] = v;
}
}
size_t size() const { return n; }
bool empty() const { return n == 0; }
void clear() { n = 0; }
T * begin() { return data; }
T * end() { return data + n; }
const T * begin() const { return data; }
const T * end() const { return data + n; }
T & back() { return data[n - 1]; }
const T & back() const { return data[n - 1]; }
T & operator[](size_t i) { return data[i]; }
const T & operator[](size_t i) const { return data[i]; }
void push_back(T val) {
GGML_ASSERT(n < MAX_N);
data[n++] = val;
}
void insert(T * pos, T val) {
GGML_ASSERT(n < MAX_N);
for (T * p = data + n; p > pos; --p) {
*p = *(p - 1);
}
*pos = val;
n++;
}
};
static inline bool htp_is_hadamard(const struct ggml_tensor * t) {
return t && t->op == GGML_OP_MUL_MAT && ggml_get_op_params_i32(t, 1) == GGML_HINT_SRC0_IS_HADAMARD;
}
struct htp_opnode {
ggml_tensor * node { nullptr };
htp_op_code opcode { HTP_OP_INVALID };
int32_t kernel_params[HTP_OP_MAX_KERN_PARAMS] {0};
const ggml_tensor * node { nullptr };
htp_op_code opcode { HTP_OP_INVALID };
int32_t params[HTP_OP_MAX_PARAMS] {0};
int32_t kernel_params[HTP_OP_MAX_KERN_PARAMS] {0};
std::vector<ggml_tensor *> fused;
std::vector<std::shared_ptr<ggml_tensor>> dummy;
std::vector<std::shared_ptr<ggml_tensor>> dummy;
std::vector<const ggml_tensor *> inputs;
std::vector<const ggml_tensor *> outputs;
std::string name;
htp_opvec<const ggml_tensor *, HTP_OP_MAX_FUSED> fused;
htp_opvec<const ggml_tensor *, HTP_OP_MAX_INPUTS> inputs;
htp_opvec<const ggml_tensor *, HTP_OP_MAX_OUTPUTS> outputs;
int n_active_src(const ggml_tensor * t) const {
if (!t) return 0;
@@ -44,34 +80,36 @@ struct htp_opnode {
return 0;
}
void init(ggml_tensor * node) {
void init(const ggml_tensor * node) {
static_assert(sizeof(this->params) == sizeof(this->node->op_params), "params size mismatch");
this->node = node;
if (this->node) {
if (this->node->op == GGML_OP_MUL_MAT &&
ggml_get_op_params_i32(this->node, 1) == GGML_HINT_SRC0_IS_HADAMARD) {
this->name = "MUL_MAT_HADAMARD";
this->inputs.push_back(this->node->src[1]);
} else {
this->name = ggml_op_desc(this->node);
if (!node) return;
// Build inputs (preserving optional nullptrs)
int n_inputs = n_active_src(this->node);
this->inputs.resize(n_inputs, nullptr);
for (int i = 0; i < n_inputs; i++) {
this->inputs[i] = this->node->src[i];
}
memcpy(this->params, this->node->op_params, sizeof(this->params));
// Build inputs (preserving optional nullptrs)
if (htp_is_hadamard(this->node)) {
this->inputs.push_back(this->node->src[1]);
} else {
int n_inputs = n_active_src(this->node);
for (int i = 0; i < n_inputs; i++) {
this->inputs.push_back(this->node->src[i]);
}
// Build outputs
this->outputs.push_back(this->dst());
}
// Build outputs
this->outputs.push_back(this->dst());
}
htp_opnode(htp_op_code opcode = HTP_OP_INVALID, ggml_tensor * node = nullptr) : opcode(opcode) {
htp_opnode(htp_op_code opcode = HTP_OP_INVALID, const ggml_tensor * node = nullptr) : opcode(opcode) {
init(node);
}
htp_opnode(const ggml_tensor * node) : opcode(HTP_OP_INVALID) {
init(node);
}
ggml_op op() const { return node->op; }
const ggml_tensor * src0() const { return node->src[0]; }
const ggml_tensor * src1() const { return node->src[1]; }
const ggml_tensor * dst() const { return outputs.empty() ? node : outputs.back(); }
@@ -81,343 +119,54 @@ struct htp_opnode {
return dummy.back().get();
}
void add_fused(ggml_tensor * t, bool extra_dst = false) {
fused.push_back(t);
name += "+";
name += ggml_op_desc(t);
if (extra_dst) {
outputs.push_back(t);
} else {
outputs.clear();
outputs.push_back(t);
}
// Remove the newly fused intermediate output tensor t from inputs (if it was there)
inputs.erase(std::remove(inputs.begin(), inputs.end(), t), inputs.end());
// Append new inputs from t, preserving middle nullptrs
int n_inputs = n_active_src(t);
for (int i = 0; i < n_inputs; i++) {
const auto * src = t->src[i];
if (!src) {
inputs.push_back(nullptr);
} else if (src != node &&
std::find(fused.begin(), fused.end(), src) == fused.end() &&
std::find(inputs.begin(), inputs.end(), src) == inputs.end()) {
inputs.push_back(src);
}
}
}
const std::vector<const ggml_tensor *> & get_inputs() const {
const htp_opvec<const ggml_tensor *, HTP_OP_MAX_INPUTS> & get_inputs() const {
return inputs;
}
const std::vector<const ggml_tensor *> & get_outputs() const {
const htp_opvec<const ggml_tensor *, HTP_OP_MAX_OUTPUTS> & get_outputs() const {
return outputs;
}
std::string op_name() const {
return name;
template <typename T>
T * kparams() {
static_assert(sizeof(T) <= sizeof(kernel_params), "kparams size exceeds HTP_OP_MAX_KERN_PARAMS");
static_assert(alignof(T) <= alignof(int32_t), "kparams alignment exceeds int32_t");
return reinterpret_cast<T *>(kernel_params);
}
bool is_empty() const {
return ggml_op_is_empty(node->op);
template <typename T>
const T * kparams() const {
static_assert(sizeof(T) <= sizeof(kernel_params), "kparams size exceeds HTP_OP_MAX_KERN_PARAMS");
static_assert(alignof(T) <= alignof(int32_t), "kparams alignment exceeds int32_t");
return reinterpret_cast<const T *>(kernel_params);
}
bool stackable() const {
switch (this->op()) {
case GGML_OP_MUL_MAT:
if (ggml_get_op_params_i32(this->node, 1) == GGML_HINT_SRC0_IS_HADAMARD) {
return false;
}
return ggml_is_quantized(this->src0()->type);
case GGML_OP_MUL_MAT_ID:
return ggml_is_quantized(this->src0()->type);
default:
return false;
}
template <typename T>
void set_kparams(const T & kp) {
static_assert(sizeof(T) <= sizeof(kernel_params), "kparams size exceeds HTP_OP_MAX_KERN_PARAMS");
static_assert(alignof(T) <= alignof(int32_t), "kparams alignment exceeds int32_t");
memcpy(kernel_params, &kp, sizeof(T));
}
bool same_input(const htp_opnode& n) const {
return n.src1() == this->src1();
}
std::string name() const;
};
struct htp_opformat {
char strides[64 * GGML_MAX_SRC];
char dims[64 * GGML_MAX_SRC];
char types[16 * GGML_MAX_SRC];
char buffs[64 * GGML_MAX_SRC];
char names[64 * GGML_MAX_SRC];
char kparams[128];
enum htp_opformat_flags {
HTP_OPFMT_OP = (1 << 0),
HTP_OPFMT_NAMES = (1 << 1),
HTP_OPFMT_DIMS = (1 << 2),
HTP_OPFMT_TYPES = (1 << 3),
HTP_OPFMT_STRIDES = (1 << 4),
HTP_OPFMT_BUFFS = (1 << 5),
HTP_OPFMT_KPARAMS = (1 << 6),
int format_tensor_dims(char * str, size_t max_size, const struct ggml_tensor * t) {
if (!t) {
return snprintf(str, max_size, "NONE");
}
if (t->ne[2] == 1 && t->ne[3] == 1) {
return snprintf(str, max_size, "%d:%d", (int) t->ne[0], (int) t->ne[1]);
} else {
return snprintf(str, max_size, "%d:%d:%d:%d", (int) t->ne[0], (int) t->ne[1], (int) t->ne[2], (int) t->ne[3]);
}
}
void format_op_dims(char * str, size_t max_size, const htp_opnode & node) {
char * p = str;
char * p_end = str + max_size;
auto inputs = node.get_inputs();
if (!inputs.empty()) {
p += std::min((size_t)format_tensor_dims(p, p_end - p, inputs[0]), (size_t)(p_end - p));
for (size_t i = 1; i < inputs.size(); i++) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " x "), (size_t)(p_end - p));
}
if (p < p_end) {
p += std::min((size_t)format_tensor_dims(p, p_end - p, inputs[i]), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " -> "), (size_t)(p_end - p));
}
}
char self[64];
format_tensor_dims(self, sizeof(self), node.dst());
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", self), (size_t)(p_end - p));
}
}
int format_tensor_strides(char * str, size_t max_size, const struct ggml_tensor * t) {
if (!t) {
return snprintf(str, max_size, "NONE");
}
const char * c = ggml_is_contiguous(t) ? "" : "!";
if (t->ne[2] == 1 && t->ne[3] == 1) {
return snprintf(str, max_size, "%zu:%zu%s", (size_t) t->nb[0], (size_t) t->nb[1], c);
} else {
return snprintf(str, max_size, "%zu:%zu:%zu:%zu%s", (size_t) t->nb[0], (size_t) t->nb[1], (size_t) t->nb[2], (size_t) t->nb[3], c);
}
}
void format_op_strides(char * str, size_t max_size, const htp_opnode & node) {
char * p = str;
char * p_end = str + max_size;
auto inputs = node.get_inputs();
if (!inputs.empty()) {
p += std::min((size_t)format_tensor_strides(p, p_end - p, inputs[0]), (size_t)(p_end - p));
for (size_t i = 1; i < inputs.size(); i++) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " x "), (size_t)(p_end - p));
}
if (p < p_end) {
p += std::min((size_t)format_tensor_strides(p, p_end - p, inputs[i]), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " -> "), (size_t)(p_end - p));
}
}
char self[64];
format_tensor_strides(self, sizeof(self), node.dst());
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", self), (size_t)(p_end - p));
}
}
void format_op_types(char * str, size_t max_size, const htp_opnode & node) {
char * p = str;
char * p_end = str + max_size;
auto inputs = node.get_inputs();
if (!inputs.empty()) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", inputs[0] ? ggml_type_name(inputs[0]->type) : "NONE"), (size_t)(p_end - p));
}
for (size_t i = 1; i < inputs.size(); i++) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " x "), (size_t)(p_end - p));
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", inputs[i] ? ggml_type_name(inputs[i]->type) : "NONE"), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " -> "), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", ggml_type_name(node.dst()->type)), (size_t)(p_end - p));
}
}
const char * tensor_buff_name(const struct ggml_tensor * t) {
if (t && t->buffer) {
return ggml_backend_buffer_name(t->buffer);
}
return "NONE";
}
void format_op_buffs(char * str, size_t max_size, const htp_opnode & node) {
char * p = str;
char * p_end = str + max_size;
auto inputs = node.get_inputs();
if (!inputs.empty()) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", tensor_buff_name(inputs[0])), (size_t)(p_end - p));
}
for (size_t i = 1; i < inputs.size(); i++) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " x "), (size_t)(p_end - p));
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", tensor_buff_name(inputs[i])), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " -> "), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", tensor_buff_name(node.dst())), (size_t)(p_end - p));
}
}
void format_op_names(char * str, size_t max_size, const htp_opnode & node) {
char * p = str;
char * p_end = str + max_size;
auto inputs = node.get_inputs();
if (!inputs.empty()) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", inputs[0] ? inputs[0]->name : "NONE"), (size_t)(p_end - p));
}
for (size_t i = 1; i < inputs.size(); i++) {
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " x "), (size_t)(p_end - p));
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", inputs[i] ? inputs[i]->name : "NONE"), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, " -> "), (size_t)(p_end - p));
}
}
if (p < p_end) {
p += std::min((size_t)snprintf(p, p_end - p, "%s", node.dst()->name), (size_t)(p_end - p));
}
}
void format_kernel_params(char * str, size_t max_size, const htp_opnode & node) {
if (node.opcode == HTP_OP_MUL_MAT || node.opcode == HTP_OP_MUL_MAT_ID ||
node.opcode == HTP_OP_MUL_MAT_NX || node.opcode == HTP_OP_MUL_MAT_ID_NX ||
node.opcode == HTP_OP_MUL_MAT_ADD) {
const auto * kparams = (const struct htp_mm_kernel_params *) node.kernel_params;
const char * path = "unknown";
int32_t type = kparams->kernel_type;
if (type == HTP_MM_KERNEL_HMX_2D || type == HTP_MM_KERNEL_HMX_BATCHED) {
path = (kparams->tile_size > 0) ? "hmx-tiled" : "hmx-flat";
} else if (type == HTP_MM_KERNEL_HVX_F16_F16_VTCM || type == HTP_MM_KERNEL_HVX_F32_F32_VTCM ||
type == HTP_MM_KERNEL_HVX_BF16_F32_VTCM) {
path = "hvx-flat";
} else if (type == HTP_MM_KERNEL_HVX_QUANT_ROW || type == HTP_MM_KERNEL_HVX_QUANT_BLOCK) {
path = "hvx-tiled";
}
snprintf(str, max_size, "%s vtcm %d", path, (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_FLASH_ATTN_EXT) {
const auto * kparams = (const struct htp_fa_kernel_params *) node.kernel_params;
const char * path = "unknown";
int32_t type = kparams->kernel_type;
if (type == HTP_FA_KERNEL_HMX) {
path = kparams->u.hmx.pipeline ? "hmx-pipe" : "hmx-seq";
} else if (type == HTP_FA_KERNEL_HVX) {
path = "hvx";
}
snprintf(str, max_size, "%s vtcm %d", path, (int) kparams->vtcm_size);
} else if (htp_op_is_unary(node.opcode)) {
const auto * kparams = (const struct htp_unary_kernel_params *) node.kernel_params;
snprintf(str, max_size, "%s vtcm %d", kparams->col_tile ? "wide-row" : "row-block", (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_MDEV_GROUP && node.node) {
snprintf(str, max_size, "idx %d count %d", (int) node.node->op_params[0], (int) node.dst()->ne[1]);
} else if ((node.opcode == HTP_OP_FENCE || node.opcode == HTP_OP_CPY_FENCE) && node.node) {
snprintf(str, max_size, "seq 0x%x", (uint32_t) node.node->op_params[0]);
} else if (node.opcode == HTP_OP_ALLREDUCE && node.node) {
snprintf(str, max_size, "seq 0x%x -> 0x%x", (uint32_t) node.node->op_params[0], (uint32_t) node.node->op_params[1]);
} else if (node.opcode == HTP_OP_SSM_CONV) {
const auto * kparams = (const struct htp_ssm_conv_kernel_params *) node.kernel_params;
snprintf(str, max_size, "%s vtcm %d", kparams->n_t == 1 ? "decode" : "prefill", (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_SOFTMAX) {
const auto * kparams = (const struct htp_softmax_kernel_params *) node.kernel_params;
snprintf(str, max_size, "k%d nth %d vtcm %d", (int) kparams->kernel_id, (int) kparams->n_threads, (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_GATED_DELTA_NET) {
const auto * kparams = (const struct htp_gdn_kernel_params *) node.kernel_params;
const char * path = (kparams->kernel_type == HTP_GDN_KERNEL_HMX_CHUNKED) ? "hmx-chunked" : "hvx-recurrent";
snprintf(str, max_size, "%s-%s vtcm %u", path, kparams->kda ? "kda" : "scalar",
(unsigned int) (kparams->vtcm_size ? kparams->vtcm_size : kparams->vtcm_per_thread * kparams->n_threads));
} else if (node.opcode == HTP_OP_MUL || node.opcode == HTP_OP_ADD || node.opcode == HTP_OP_ADD_ID ||
node.opcode == HTP_OP_SUB || node.opcode == HTP_OP_DIV) {
const auto * kparams = (const struct htp_binary_kernel_params *) node.kernel_params;
snprintf(str, max_size, "vtcm %u", (unsigned int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_ARGSORT || node.opcode == HTP_OP_TOP_K) {
const auto * kparams = (const struct htp_sort_kernel_params *) node.kernel_params;
snprintf(str, max_size, "%s nth %d nchk %d chk %d vtcm %d",
node.opcode == HTP_OP_TOP_K ? "top_k" : "argsort",
(int) kparams->n_threads, (int) kparams->n_chunks,
(int) kparams->chunk_elems, (int) kparams->vtcm_size);
} else if (node.opcode == HTP_OP_GET_ROWS) {
const auto * kparams = (const struct htp_get_rows_kernel_params *) node.kernel_params;
const char * ktype_str = "unknown";
switch (kparams->kernel_type) {
case HTP_GET_ROWS_KERNEL_SAMETYPE: ktype_str = "sametype"; break;
case HTP_GET_ROWS_KERNEL_TILED: ktype_str = "tiled"; break;
case HTP_GET_ROWS_KERNEL_FLAT: ktype_str = "flat"; break;
}
snprintf(str, max_size, "%s%s vtcm %u", ktype_str, kparams->n_threads > 1 ? "-multi" : "", (unsigned int) kparams->vtcm_size);
} else {
snprintf(str, max_size, "----");
}
}
void format(const htp_opnode & node) {
format_op_dims(dims, sizeof(dims), node);
format_op_strides(strides, sizeof(strides), node);
format_op_types(types, sizeof(types), node);
format_op_buffs(buffs, sizeof(buffs), node);
format_op_names(names, sizeof(names), node);
format_kernel_params(kparams, sizeof(kparams), node);
}
htp_opformat() {
strides[0] = '\0';
dims[0] = '\0';
types[0] = '\0';
buffs[0] = '\0';
names[0] = '\0';
kparams[0] = '\0';
}
htp_opformat(const htp_opnode & node) { format(node); }
HTP_OPFMT_EXEC = HTP_OPFMT_OP | HTP_OPFMT_NAMES | HTP_OPFMT_DIMS | HTP_OPFMT_TYPES | HTP_OPFMT_STRIDES | HTP_OPFMT_BUFFS | HTP_OPFMT_KPARAMS,
HTP_OPFMT_SUPP = HTP_OPFMT_OP | HTP_OPFMT_NAMES | HTP_OPFMT_DIMS | HTP_OPFMT_TYPES | HTP_OPFMT_STRIDES | HTP_OPFMT_BUFFS,
HTP_OPFMT_PROF = HTP_OPFMT_OP | HTP_OPFMT_NAMES | HTP_OPFMT_DIMS | HTP_OPFMT_TYPES | HTP_OPFMT_STRIDES | HTP_OPFMT_KPARAMS,
HTP_OPFMT_TENSOR = HTP_OPFMT_NAMES | HTP_OPFMT_DIMS | HTP_OPFMT_TYPES | HTP_OPFMT_STRIDES,
};
std::string htp_format_op(const htp_opnode & node, uint32_t flags = HTP_OPFMT_EXEC);
std::string htp_format_tensor(const ggml_tensor * t, uint32_t flags = HTP_OPFMT_TENSOR);
#endif // HTP_OPNODE_H
+1 -1
View File
@@ -28,7 +28,7 @@ add_library(${HTP_LIB} SHARED
unary-ops.c
sum-rows-ops.c
softmax-ops.c
act-ops.c
glu-ops.c
rope-ops.c
set-rows-ops.c
get-rows-ops.c
+7 -1
View File
@@ -32,6 +32,7 @@ static inline size_t htp_allreduce_vtcm_buffer_count(
}
struct htp_allreduce_kernel_params {
uint8_t kernel_type;
int32_t rank;
int32_t n_ranks;
int32_t n_threads;
@@ -39,7 +40,6 @@ struct htp_allreduce_kernel_params {
int32_t elems_per_thread; // 1D: nelem_per_thread, 2D: nrows_per_thread
int32_t vtcm_size_per_thread;
int32_t vtcm_size;
int32_t kernel_type;
int32_t ne0;
int32_t ne1;
int32_t row_size_aligned;
@@ -50,6 +50,12 @@ struct htp_allreduce_kernel_params {
int32_t mode; // enum htp_allreduce_mode: FULL or SHARDED_FANOUT
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_allreduce_kernel_params) <= 128, "htp_allreduce_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_allreduce_kernel_params) <= 128, "htp_allreduce_kernel_params is too large for kernel_params blob");
#endif
#ifdef __cplusplus
}
#endif
+100 -97
View File
@@ -453,7 +453,10 @@ static void merge_runs(
struct htp_sort_chunk_ctx {
struct htp_ops_context * octx;
const struct htp_sort_kernel_params * kparams;
uint8_t * vtcm_base;
uint8_t * phase1_base;
size_t phase1_slot_size;
float * merge_values;
int32_t * merge_indices;
uint32_t real_count[HTP_MAX_NTHREADS];
};
@@ -462,26 +465,27 @@ static void htp_sort_chunk_job(unsigned int n, unsigned int i, void * data) {
struct htp_ops_context * octx = cctx->octx;
const struct htp_sort_kernel_params * kparams = cctx->kparams;
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
uint32_t ne00 = (uint32_t) kparams->ne00;
uint32_t ne00 = src0->ne[0];
uint32_t chunk_base = i * chunk_elems;
uint32_t real_count = (chunk_base < ne00) ? MIN(chunk_elems, ne00 - chunk_base) : 0;
cctx->real_count[i] = real_count;
uint8_t * spad = cctx->vtcm_base + (size_t) kparams->phase1_slot_size * i;
uint8_t * spad = cctx->phase1_base + cctx->phase1_slot_size * i;
float * values_buf = (float *) spad;
int32_t * indices_buf = (int32_t *) (spad + chunk_elems * sizeof(float));
float * merge_values = (float *) (cctx->vtcm_base + kparams->merge_values_off);
int32_t * merge_indices = (int32_t *) (cctx->vtcm_base + kparams->merge_indices_off);
float * merge_values = cctx->merge_values;
int32_t * merge_indices = cctx->merge_indices;
struct htp_thread_trace * tr = &octx->ctx->trace[i];
const dma_addr_t src_addr = src0->data + (size_t) chunk_base * sizeof(float);
if (kparams->is_top_k) {
uint32_t k = (uint32_t) kparams->k;
uint32_t k = dst->ne[0];
uint32_t local_k = MIN(k, chunk_elems);
if (real_count == 0) {
@@ -559,17 +563,17 @@ static void htp_argsort_merge_l1_job(unsigned int n, unsigned int i, void * data
uint32_t count0 = cctx->real_count[c0];
uint32_t count1 = cctx->real_count[c1];
size_t slot_size = (size_t) kparams->phase1_slot_size;
size_t slot_size = cctx->phase1_slot_size;
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
const float * val0 = (const float *) (cctx->vtcm_base + slot_size * c0);
const int32_t * idx0 = (const int32_t *) (cctx->vtcm_base + slot_size * c0 + chunk_elems * sizeof(float));
const float * val1 = (const float *) (cctx->vtcm_base + slot_size * c1);
const int32_t * idx1 = (const int32_t *) (cctx->vtcm_base + slot_size * c1 + chunk_elems * sizeof(float));
const float * val0 = (const float *) (cctx->phase1_base + slot_size * c0);
const int32_t * idx0 = (const int32_t *) (cctx->phase1_base + slot_size * c0 + chunk_elems * sizeof(float));
const float * val1 = (const float *) (cctx->phase1_base + slot_size * c1);
const int32_t * idx1 = (const int32_t *) (cctx->phase1_base + slot_size * c1 + chunk_elems * sizeof(float));
uint32_t out_offset = (2 * i) * chunk_elems;
float * out_val = (float *) (cctx->vtcm_base + kparams->merge_values_off) + out_offset;
int32_t * out_idx = (int32_t *) (cctx->vtcm_base + kparams->merge_indices_off) + out_offset;
float * out_val = cctx->merge_values + out_offset;
int32_t * out_idx = cctx->merge_indices + out_offset;
struct htp_thread_trace * tr = &cctx->octx->ctx->trace[i];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i);
@@ -587,21 +591,21 @@ static void htp_argsort_merge_l2_job(unsigned int n, unsigned int i, void * data
struct htp_sort_chunk_ctx * cctx = mctx->cctx;
const struct htp_sort_kernel_params * kparams = cctx->kparams;
size_t slot_size = (size_t) kparams->phase1_slot_size;
size_t slot_size = cctx->phase1_slot_size;
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
uint32_t off0 = (4 * i) * chunk_elems;
uint32_t off1 = (4 * i + 2) * chunk_elems;
const float * val0 = (const float *) (cctx->vtcm_base + kparams->merge_values_off) + off0;
const int32_t * idx0 = (const int32_t *) (cctx->vtcm_base + kparams->merge_indices_off) + off0;
const float * val1 = (const float *) (cctx->vtcm_base + kparams->merge_values_off) + off1;
const int32_t * idx1 = (const int32_t *) (cctx->vtcm_base + kparams->merge_indices_off) + off1;
const float * val0 = cctx->merge_values + off0;
const int32_t * idx0 = cctx->merge_indices + off0;
const float * val1 = cctx->merge_values + off1;
const int32_t * idx1 = cctx->merge_indices + off1;
uint32_t count0 = cctx->real_count[4*i + 0] + cctx->real_count[4*i + 1];
uint32_t count1 = cctx->real_count[4*i + 2] + cctx->real_count[4*i + 3];
uint8_t * slot_base = cctx->vtcm_base + (4 * i) * slot_size;
uint8_t * slot_base = cctx->phase1_base + (4 * i) * slot_size;
float * out_val = (float *) slot_base;
int32_t * out_idx = (int32_t *) (slot_base + 4 * chunk_elems * sizeof(float));
@@ -614,7 +618,10 @@ static void htp_argsort_merge_l2_job(unsigned int n, unsigned int i, void * data
struct htp_sort_multi_row_ctx {
struct htp_ops_context * octx;
const struct htp_sort_kernel_params * kparams;
uint8_t * vtcm_base;
uint8_t * phase1_base;
size_t phase1_slot_size;
uint32_t row_start;
uint32_t row_end;
uint32_t nrows_per_thread;
};
@@ -624,12 +631,18 @@ struct htp_tensor_row_coord {
uint32_t i03;
};
static inline struct htp_tensor_row_coord init_row_coord(uint32_t r, uint32_t ne01, uint32_t ne02) {
static inline struct htp_tensor_row_coord init_row_coord(
uint32_t r,
uint32_t ne01,
uint32_t ne02,
const struct fastdiv_values * div_ne01,
const struct fastdiv_values * div_ne01_ne02
) {
uint32_t ne01_ne02 = ne01 * ne02;
uint32_t i03 = (ne01_ne02 > 0) ? (r / ne01_ne02) : 0;
uint32_t rem = (ne01_ne02 > 0) ? (r % ne01_ne02) : 0;
uint32_t i02 = (ne01 > 0) ? (rem / ne01) : 0;
uint32_t i01 = (ne01 > 0) ? (rem % ne01) : 0;
uint32_t i03 = (ne01_ne02 > 0) ? fastdiv(r, div_ne01_ne02) : 0;
uint32_t rem = (ne01_ne02 > 0) ? (r - i03 * ne01_ne02) : 0;
uint32_t i02 = (ne01 > 0) ? fastdiv(rem, div_ne01) : 0;
uint32_t i01 = (ne01 > 0) ? (rem - i02 * ne01) : 0;
return (struct htp_tensor_row_coord){ i01, i02, i03 };
}
@@ -701,7 +714,7 @@ static void htp_sort_multi_row_job(unsigned int n, unsigned int ith, void * data
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
uint32_t ne00 = (uint32_t) kparams->ne00;
uint32_t ne00 = src0->ne[0];
uint32_t ne01 = src0->ne[1];
uint32_t ne02 = src0->ne[2];
@@ -713,16 +726,16 @@ static void htp_sort_multi_row_job(unsigned int n, unsigned int ith, void * data
uint32_t nb2 = dst->nb[2];
uint32_t nb3 = dst->nb[3];
uint32_t row_start = (uint32_t) kparams->row_start;
uint32_t row_end = (uint32_t) kparams->row_end;
uint32_t row_start = mctx->row_start;
uint32_t row_end = mctx->row_end;
uint32_t r_start = row_start + ith * mctx->nrows_per_thread;
uint32_t r_end = MIN(r_start + mctx->nrows_per_thread, row_end);
if (r_start >= r_end) return;
size_t spad_offset = ith * (size_t) (kparams->phase1_slot_size * kparams->n_slots);
uint8_t * thread_spad = mctx->vtcm_base + spad_offset;
size_t slot_size = (size_t) kparams->phase1_slot_size;
size_t slot_size = mctx->phase1_slot_size;
size_t spad_offset = ith * slot_size * (size_t) kparams->n_slots;
uint8_t * thread_spad = mctx->phase1_base + spad_offset;
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
float * values_buf = (float *) thread_spad;
@@ -732,14 +745,14 @@ static void htp_sort_multi_row_job(unsigned int n, unsigned int ith, void * data
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
bool is_top_k = kparams->is_top_k != 0;
uint32_t k = (uint32_t) kparams->k;
uint32_t k = dst->ne[0];
enum ggml_sort_order order = (enum ggml_sort_order) kparams->order;
const uint32_t src_bytes = ne00 * sizeof(float);
const uint32_t dst_bytes = (is_top_k ? k : ne00) * sizeof(int32_t);
if (kparams->n_slots == 2) {
struct htp_tensor_row_coord prime_coord = init_row_coord(r_start, ne01, ne02);
struct htp_tensor_row_coord prime_coord = init_row_coord(r_start, ne01, ne02, &kparams->div_ne01, &kparams->div_ne01_ne02);
for (uint32_t r = r_start, spad_idx = 0; r < r_end && spad_idx < 2; r++, spad_idx++) {
uint8_t * cur_spad = thread_spad + spad_idx * slot_size;
float * cur_values = (float *) cur_spad;
@@ -759,8 +772,8 @@ static void htp_sort_multi_row_job(unsigned int n, unsigned int ith, void * data
step_row_coord(&prime_coord, ne01, ne02);
}
struct htp_tensor_row_coord dst_coord = init_row_coord(r_start, ne01, ne02);
struct htp_tensor_row_coord next_src_coord = init_row_coord(r_start + 2, ne01, ne02);
struct htp_tensor_row_coord dst_coord = init_row_coord(r_start, ne01, ne02, &kparams->div_ne01, &kparams->div_ne01_ne02);
struct htp_tensor_row_coord next_src_coord = init_row_coord(r_start + 2, ne01, ne02, &kparams->div_ne01, &kparams->div_ne01_ne02);
for (uint32_t r = r_start; r < r_end; r++) {
uint32_t cur_slot = (r - r_start) & 1;
@@ -796,7 +809,7 @@ static void htp_sort_multi_row_job(unsigned int n, unsigned int ith, void * data
dma_queue_flush(dma_q);
} else {
struct htp_tensor_row_coord coord = init_row_coord(r_start, ne01, ne02);
struct htp_tensor_row_coord coord = init_row_coord(r_start, ne01, ne02, &kparams->div_ne01, &kparams->div_ne01_ne02);
for (uint32_t r = r_start; r < r_end; r++) {
dma_addr_t src_addr = src0->data + coord_offset(coord, nb01, nb02, nb03);
dma_addr_t dst_addr = dst->data + coord_offset(coord, nb1, nb2, nb3);
@@ -847,52 +860,39 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
uint32_t ne00 = src0->ne[0];
uint32_t k = dst->ne[0];
struct htp_sort_kernel_params kparams_local;
const struct htp_sort_kernel_params * kparams = (const struct htp_sort_kernel_params *) octx->kernel_params;
if (kparams->n_threads == 0) {
struct htp_sort_vtcm_layout layout;
if (!htp_sort_solve_layout(&layout, ne00, total_rows, k, octx->n_threads, octx->ctx->vtcm_size, is_top_k)) {
return HTP_STATUS_VTCM_TOO_SMALL;
}
memset(&kparams_local, 0, sizeof(kparams_local));
kparams_local.n_threads = (int32_t) layout.n_threads;
kparams_local.total_rows = (int32_t) total_rows;
kparams_local.row_start = (int32_t) row_start;
kparams_local.row_end = (int32_t) row_end;
kparams_local.ne00 = (int32_t) ne00;
kparams_local.k = (int32_t) k;
kparams_local.order = is_top_k ? GGML_SORT_ORDER_DESC : (int32_t) octx->op_params[0];
kparams_local.is_top_k = is_top_k ? 1 : 0;
kparams_local.use_dma = 1;
kparams_local.chunk_elems = (int32_t) layout.chunk_elems;
kparams_local.n_chunks = (int32_t) layout.n_chunks;
kparams_local.vtcm_size = (int32_t) layout.total_bytes;
kparams_local.phase1_slot_size = (int32_t) layout.phase1_slot_size;
kparams_local.merge_values_off = (int32_t) layout.merge_values_off;
kparams_local.merge_indices_off = (int32_t) layout.merge_indices_off;
kparams_local.merge_elems = (int32_t) layout.merge_elems;
kparams_local.n_slots = (int32_t) layout.n_slots;
kparams = &kparams_local;
} else if (octx->ctx->mdev.count > 1) {
memcpy(&kparams_local, kparams, sizeof(kparams_local));
kparams_local.row_start = (int32_t) row_start;
kparams_local.row_end = (int32_t) row_end;
kparams = &kparams_local;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
if (octx->ctx->vtcm_size < (size_t) kparams->vtcm_size) {
FARF(ERROR, "sort: VTCM size too small. Needed %d, have %zu", kparams->vtcm_size, octx->ctx->vtcm_size);
struct htp_sort_vtcm_layout layout;
htp_sort_vtcm_layout_build(&layout,
total_rows,
(uint32_t) kparams->chunk_elems,
(uint32_t) kparams->n_chunks,
(uint32_t) kparams->merge_elems,
(uint32_t) kparams->n_threads,
(uint32_t) kparams->n_slots);
if (octx->ctx->vtcm_size < layout.total_bytes) {
FARF(ERROR, "sort: VTCM size too small. Needed %zu, have %zu", layout.total_bytes, octx->ctx->vtcm_size);
return HTP_STATUS_VTCM_TOO_SMALL;
}
uint8_t * vtcm_base = (uint8_t *) octx->ctx->vtcm_base;
uint8_t * vtcm_base = (uint8_t *) octx->ctx->vtcm_base;
uint8_t * phase1_base = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, layout.off_phase1);
float * merge_values = VTCM_LAYOUT_PTR(float, vtcm_base, layout.off_merge_values);
int32_t * merge_indices = VTCM_LAYOUT_PTR(int32_t, vtcm_base, layout.off_merge_indices);
if (total_rows == 1 && kparams->n_chunks > 1) {
struct htp_sort_chunk_ctx cctx;
cctx.octx = octx;
cctx.kparams = kparams;
cctx.vtcm_base = vtcm_base;
cctx.octx = octx;
cctx.kparams = kparams;
cctx.phase1_base = phase1_base;
cctx.phase1_slot_size = layout.phase1_slot_size;
cctx.merge_values = merge_values;
cctx.merge_indices = merge_indices;
memset(cctx.real_count, 0, sizeof(cctx.real_count));
work_queue_run(octx->ctx->work_queue, htp_sort_chunk_job, &cctx, (uint32_t) kparams->n_chunks);
@@ -902,8 +902,8 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
uint32_t local_k = MIN(k, chunk_elems);
if (k == 1 && ne00 >= 128*1024) {
float * cand_vals = (float *) (vtcm_base + kparams->merge_values_off);
int32_t * cand_idxs = (int32_t *) (vtcm_base + kparams->merge_indices_off);
float * cand_vals = merge_values;
int32_t * cand_idxs = merge_indices;
float best_val = cand_vals[0];
int32_t best_idx = cand_idxs[0];
for (int32_t c = 1; c < kparams->n_chunks; c++) {
@@ -918,8 +918,8 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
}
uint32_t total_candidates = (uint32_t) kparams->n_chunks * local_k;
float * cand_vals = (float *) (vtcm_base + kparams->merge_values_off);
int32_t * cand_idxs = (int32_t *) (vtcm_base + kparams->merge_indices_off);
float * cand_vals = merge_values;
int32_t * cand_idxs = merge_indices;
uint32_t merge_elems = (uint32_t) kparams->merge_elems;
if (merge_elems > total_candidates) {
@@ -943,18 +943,18 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
struct htp_argsort_merge_l2_ctx l2ctx = { &cctx, asc };
work_queue_run(octx->ctx->work_queue, htp_argsort_merge_l2_job, &l2ctx, 2);
size_t slot_size = (size_t) kparams->phase1_slot_size;
size_t slot_size = layout.phase1_slot_size;
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
const float * val0 = (const float *) vtcm_base;
const int32_t * idx0 = (const int32_t *) (vtcm_base + 4 * chunk_elems * sizeof(float));
const float * val1 = (const float *) (vtcm_base + 4 * slot_size);
const int32_t * idx1 = (const int32_t *) (vtcm_base + 4 * slot_size + 4 * chunk_elems * sizeof(float));
const float * val0 = (const float *) phase1_base;
const int32_t * idx0 = (const int32_t *) (phase1_base + 4 * chunk_elems * sizeof(float));
const float * val1 = (const float *) (phase1_base + 4 * slot_size);
const int32_t * idx1 = (const int32_t *) (phase1_base + 4 * slot_size + 4 * chunk_elems * sizeof(float));
uint32_t n01 = cctx.real_count[0] + cctx.real_count[1] + cctx.real_count[2] + cctx.real_count[3];
uint32_t n23 = cctx.real_count[4] + cctx.real_count[5] + cctx.real_count[6] + cctx.real_count[7];
int32_t * final_idx = (int32_t *) (vtcm_base + kparams->merge_indices_off);
int32_t * final_idx = merge_indices;
struct htp_thread_trace * tr = &octx->ctx->trace[0];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, 0);
merge_runs(val0, idx0, n01, val1, idx1, n23, NULL, final_idx, asc);
@@ -968,27 +968,27 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
uint32_t n01 = cctx.real_count[0] + cctx.real_count[1];
uint32_t n23 = cctx.real_count[2] + cctx.real_count[3];
const float * val01 = (const float *) (vtcm_base + kparams->merge_values_off);
const int32_t * idx01 = (const int32_t *) (vtcm_base + kparams->merge_indices_off);
const float * val23 = (const float *) (vtcm_base + kparams->merge_values_off) + 2 * chunk_elems;
const int32_t * idx23 = (const int32_t *) (vtcm_base + kparams->merge_indices_off) + 2 * chunk_elems;
const float * val01 = merge_values;
const int32_t * idx01 = merge_indices;
const float * val23 = merge_values + 2 * chunk_elems;
const int32_t * idx23 = merge_indices + 2 * chunk_elems;
int32_t * final_idx = (int32_t *) vtcm_base;
int32_t * final_idx = (int32_t *) phase1_base;
struct htp_thread_trace * tr = &octx->ctx->trace[0];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, 0);
merge_runs(val01, idx01, n01, val23, idx23, n23, NULL, final_idx, asc);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, 0);
dma_sync_write(octx->ctx->dma[0], dst->data, final_idx, ne00 * sizeof(int32_t));
} else if (kparams->n_chunks == 2) {
size_t slot_size = (size_t) kparams->phase1_slot_size;
size_t slot_size = layout.phase1_slot_size;
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
const float * val0 = (const float *) (vtcm_base);
const int32_t * idx0 = (const int32_t *) (vtcm_base + chunk_elems * sizeof(float));
const float * val1 = (const float *) (vtcm_base + slot_size);
const int32_t * idx1 = (const int32_t *) (vtcm_base + slot_size + chunk_elems * sizeof(float));
const float * val0 = (const float *) (phase1_base);
const int32_t * idx0 = (const int32_t *) (phase1_base + chunk_elems * sizeof(float));
const float * val1 = (const float *) (phase1_base + slot_size);
const int32_t * idx1 = (const int32_t *) (phase1_base + slot_size + chunk_elems * sizeof(float));
int32_t * final_idx = (int32_t *) (vtcm_base + kparams->merge_indices_off);
int32_t * final_idx = merge_indices;
struct htp_thread_trace * tr = &octx->ctx->trace[0];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, 0);
merge_runs(val0, idx0, cctx.real_count[0], val1, idx1, cctx.real_count[1], NULL, final_idx, asc);
@@ -996,7 +996,7 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
dma_sync_write(octx->ctx->dma[0], dst->data, final_idx, ne00 * sizeof(int32_t));
} else {
uint32_t chunk_elems = (uint32_t) kparams->chunk_elems;
int32_t * final_idx = (int32_t *) (vtcm_base + chunk_elems * sizeof(float));
int32_t * final_idx = (int32_t *) (phase1_base + chunk_elems * sizeof(float));
dma_sync_write(octx->ctx->dma[0], dst->data, final_idx, ne00 * sizeof(int32_t));
}
}
@@ -1006,7 +1006,10 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
struct htp_sort_multi_row_ctx mctx;
mctx.octx = octx;
mctx.kparams = kparams;
mctx.vtcm_base = vtcm_base;
mctx.phase1_base = phase1_base;
mctx.phase1_slot_size = layout.phase1_slot_size;
mctx.row_start = row_start;
mctx.row_end = row_end;
uint32_t dst_row_bytes = (uint32_t) dst_row_size;
uint32_t rows_per_chunk = 0;
@@ -1014,13 +1017,13 @@ static int op_sort_common(struct htp_ops_context * octx, bool is_top_k) {
if (rows_per_chunk == 0) {
rows_per_chunk = 1;
}
uint32_t dr = (nrows + (uint32_t) kparams->n_threads - 1) / (uint32_t) kparams->n_threads;
uint32_t dr = fastdiv(nrows + octx->n_threads - 1, &octx->n_threads_div);
if (rows_per_chunk > 1) {
dr = hex_round_up(dr, rows_per_chunk);
}
mctx.nrows_per_thread = dr;
work_queue_run(octx->ctx->work_queue, htp_sort_multi_row_job, &mctx, (uint32_t) kparams->n_threads);
work_queue_run(octx->ctx->work_queue, htp_sort_multi_row_job, &mctx, octx->n_threads);
return HTP_STATUS_OK;
}
+58 -73
View File
@@ -7,33 +7,27 @@
#include <string.h>
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
struct htp_sort_kernel_params {
int32_t n_threads;
int32_t total_rows;
int32_t row_start;
int32_t row_end;
int32_t ne00;
int32_t k;
int32_t order; // GGML_SORT_ORDER_ASC (0) or GGML_SORT_ORDER_DESC (1)
int32_t is_top_k; // 1 if TOP_K, 0 if ARGSORT
int32_t use_dma; // 1 if DMA enabled
int32_t chunk_elems;
int32_t n_chunks;
int32_t vtcm_size;
int32_t phase1_slot_size;
int32_t merge_values_off;
int32_t merge_indices_off;
int32_t merge_elems;
int32_t n_slots;
int32_t pad[15];
uint32_t n_threads;
uint32_t order; // GGML_SORT_ORDER_ASC (0) or GGML_SORT_ORDER_DESC (1)
uint32_t is_top_k; // 1 if TOP_K, 0 if ARGSORT
uint32_t chunk_elems;
uint32_t n_chunks;
uint32_t vtcm_size;
uint32_t merge_elems;
uint32_t n_slots;
struct fastdiv_values div_ne01;
struct fastdiv_values div_ne01_ne02;
};
struct htp_sort_vtcm_layout {
size_t total_bytes;
size_t phase1_slot_size;
size_t merge_values_off;
size_t merge_indices_off;
size_t off_phase1;
size_t off_merge_values;
size_t off_merge_indices;
uint32_t chunk_elems;
uint32_t n_chunks;
uint32_t merge_elems;
@@ -41,6 +35,39 @@ struct htp_sort_vtcm_layout {
uint32_t n_slots;
};
static inline void htp_sort_vtcm_layout_build(
struct htp_sort_vtcm_layout * L,
uint32_t total_rows,
uint32_t chunk_elems,
uint32_t n_chunks,
uint32_t merge_elems,
uint32_t n_threads,
uint32_t n_slots) {
memset(L, 0, sizeof(*L));
L->chunk_elems = chunk_elems;
L->n_chunks = n_chunks;
L->merge_elems = merge_elems;
L->n_threads = n_threads;
L->n_slots = n_slots;
const size_t values_size = ((chunk_elems * sizeof(float)) + 127) & ~127;
const size_t indices_size = ((chunk_elems * sizeof(int32_t)) + 127) & ~127;
L->phase1_slot_size = ((values_size + indices_size) + 255) & ~255;
size_t off = 0;
if (total_rows > 1) {
VTCM_LAYOUT_ALLOC(off, off_phase1, L->phase1_slot_size * n_slots * n_threads);
} else {
VTCM_LAYOUT_ALLOC(off, off_phase1, L->phase1_slot_size * n_chunks * n_slots);
const size_t merge_values_size = ((merge_elems * sizeof(float)) + 127) & ~127;
const size_t merge_indices_size = ((merge_elems * sizeof(int32_t)) + 127) & ~127;
VTCM_LAYOUT_ALLOC_OPTIONAL(off, off_merge_values, merge_values_size, n_chunks > 1);
VTCM_LAYOUT_ALLOC_OPTIONAL(off, off_merge_indices, merge_indices_size, n_chunks > 1);
}
L->total_bytes = off;
}
static inline bool htp_sort_solve_layout(
struct htp_sort_vtcm_layout * layout,
uint32_t ne00,
@@ -75,18 +102,8 @@ static inline bool htp_sort_solve_layout(
n_threads--;
}
size_t total_bytes = spad_per_thread * n_threads;
if (total_bytes > vtcm_budget) {
return false;
}
layout->total_bytes = total_bytes;
layout->phase1_slot_size = spad_per_slot;
layout->chunk_elems = ne00_padded;
layout->n_chunks = 1;
layout->n_threads = n_threads;
layout->n_slots = n_slots;
return true;
htp_sort_vtcm_layout_build(layout, total_rows, ne00_padded, 1, 0, n_threads, n_slots);
return layout->total_bytes <= vtcm_budget;
}
uint32_t n_vec = (ne00 + 31) / 32;
@@ -102,17 +119,7 @@ static inline bool htp_sort_solve_layout(
uint32_t chunk_n_vec = n_vec_pow2 / n_chunks;
uint32_t chunk_elems = chunk_n_vec * 32;
size_t phase1_values_size = ((chunk_elems * sizeof(float)) + 127) & ~127;
size_t phase1_indices_size = ((chunk_elems * sizeof(int32_t)) + 127) & ~127;
size_t phase1_slot_size = ((phase1_values_size + phase1_indices_size) + 255) & ~255;
size_t phase1_total_size = phase1_slot_size * n_chunks;
size_t merge_values_size = 0;
size_t merge_indices_size = 0;
size_t merge_values_off = phase1_total_size;
size_t merge_indices_off = 0;
uint32_t merge_elems = 0;
uint32_t merge_elems = 0;
if (n_chunks > 1) {
if (is_top_k) {
@@ -125,47 +132,25 @@ static inline bool htp_sort_solve_layout(
} else {
merge_elems = n_vec_pow2 * 32;
}
merge_values_size = ((merge_elems * sizeof(float)) + 127) & ~127;
merge_indices_size = ((merge_elems * sizeof(int32_t)) + 127) & ~127;
merge_indices_off = merge_values_off + merge_values_size;
}
size_t total_bytes = phase1_total_size + merge_values_size + merge_indices_size;
htp_sort_vtcm_layout_build(layout, 1, chunk_elems, n_chunks, merge_elems, n_chunks, 1);
if (total_bytes > vtcm_budget && n_chunks > 1) {
n_chunks = 1;
if (layout->total_bytes > vtcm_budget && n_chunks > 1) {
n_chunks = 1;
chunk_elems = n_vec_pow2 * 32;
phase1_values_size = ((chunk_elems * sizeof(float)) + 127) & ~127;
phase1_indices_size = ((chunk_elems * sizeof(int32_t)) + 127) & ~127;
phase1_slot_size = ((phase1_values_size + phase1_indices_size) + 255) & ~255;
phase1_total_size = phase1_slot_size;
merge_values_size = 0;
merge_indices_size = 0;
merge_values_off = phase1_total_size;
merge_indices_off = 0;
merge_elems = 0;
total_bytes = phase1_total_size;
merge_elems = 0;
htp_sort_vtcm_layout_build(layout, 1, chunk_elems, n_chunks, merge_elems, 1, 1);
}
if (total_bytes > vtcm_budget) {
if (layout->total_bytes > vtcm_budget) {
return false;
}
uint32_t n_slots = 1;
if (n_chunks == 1 && phase1_slot_size * 2 <= vtcm_budget) {
n_slots = 2;
total_bytes = phase1_slot_size * 2;
if (n_chunks == 1 && layout->phase1_slot_size * 2 <= vtcm_budget) {
htp_sort_vtcm_layout_build(layout, 1, chunk_elems, 1, 0, 1, 2);
}
layout->total_bytes = total_bytes;
layout->phase1_slot_size = phase1_slot_size;
layout->merge_values_off = merge_values_off;
layout->merge_indices_off = merge_indices_off;
layout->chunk_elems = chunk_elems;
layout->n_chunks = n_chunks;
layout->merge_elems = merge_elems;
layout->n_threads = n_chunks;
layout->n_slots = n_slots;
return true;
}
+129 -86
View File
@@ -42,6 +42,7 @@ struct htp_binary_context {
uint32_t nrows_per_thread;
uint32_t total_rows;
uint32_t row_start;
uint32_t n_srcs;
size_t src0_row_size_aligned;
size_t src1_row_size_aligned;
size_t dst_row_size_aligned;
@@ -380,6 +381,7 @@ static void binary_thread_vector_same_shape(unsigned int nth, unsigned int ith,
size_t dst_spad_half = layout->dst_spad_half_size;
dma_queue * dma_q = octx->ctx->dma[ith];
const uint32_t n_srcs = bctx->n_srcs;
uint32_t ir_prefetch = start_row;
int spad_idx = 0;
@@ -391,12 +393,7 @@ static void binary_thread_vector_same_shape(unsigned int nth, unsigned int ith,
i02 = fastdiv(rem, &bctx->src0_dim1_div);
i01 = rem - i02 * ne01;
uint32_t i13 = (ne13 == 1) ? 0 : i03;
uint32_t i12 = (ne12 == 1) ? 0 : i02;
uint32_t i11 = (ne11 == 1) ? 0 : i01;
dma_addr_t src0_curr = src0->data + i03 * nb03 + i02 * nb02 + i01 * nb01;
dma_addr_t src1_curr = src1->data + i13 * nb13 + i12 * nb12 + i11 * nb11;
dma_addr_t dst_curr = dst->data + i03 * nb3 + i02 * nb2 + i01 * nb1;
uint8_t * s0_spad = src0_spad_base + spad_idx * src0_spad_half;
@@ -405,7 +402,15 @@ static void binary_thread_vector_same_shape(unsigned int nth, unsigned int ith,
dma_queue_push(dma_q, dma_make_data(dst_curr, d_spad), nb1, bctx->dst_row_size_aligned, row_size_bytes, 0);
dma_queue_push(dma_q, dma_make_data(s0_spad, src0_curr), bctx->src0_row_size_aligned, nb01, row_size_bytes, current_block_size);
dma_queue_push(dma_q, dma_make_data(s1_spad, src1_curr), bctx->src1_row_size_aligned, nb11, row_size_bytes, current_block_size);
for (uint32_t s = 1; s < n_srcs; s++) {
const struct htp_tensor * src_s = octx->src[s];
uint32_t is3 = (src_s->ne[3] == 1) ? 0 : i03;
uint32_t is2 = (src_s->ne[2] == 1) ? 0 : i02;
uint32_t is1 = (src_s->ne[1] == 1) ? 0 : i01;
dma_addr_t s_curr = src_s->data + is3 * src_s->nb[3] + is2 * src_s->nb[2] + is1 * src_s->nb[1];
uint8_t * s_spad = s1_spad + (s - 1) * 2 * src1_spad_half;
dma_queue_push(dma_q, dma_make_data(s_spad, s_curr), bctx->src1_row_size_aligned, src_s->nb[1], row_size_bytes, current_block_size);
}
ir_prefetch += current_block_size;
spad_idx ^= 1;
}
@@ -422,6 +427,11 @@ static void binary_thread_vector_same_shape(unsigned int nth, unsigned int ith,
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir);
compute(d_spad, s0_spad, s1_spad, current_block_size,
bctx->dst_row_size_aligned, bctx->src0_row_size_aligned, bctx->src1_row_size_aligned, ne00);
for (uint32_t s = 2; s < n_srcs; s++) {
uint8_t * ss_spad = (uint8_t *) dma_queue_pop(dma_q).dst;
compute(d_spad, d_spad, ss_spad, current_block_size,
bctx->dst_row_size_aligned, bctx->dst_row_size_aligned, bctx->src1_row_size_aligned, ne00);
}
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir);
uint32_t i03, i02, i01, rem;
@@ -440,15 +450,18 @@ static void binary_thread_vector_same_shape(unsigned int nth, unsigned int ith,
p02 = fastdiv(prem, &bctx->src0_dim1_div);
p01 = prem - p02 * ne01;
uint32_t p13 = (ne13 == 1) ? 0 : p03;
uint32_t p12 = (ne12 == 1) ? 0 : p02;
uint32_t p11 = (ne11 == 1) ? 0 : p01;
dma_addr_t s0_next = src0->data + p03 * nb03 + p02 * nb02 + p01 * nb01;
dma_addr_t s1_next = src1->data + p13 * nb13 + p12 * nb12 + p11 * nb11;
dma_queue_push(dma_q, dma_make_data(s0_spad, s0_next), bctx->src0_row_size_aligned, nb01, row_size_bytes, next_block_size);
dma_queue_push(dma_q, dma_make_data(s1_spad, s1_next), bctx->src1_row_size_aligned, nb11, row_size_bytes, next_block_size);
for (uint32_t s = 1; s < n_srcs; s++) {
const struct htp_tensor * src_s = octx->src[s];
uint32_t ps3 = (src_s->ne[3] == 1) ? 0 : p03;
uint32_t ps2 = (src_s->ne[2] == 1) ? 0 : p02;
uint32_t ps1 = (src_s->ne[1] == 1) ? 0 : p01;
dma_addr_t s_next = src_s->data + ps3 * src_s->nb[3] + ps2 * src_s->nb[2] + ps1 * src_s->nb[1];
uint8_t * s_spad = s1_spad + (s - 1) * 2 * src1_spad_half;
dma_queue_push(dma_q, dma_make_data(s_spad, s_next), bctx->src1_row_size_aligned, src_s->nb[1], row_size_bytes, next_block_size);
}
ir_prefetch += next_block_size;
}
@@ -859,6 +872,7 @@ struct binary_chunked_context {
uint32_t chunk_size;
uint32_t chunks_per_thread;
uint32_t total_chunks;
uint32_t n_srcs;
bool is_scalar;
float scalar_f32;
_Float16 scalar_f16;
@@ -872,7 +886,6 @@ static void binary_thread_chunked(unsigned int nth, unsigned int ith, void * dat
struct binary_chunked_context * ctx = (struct binary_chunked_context *) data;
struct htp_ops_context * octx = ctx->octx;
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * src1 = octx->src[1];
const struct htp_tensor * dst = octx->dst;
const uint32_t start_chunk = ctx->chunks_per_thread * ith;
@@ -895,6 +908,7 @@ static void binary_thread_chunked(unsigned int nth, unsigned int ith, void * dat
uint8_t * dst_spad_base = VTCM_LAYOUT_PTR(uint8_t, ctx->vtcm_base, layout->off_dst) + (ith * layout->dst_bytes_per_thread);
dma_queue * dma_q = octx->ctx->dma[ith];
const uint32_t n_srcs = ctx->n_srcs;
uint32_t prefetch_chunk = start_chunk;
int spad_idx = 0;
@@ -913,9 +927,12 @@ static void binary_thread_chunked(unsigned int nth, unsigned int ith, void * dat
dma_queue_push(dma_q, dma_make_data(d_curr, d_spad), chunk_bytes, chunk_bytes, cur_bytes, 0);
dma_queue_push(dma_q, dma_make_data(s0_spad, s0_curr), chunk_bytes, chunk_bytes, cur_bytes, 1);
if (!ctx->is_scalar) {
dma_addr_t s1_curr = src1->data + (size_t) c_start * elem_size;
uint8_t * s1_spad = src1_spad_base + spad_idx * chunk_bytes;
dma_queue_push(dma_q, dma_make_data(s1_spad, s1_curr), chunk_bytes, chunk_bytes, cur_bytes, 1);
for (uint32_t s = 1; s < n_srcs; s++) {
dma_addr_t s_curr = octx->src[s]->data + (size_t) c_start * elem_size;
uint8_t * s_spad = s1_spad + (s - 1) * 2 * chunk_bytes;
dma_queue_push(dma_q, dma_make_data(s_spad, s_curr), chunk_bytes, chunk_bytes, cur_bytes, 1);
}
}
prefetch_chunk++;
@@ -943,6 +960,10 @@ static void binary_thread_chunked(unsigned int nth, unsigned int ith, void * dat
}
} else {
ctx->compute(d_spad, s0_spad, s1_spad, cur_elems);
for (uint32_t s = 2; s < n_srcs; s++) {
uint8_t * s_spad = (uint8_t *) dma_queue_pop(dma_q).dst;
ctx->compute(d_spad, d_spad, s_spad, cur_elems);
}
}
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) c);
@@ -958,8 +979,11 @@ static void binary_thread_chunked(unsigned int nth, unsigned int ith, void * dat
dma_addr_t s0_next = src0->data + (size_t) pc_start * elem_size;
dma_queue_push(dma_q, dma_make_data(s0_spad, s0_next), chunk_bytes, chunk_bytes, p_bytes, 1);
if (!ctx->is_scalar) {
dma_addr_t s1_next = src1->data + (size_t) pc_start * elem_size;
dma_queue_push(dma_q, dma_make_data(s1_spad, s1_next), chunk_bytes, chunk_bytes, p_bytes, 1);
for (uint32_t s = 1; s < n_srcs; s++) {
dma_addr_t s_next = octx->src[s]->data + (size_t) pc_start * elem_size;
uint8_t * s_spad = s1_spad + (s - 1) * 2 * chunk_bytes;
dma_queue_push(dma_q, dma_make_data(s_spad, s_next), chunk_bytes, chunk_bytes, p_bytes, 1);
}
}
prefetch_chunk++;
@@ -974,6 +998,7 @@ static int execute_op_binary(struct htp_ops_context * octx) {
const struct htp_tensor * src1 = octx->src[1];
const struct htp_tensor * dst = octx->dst;
const struct htp_binary_kernel_params * kparams = (const struct htp_binary_kernel_params *) octx->kernel_params;
const uint32_t n_srcs = kparams->n_srcs > 2 ? kparams->n_srcs : 2;
const uint32_t src0_nrows = src0->ne[1] * src0->ne[2] * src0->ne[3];
@@ -985,7 +1010,7 @@ static int execute_op_binary(struct htp_ops_context * octx) {
const size_t dst_row_size = dst->ne[0] * elem_size;
if (kparams->kernel_type == HTP_BINARY_KERNEL_CHUNKED) {
const bool is_scalar = kparams->is_scalar || (src1->ne[0] == 1 && src1->ne[1] == 1 && src1->ne[2] == 1 && src1->ne[3] == 1);
const bool is_scalar = kparams->is_scalar;
compute_binary_chunked_t compute = NULL;
compute_binary_scalar_chunked_f32_t compute_scalar_f32 = NULL;
@@ -1045,12 +1070,16 @@ static int execute_op_binary(struct htp_ops_context * octx) {
const uint32_t elems_per_line = (src0_type == HTP_TYPE_F32) ? 32 : 64;
if (octx->ctx->mdev.count > 1) {
const bool can_split = htp_tensor_mdev_data_aligned(dst) &&
htp_tensor_mdev_data_aligned(src0) &&
(is_scalar || htp_tensor_mdev_data_aligned(src1)) &&
htp_tensor_is_contiguous(dst, elem_size) &&
htp_tensor_is_contiguous(src0, elem_size) &&
(is_scalar || htp_tensor_is_contiguous(src1, elem_size));
bool can_split = htp_tensor_mdev_data_aligned(dst) &&
htp_tensor_mdev_data_aligned(src0) &&
(is_scalar || htp_tensor_mdev_data_aligned(src1)) &&
htp_tensor_is_contiguous(dst, elem_size) &&
htp_tensor_is_contiguous(src0, elem_size) &&
(is_scalar || htp_tensor_is_contiguous(src1, elem_size));
for (uint32_t s = 2; can_split && s < n_srcs; s++) {
can_split = htp_tensor_mdev_data_aligned(octx->src[s]) &&
htp_tensor_is_contiguous(octx->src[s], elem_size);
}
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(
total_elems, can_split ? elems_per_line : 0,
octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
@@ -1072,7 +1101,7 @@ static int execute_op_binary(struct htp_ops_context * octx) {
return HTP_STATUS_VTCM_TOO_SMALL;
}
const uint32_t chunk_size = kparams->chunk_size > 0 ? kparams->chunk_size : (32768 / elem_size);
const uint32_t chunk_size = kparams->chunk_size;
const uint32_t total_chunks = (nelem + chunk_size - 1) / chunk_size;
const uint32_t n_threads = (total_chunks >= 2) ? MIN(octx->n_threads, total_chunks) : 1;
const uint32_t chunks_per_thread = (total_chunks + n_threads - 1) / n_threads;
@@ -1101,6 +1130,7 @@ static int execute_op_binary(struct htp_ops_context * octx) {
.chunk_size = chunk_size,
.chunks_per_thread = chunks_per_thread,
.total_chunks = total_chunks,
.n_srcs = n_srcs,
.is_scalar = is_scalar,
.scalar_f32 = scalar_f32,
.scalar_f16 = scalar_f16,
@@ -1146,65 +1176,6 @@ static int execute_op_binary(struct htp_ops_context * octx) {
return HTP_STATUS_VTCM_TOO_SMALL;
}
dma_queue * dma_q = octx->ctx->dma[0];
uint8_t * vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, bctx.vtcm_base, bctx.vtcm_layout.off_src1);
if (kparams->kernel_type == HTP_BINARY_KERNEL_ROW_BCAST) {
dma_queue_push(dma_q, dma_make_data(vtcm_src1, src1->data), bctx.vtcm_layout.src1_size, 0, src1->ne[0] * elem_size, 1);
} else if (kparams->kernel_type == HTP_BINARY_KERNEL_SCALAR ||
kparams->kernel_type == HTP_BINARY_KERNEL_REPEAT ||
kparams->kernel_type == HTP_BINARY_KERNEL_COMPLEX) {
if (!kparams->src1_strided) {
const size_t src1_bytes = (size_t) src1->ne[0] * src1->ne[1] * src1->ne[2] * src1->ne[3] * elem_size;
dma_queue_push(dma_q, dma_make_data(vtcm_src1, src1->data), bctx.vtcm_layout.src1_size, 0, src1_bytes, 1);
} else {
const uint32_t ne11 = src1->ne[1];
const uint32_t ne12 = src1->ne[2];
const uint32_t ne13 = src1->ne[3];
const size_t row_bytes = src1->ne[0] * elem_size;
for (uint32_t i13 = 0; i13 < ne13; i13++) {
for (uint32_t i12 = 0; i12 < ne12; i12++) {
dma_addr_t src_addr = src1->data + i13 * src1->nb[3] + i12 * src1->nb[2];
uint8_t * dst_ptr = vtcm_src1 + (i13 * ne12 * ne11 + i12 * ne11) * row_bytes;
while (!dma_queue_push(dma_q, dma_make_data(dst_ptr, src_addr),
row_bytes, src1->nb[1], row_bytes, ne11)) {
dma_queue_pop(dma_q);
}
}
}
}
} else if (kparams->kernel_type == HTP_BINARY_KERNEL_ADD_ID) {
const struct htp_tensor * src2 = octx->src[2];
uint8_t * vtcm_src2 = VTCM_LAYOUT_PTR(uint8_t, bctx.vtcm_base, bctx.vtcm_layout.off_src2);
dma_queue_push(dma_q, dma_make_data(vtcm_src1, src1->data),
kparams->src1_row_size_aligned, src1->nb[1],
src1->ne[0] * elem_size, src1->ne[1]);
const size_t src2_row_bytes = src2->ne[0] * sizeof(int32_t);
dma_queue_push(dma_q, dma_make_data(vtcm_src2, src2->data),
src2_row_bytes, src2->nb[1],
src2_row_bytes, src2->ne[1]);
}
bctx.octx = octx;
bctx.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
bctx.total_rows = nrows;
bctx.row_start = row_start;
bctx.block_max = bctx.vtcm_layout.rows_per_buffer;
bctx.src0_row_size_aligned = src0_row_size_aligned;
bctx.src1_row_size_aligned = src1_row_size_aligned;
bctx.dst_row_size_aligned = dst_row_size_aligned;
bctx.row_size_bytes = src0_row_size;
bctx.src0_dim1_div = init_fastdiv_values(src0->ne[1]);
bctx.src0_dim2_div = init_fastdiv_values(src0->ne[2]);
bctx.src0_dim12_div = init_fastdiv_values(src0->ne[1] * src0->ne[2]);
bctx.src1_dim1_div = init_fastdiv_values(src1->ne[1]);
bctx.src1_dim2_div = init_fastdiv_values(src1->ne[2]);
bctx.src1_dim3_div = init_fastdiv_values(src1->ne[3]);
bctx.split_at_ne01 = kparams->split_at_ne01;
bctx.split_at_ne02 = kparams->split_at_ne02;
worker_callback_t worker_func = NULL;
void * compute_func = NULL;
@@ -1322,7 +1293,70 @@ static int execute_op_binary(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
bctx.compute = compute_func;
dma_queue * dma_q = octx->ctx->dma[0];
uint8_t * vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, bctx.vtcm_base, bctx.vtcm_layout.off_src1);
if (kparams->kernel_type == HTP_BINARY_KERNEL_ROW_BCAST) {
dma_queue_push(dma_q, dma_make_data(vtcm_src1, src1->data), bctx.vtcm_layout.src1_size, 0, src1->ne[0] * elem_size, 1);
} else if (kparams->kernel_type == HTP_BINARY_KERNEL_SCALAR ||
kparams->kernel_type == HTP_BINARY_KERNEL_REPEAT ||
kparams->kernel_type == HTP_BINARY_KERNEL_COMPLEX) {
if (!kparams->src1_strided) {
const size_t src1_bytes = (size_t) src1->ne[0] * src1->ne[1] * src1->ne[2] * src1->ne[3] * elem_size;
dma_queue_push(dma_q, dma_make_data(vtcm_src1, src1->data), bctx.vtcm_layout.src1_size, 0, src1_bytes, 1);
if (kparams->kernel_type == HTP_BINARY_KERNEL_SCALAR && octx->src[2] != NULL) {
uint8_t * vtcm_src2 = VTCM_LAYOUT_PTR(uint8_t, bctx.vtcm_base, bctx.vtcm_layout.off_src2);
dma_queue_push(dma_q, dma_make_data(vtcm_src2, octx->src[2]->data), bctx.vtcm_layout.src2_size, 0, src1_bytes, 1);
}
} else {
const uint32_t ne11 = src1->ne[1];
const uint32_t ne12 = src1->ne[2];
const uint32_t ne13 = src1->ne[3];
const size_t row_bytes = src1->ne[0] * elem_size;
for (uint32_t i13 = 0; i13 < ne13; i13++) {
for (uint32_t i12 = 0; i12 < ne12; i12++) {
dma_addr_t src_addr = src1->data + i13 * src1->nb[3] + i12 * src1->nb[2];
uint8_t * dst_ptr = vtcm_src1 + (i13 * ne12 * ne11 + i12 * ne11) * row_bytes;
while (!dma_queue_push(dma_q, dma_make_data(dst_ptr, src_addr),
row_bytes, src1->nb[1], row_bytes, ne11)) {
dma_queue_pop(dma_q);
}
}
}
}
} else if (kparams->kernel_type == HTP_BINARY_KERNEL_ADD_ID) {
const struct htp_tensor * src2 = octx->src[2];
uint8_t * vtcm_src2 = VTCM_LAYOUT_PTR(uint8_t, bctx.vtcm_base, bctx.vtcm_layout.off_src2);
dma_queue_push(dma_q, dma_make_data(vtcm_src1, src1->data),
kparams->src1_row_size_aligned, src1->nb[1],
src1->ne[0] * elem_size, src1->ne[1]);
const size_t src2_row_bytes = src2->ne[0] * sizeof(int32_t);
dma_queue_push(dma_q, dma_make_data(vtcm_src2, src2->data),
src2_row_bytes, src2->nb[1],
src2_row_bytes, src2->ne[1]);
}
bctx.octx = octx;
bctx.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
bctx.total_rows = nrows;
bctx.row_start = row_start;
bctx.n_srcs = n_srcs;
bctx.block_max = bctx.vtcm_layout.rows_per_buffer;
bctx.src0_row_size_aligned = src0_row_size_aligned;
bctx.src1_row_size_aligned = src1_row_size_aligned;
bctx.dst_row_size_aligned = dst_row_size_aligned;
bctx.row_size_bytes = src0_row_size;
bctx.src0_dim1_div = kparams->div_ne01;
bctx.src0_dim2_div = kparams->div_ne02;
bctx.src0_dim12_div = kparams->div_ne012;
bctx.src1_dim1_div = kparams->div_ne11;
bctx.src1_dim2_div = kparams->div_ne12;
bctx.src1_dim3_div = kparams->div_ne13;
bctx.split_at_ne01 = kparams->split_at_ne01;
bctx.split_at_ne02 = kparams->split_at_ne02;
bctx.compute = compute_func;
if (kparams->kernel_type == HTP_BINARY_KERNEL_ROW_BCAST ||
kparams->kernel_type == HTP_BINARY_KERNEL_SCALAR ||
@@ -1330,6 +1364,15 @@ static int execute_op_binary(struct htp_ops_context * octx) {
kparams->kernel_type == HTP_BINARY_KERNEL_COMPLEX ||
kparams->kernel_type == HTP_BINARY_KERNEL_ADD_ID) {
dma_queue_flush(dma_q);
if (kparams->kernel_type == HTP_BINARY_KERNEL_SCALAR && octx->src[2] != NULL && octx->op == HTP_OP_MUL) {
uint8_t * vtcm_src2 = VTCM_LAYOUT_PTR(uint8_t, bctx.vtcm_base, bctx.vtcm_layout.off_src2);
const uint32_t n_scalars = src1->ne[0] * src1->ne[1] * src1->ne[2] * src1->ne[3];
if (src0_type == HTP_TYPE_F32) {
hvx_mul_f32_aaa(vtcm_src1, vtcm_src1, vtcm_src2, n_scalars);
} else if (src0_type == HTP_TYPE_F16) {
hvx_mul_f16_aaa(vtcm_src1, vtcm_src1, vtcm_src2, n_scalars);
}
}
}
work_queue_run(octx->ctx->work_queue, worker_func, &bctx, n_threads);
+77 -11
View File
@@ -6,6 +6,7 @@
#include <string.h>
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-ops.h"
#include "htp-vtcm.h"
@@ -20,7 +21,15 @@ enum htp_binary_kernel_type {
};
struct htp_binary_kernel_params {
uint32_t kernel_type;
uint8_t kernel_type;
uint8_t split_at_ne01;
uint8_t split_at_ne02;
uint8_t src1_strided;
uint8_t n_srcs;
uint8_t is_scalar;
uint8_t pad[2];
uint32_t n_threads;
uint32_t rows_per_buffer;
@@ -34,12 +43,14 @@ struct htp_binary_kernel_params {
uint32_t chunk_size;
uint32_t chunk_bytes;
uint32_t is_scalar;
uint8_t split_at_ne01;
uint8_t split_at_ne02;
uint8_t src1_strided;
uint8_t pad;
struct fastdiv_values div_ne01;
struct fastdiv_values div_ne02;
struct fastdiv_values div_ne012;
struct fastdiv_values div_ne11;
struct fastdiv_values div_ne12;
struct fastdiv_values div_ne13;
};
#if defined(__cplusplus)
@@ -100,6 +111,8 @@ static inline void htp_binary_vtcm_layout_build(
return;
}
const uint32_t n_srcs = kparams->n_srcs > 2 ? kparams->n_srcs : 2;
if (kparams->kernel_type == HTP_BINARY_KERNEL_CHUNKED) {
const size_t chunk_bytes = kparams->chunk_bytes;
if (chunk_bytes == 0) {
@@ -107,7 +120,7 @@ static inline void htp_binary_vtcm_layout_build(
}
L->src0_bytes_per_thread = 2 * chunk_bytes;
L->src1_bytes_per_thread = kparams->is_scalar ? 0 : (2 * chunk_bytes);
L->src1_bytes_per_thread = kparams->is_scalar ? 0 : (2 * (n_srcs - 1) * chunk_bytes);
L->dst_bytes_per_thread = 2 * chunk_bytes;
L->src0_spad_half_size = chunk_bytes;
@@ -135,7 +148,7 @@ static inline void htp_binary_vtcm_layout_build(
}
const size_t spad_row_total = (kparams->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE)
? 2 * (kparams->src0_row_size_aligned + kparams->src1_row_size_aligned + kparams->dst_row_size_aligned)
? 2 * (kparams->src0_row_size_aligned + (n_srcs - 1) * kparams->src1_row_size_aligned + kparams->dst_row_size_aligned)
: 2 * (kparams->src0_row_size_aligned + kparams->dst_row_size_aligned);
const size_t static_vtcm_size = kparams->src1_size + kparams->src2_size;
@@ -143,7 +156,9 @@ static inline void htp_binary_vtcm_layout_build(
return;
}
const size_t rows_per_buffer = (vtcm_size - static_vtcm_size) / (n_threads * spad_row_total);
const size_t rows_per_buffer = (kparams->rows_per_buffer > 0)
? kparams->rows_per_buffer
: (vtcm_size - static_vtcm_size) / (n_threads * spad_row_total);
if (rows_per_buffer == 0) {
return;
}
@@ -155,11 +170,13 @@ static inline void htp_binary_vtcm_layout_build(
L->src0_bytes_per_thread = rows_per_buffer * 2 * kparams->src0_row_size_aligned;
L->dst_bytes_per_thread = rows_per_buffer * 2 * kparams->dst_row_size_aligned;
L->src1_bytes_per_thread = (kparams->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE)
? rows_per_buffer * 2 * kparams->src1_row_size_aligned
? rows_per_buffer * 2 * (n_srcs - 1) * kparams->src1_row_size_aligned
: 0;
L->src0_spad_half_size = L->src0_bytes_per_thread / 2;
L->src1_spad_half_size = L->src1_bytes_per_thread / 2;
L->src1_spad_half_size = (kparams->kernel_type == HTP_BINARY_KERNEL_SAME_SHAPE)
? rows_per_buffer * kparams->src1_row_size_aligned
: 0;
L->dst_spad_half_size = L->dst_bytes_per_thread / 2;
const size_t src0_total = n_threads * L->src0_bytes_per_thread;
@@ -178,4 +195,53 @@ static inline void htp_binary_vtcm_layout_build(
L->total_bytes = off;
}
static inline bool htp_binary_solve_chunked(
struct htp_binary_vtcm_layout * L,
struct htp_binary_kernel_params * kparams,
uint32_t total_elems,
uint32_t elem_size,
uint32_t max_threads,
uint32_t n_srcs,
bool is_scalar,
size_t vtcm_size
) {
const size_t n_bufs = is_scalar ? 2 : (size_t) n_srcs + 1;
const size_t scalar_bytes = is_scalar ? 128 : 0;
const size_t budget_per_buf = (max_threads > 0 && vtcm_size > scalar_bytes)
? hex_align_down((vtcm_size - scalar_bytes) / (2 * max_threads * n_bufs), 128)
: 0;
const uint32_t max_chunk_bytes = (budget_per_buf > 0 && budget_per_buf < 32768) ? (uint32_t) budget_per_buf : 32768u;
const uint32_t max_chunk_elems = max_chunk_bytes / elem_size;
if (max_chunk_elems == 0) {
return false;
}
const uint32_t min_chunk_elems = 256 < max_chunk_elems ? 256 : max_chunk_elems;
const uint32_t target_chunk_elems = hex_round_up((total_elems + (2 * max_threads) - 1) / (2 * max_threads), 32);
const uint32_t chunk_size = (target_chunk_elems < min_chunk_elems) ? min_chunk_elems
: (target_chunk_elems > max_chunk_elems) ? max_chunk_elems
: target_chunk_elems;
const uint32_t chunk_bytes = hex_round_up(chunk_size * elem_size, 128);
const uint32_t total_chunks = (total_elems + chunk_size - 1) / chunk_size;
const uint32_t n_threads = (total_chunks >= 2) ? (max_threads < total_chunks ? max_threads : total_chunks) : 1;
kparams->kernel_type = HTP_BINARY_KERNEL_CHUNKED;
kparams->n_threads = n_threads;
kparams->n_srcs = (uint8_t) n_srcs;
kparams->rows_per_buffer = 1;
kparams->src1_row_size_aligned = is_scalar ? 0 : kparams->src0_row_size_aligned;
kparams->src1_size = 0;
kparams->chunk_size = chunk_size;
kparams->chunk_bytes = chunk_bytes;
kparams->is_scalar = is_scalar ? 1 : 0;
htp_binary_vtcm_layout_build(L, kparams, vtcm_size);
if (L->total_bytes == 0 || L->total_bytes > vtcm_size) {
return false;
}
kparams->vtcm_size = (uint32_t) L->total_bytes;
return true;
}
#endif
+7 -8
View File
@@ -294,22 +294,21 @@ static int concat_transposed(struct htp_ops_context * octx, const struct htp_con
const uint32_t n_threads = octx->n_threads;
// layout precomputed on host; kept for reference:
// struct htp_concat_transposed_vtcm_layout layout;
// htp_concat_transposed_vtcm_layout_build(&layout, octx->src[0]->ne[0], octx->src[1]->ne[0], type_size, n_threads);
struct htp_concat_transposed_vtcm_layout layout;
htp_concat_transposed_vtcm_layout_build(&layout, octx->src[0]->ne[0], octx->src[1]->ne[0], type_size, n_threads);
uint8_t * vtcm_base = (uint8_t *) octx->ctx->vtcm_base;
struct htp_concat_context cctx;
cctx.octx = octx;
cctx.spad0_base = vtcm_base;
cctx.spad1_base = vtcm_base + n_threads * kparams->u.transposed.spad0_size_per_thread;
cctx.spad0_size_per_thread = kparams->u.transposed.spad0_size_per_thread;
cctx.spad1_size_per_thread = kparams->u.transposed.spad1_size_per_thread;
cctx.spad0_base = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, layout.off_spad0);
cctx.spad1_base = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, layout.off_spad1);
cctx.spad0_size_per_thread = layout.src0_spad_size_per_thread;
cctx.spad1_size_per_thread = layout.src1_spad_size_per_thread;
cctx.row_start = row_start;
cctx.nrows = nrows;
cctx.nplanes = dst->ne[2] * dst->ne[3];
cctx.div_ne2 = init_fastdiv_values(dst->ne[2]);
cctx.div_ne2 = kparams->u.transposed.div_ne2;
cctx.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
work_queue_func_t worker_func = (type_size == 4) ? concat_2d_f32_transposed : concat_2d_f16_transposed;
+13 -6
View File
@@ -2,6 +2,8 @@
#define HTP_CONCAT_OPS_H
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
#include "gather-rows.h"
#include <stdint.h>
@@ -13,8 +15,7 @@ enum htp_concat_kernel_type {
};
struct htp_concat_transposed_params {
uint32_t spad0_size_per_thread;
uint32_t spad1_size_per_thread;
struct fastdiv_values div_ne2;
};
struct htp_concat_kernel_params {
@@ -40,11 +41,13 @@ _Static_assert(sizeof(struct htp_concat_kernel_params) <= 128, "htp_concat_kerne
struct htp_concat_transposed_vtcm_layout {
uint32_t src0_spad_size_per_thread;
uint32_t src1_spad_size_per_thread;
size_t off_spad0;
size_t off_spad1;
uint32_t total_bytes;
};
static inline void htp_concat_transposed_vtcm_layout_build(
struct htp_concat_transposed_vtcm_layout * layout,
struct htp_concat_transposed_vtcm_layout * L,
uint32_t src0_ne0,
uint32_t src1_ne0,
uint32_t type_size,
@@ -55,9 +58,13 @@ static inline void htp_concat_transposed_vtcm_layout_build(
uint32_t src1_ne0_padded = hex_round_up(src1_ne0, block_i);
uint32_t spad0_row_bytes = hex_round_up(src0_ne0 * type_size, 128) + src1_ne0_padded * type_size;
layout->src0_spad_size_per_thread = block_i * spad0_row_bytes;
layout->src1_spad_size_per_thread = src1_ne0_padded * spad1_stride;
layout->total_bytes = n_threads * (layout->src0_spad_size_per_thread + layout->src1_spad_size_per_thread);
L->src0_spad_size_per_thread = block_i * spad0_row_bytes;
L->src1_spad_size_per_thread = src1_ne0_padded * spad1_stride;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_spad0, (size_t) n_threads * L->src0_spad_size_per_thread);
VTCM_LAYOUT_ALLOC(off, off_spad1, (size_t) n_threads * L->src1_spad_size_per_thread);
L->total_bytes = (uint32_t) off;
}
#endif // HTP_CONCAT_OPS_H
+17 -14
View File
@@ -32,6 +32,7 @@ struct htp_copy_context {
uint32_t nelem;
uint32_t elem_per_thread;
struct htp_copy_convert_vtcm_layout layout;
uint8_t * vtcm_src0;
uint8_t * vtcm_dst;
};
@@ -176,13 +177,14 @@ static void cpy_thread_##NAME##_sameshape(unsigned int nth, unsigned int ith, vo
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
\
const struct htp_copy_convert_params * cvt = &ct->kparams->u.convert; \
const uint32_t src0_buf_size = cvt->src0_buf_size; \
const uint32_t dst_buf_size = cvt->dst_buf_size; \
const uint32_t src0_row_stride = cvt->src0_row_stride; \
const uint32_t dst_row_stride = cvt->dst_row_stride; \
const uint32_t blk_rows = cvt->blk_rows; \
uint8_t * vtcm_src0_base = ct->vtcm_src0 + ith * cvt->spad0_size_per_thread; \
uint8_t * vtcm_dst_base = ct->vtcm_dst + ith * cvt->spad1_size_per_thread; \
const struct htp_copy_convert_vtcm_layout * L = &ct->layout; \
const uint32_t src0_buf_size = L->src0_buf_size; \
const uint32_t dst_buf_size = L->dst_buf_size; \
const uint32_t src0_row_stride = L->src0_row_stride; \
const uint32_t dst_row_stride = L->dst_row_stride; \
const uint32_t blk_rows = L->blk_rows; \
uint8_t * vtcm_src0_base = ct->vtcm_src0 + ith * L->spad0_size_per_thread; \
uint8_t * vtcm_dst_base = ct->vtcm_dst + ith * L->spad1_size_per_thread; \
const uint32_t src0_row_size = ne00 * ct->kparams->src0_type_size; \
const uint32_t dst_row_size = ne00 * ct->kparams->dst_type_size; \
\
@@ -254,17 +256,16 @@ static int cpy_scalar(struct htp_ops_context * octx, const struct htp_copy_kerne
}
dma_queue * dma_q = octx->ctx->dma[0];
dma_addr_t s_vtcm = (dma_addr_t)(uintptr_t) octx->ctx->vtcm_base;
dma_addr_t d_vtcm = s_vtcm + VLEN;
uint8_t * s_ptr = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, 0);
uint8_t * d_ptr = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, VLEN);
dma_addr_t s_vtcm = (dma_addr_t)(uintptr_t) s_ptr;
dma_addr_t d_vtcm = (dma_addr_t)(uintptr_t) d_ptr;
const uint32_t s_size = kparams->src0_type_size;
const uint32_t d_size = kparams->dst_type_size;
dma_queue_push(dma_q, dma_make_data(s_vtcm, src0->data), s_size, s_size, s_size, 1);
dma_queue_pop(dma_q);
uint8_t * s_ptr = (uint8_t *) octx->ctx->vtcm_base;
uint8_t * d_ptr = s_ptr + VLEN;
const HVX_Vector v_src = hvx_vmem(s_ptr);
HVX_Vector v_dst;
@@ -366,6 +367,8 @@ static int cpy_sameshape_convert(struct htp_ops_context * octx, const struct htp
const struct htp_copy_convert_params * cvt = &kparams->u.convert;
struct htp_copy_context ct;
htp_copy_convert_vtcm_layout_build(&ct.layout, src0->ne[0], kparams->src0_type_size, kparams->dst_type_size, cvt->blk_rows, n_threads);
ct.octx = octx;
ct.kparams = kparams;
ct.row_start = row_start;
@@ -373,8 +376,8 @@ static int cpy_sameshape_convert(struct htp_ops_context * octx, const struct htp
ct.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
uint8_t * vtcm_base = (uint8_t *) octx->ctx->vtcm_base;
ct.vtcm_src0 = vtcm_base;
ct.vtcm_dst = vtcm_base + (size_t) n_threads * cvt->spad0_size_per_thread;
ct.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, ct.layout.off_src0);
ct.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, ct.layout.off_dst);
work_queue_func_t copy_fun = NULL;
if (dst->type == HTP_TYPE_F16 && src0->type == HTP_TYPE_F32) {
+34 -17
View File
@@ -3,6 +3,7 @@
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
#include "gather-rows.h"
#include <stdint.h>
@@ -17,12 +18,6 @@ enum htp_copy_kernel_type {
};
struct htp_copy_convert_params {
uint32_t src0_buf_size;
uint32_t dst_buf_size;
uint32_t spad0_size_per_thread;
uint32_t spad1_size_per_thread;
uint32_t src0_row_stride; // row pitch in the VTCM buffers
uint32_t dst_row_stride;
uint32_t blk_rows; // rows moved per DMA descriptor
struct fastdiv_values div_ne01;
struct fastdiv_values div_ne02_ne01;
@@ -60,6 +55,9 @@ struct htp_copy_kernel_params {
#define HTP_COPY_VTCM_BLK_BYTES (32 * 1024)
struct htp_copy_convert_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_dst;
uint32_t src0_row_stride;
uint32_t dst_row_stride;
uint32_t blk_rows;
@@ -67,11 +65,35 @@ struct htp_copy_convert_vtcm_layout {
uint32_t dst_buf_size;
uint32_t spad0_size_per_thread;
uint32_t spad1_size_per_thread;
uint32_t total_bytes;
};
// ne01 bounds a block: rows of one block share the dim-1 stride.
static inline void htp_copy_convert_vtcm_layout_build(
struct htp_copy_convert_vtcm_layout * L,
uint32_t ne00,
uint32_t src_type_size,
uint32_t dst_type_size,
uint32_t blk_rows,
uint32_t n_threads) {
const uint32_t src0_row_stride = hex_round_up(ne00 * src_type_size, 256);
const uint32_t dst_row_stride = hex_round_up(ne00 * dst_type_size, 256);
L->src0_row_stride = src0_row_stride;
L->dst_row_stride = dst_row_stride;
L->blk_rows = blk_rows;
L->src0_buf_size = blk_rows * src0_row_stride;
L->dst_buf_size = blk_rows * dst_row_stride;
L->spad0_size_per_thread = 2 * L->src0_buf_size;
L->spad1_size_per_thread = 2 * L->dst_buf_size;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, (size_t) n_threads * L->spad0_size_per_thread);
VTCM_LAYOUT_ALLOC(off, off_dst, (size_t) n_threads * L->spad1_size_per_thread);
L->total_bytes = off;
}
// ne01 bounds a block: rows of one block share the dim-1 stride.
static inline void htp_copy_convert_solve_layout(
struct htp_copy_convert_vtcm_layout * layout,
uint32_t ne00,
uint32_t ne01,
@@ -79,10 +101,10 @@ static inline void htp_copy_convert_vtcm_layout_build(
uint32_t dst_type_size,
uint32_t n_threads) {
layout->src0_row_stride = hex_round_up(ne00 * src_type_size, 256);
layout->dst_row_stride = hex_round_up(ne00 * dst_type_size, 256);
const uint32_t src0_row_stride = hex_round_up(ne00 * src_type_size, 256);
const uint32_t dst_row_stride = hex_round_up(ne00 * dst_type_size, 256);
const uint32_t max_row = layout->src0_row_stride > layout->dst_row_stride ? layout->src0_row_stride : layout->dst_row_stride;
const uint32_t max_row = src0_row_stride > dst_row_stride ? src0_row_stride : dst_row_stride;
uint32_t blk_rows = HTP_COPY_VTCM_BLK_BYTES / max_row;
if (blk_rows > ne01) {
blk_rows = ne01;
@@ -90,13 +112,8 @@ static inline void htp_copy_convert_vtcm_layout_build(
if (blk_rows == 0) {
blk_rows = 1;
}
layout->blk_rows = blk_rows;
layout->src0_buf_size = blk_rows * layout->src0_row_stride;
layout->dst_buf_size = blk_rows * layout->dst_row_stride;
layout->spad0_size_per_thread = 2 * layout->src0_buf_size;
layout->spad1_size_per_thread = 2 * layout->dst_buf_size;
layout->total_bytes = n_threads * (layout->spad0_size_per_thread + layout->spad1_size_per_thread);
htp_copy_convert_vtcm_layout_build(layout, ne00, src_type_size, dst_type_size, blk_rows, n_threads);
}
#if defined(__cplusplus)
+34 -27
View File
@@ -12,9 +12,11 @@
#include "htp-ctx.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "htp-vtcm.h"
#include "hvx-types.h"
#include "hvx-utils.h"
#include "dma-queue.h"
#include "cumsum-ops.h"
#define htp_cumsum_tensors_preamble \
const struct htp_tensor * restrict src0 = octx->src[0]; \
@@ -89,8 +91,8 @@ static inline HVX_Vector hvx_splat_last_f32(HVX_Vector v) {
}
static inline void hvx_cumsum_row_f32(const float * restrict src, float * restrict dst, uint32_t n) {
const uint32_t nvec = n / VLEN_FP32;
const uint32_t nloe = n % VLEN_FP32;
const uint32_t nvec = n >> 5;
const uint32_t nloe = n & (VLEN_FP32 - 1);
HVX_Vector carry = Q6_V_vsplat_R(0);
@@ -210,16 +212,19 @@ static void cumsum_thread_f32(unsigned int nth, unsigned int ith, void * data) {
int op_cumsum_f32(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
const struct htp_cumsum_kernel_params * kparams =
(const struct htp_cumsum_kernel_params *) octx->kernel_params;
const uint32_t total_rows = src0->ne[1] * src0->ne[2] * src0->ne[3];
const size_t dst_data_row_size = dst->ne[0] * sizeof(float);
const uint32_t total_rows = kparams->total_rows;
const size_t src_row_size = src0->nb[1];
const size_t dst_row_size = dst->nb[1];
uint32_t row_start = 0;
uint32_t nrows = total_rows;
if (octx->ctx->mdev.count > 1) {
uint32_t rows_per_chunk = 0;
htp_tensor_mdev_rows_per_chunk(dst, sizeof(float), (uint32_t) dst_data_row_size, &rows_per_chunk);
htp_tensor_mdev_rows_per_chunk(dst, sizeof(float), (uint32_t) dst_row_size, &rows_per_chunk);
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(total_rows, rows_per_chunk, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
row_start = range.start;
nrows = range.count;
@@ -229,43 +234,45 @@ int op_cumsum_f32(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, nrows))) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t n_threads = octx->n_threads;
const size_t src_row_size = src0->nb[1];
const size_t dst_row_size = dst->nb[1];
const size_t src_row_size_aligned = hex_round_up(src_row_size, VLEN);
const size_t dst_row_size_aligned = hex_round_up(dst_row_size, VLEN);
if (!kparams->use_dma && (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst))) {
return HTP_STATUS_NO_SUPPORT;
}
// 2 ping-pong buffers per thread for src and dst
const size_t spad_per_thread = 2 * (src_row_size_aligned + dst_row_size_aligned);
struct htp_cumsum_vtcm_layout layout = { 0 };
if (kparams->use_dma) {
htp_cumsum_vtcm_layout_build(&layout, src_row_size, dst_row_size, n_threads);
octx->src0_spad.size_per_thread = src_row_size_aligned * 2;
octx->dst_spad.size_per_thread = dst_row_size_aligned * 2;
octx->src0_spad.size = n_threads * octx->src0_spad.size_per_thread;
octx->dst_spad.size = n_threads * octx->dst_spad.size_per_thread;
octx->src0_spad.data = octx->ctx->vtcm_base; octx->src0_spad.src = NULL;
octx->dst_spad.data = octx->src0_spad.data + octx->src0_spad.size; octx->dst_spad.src = NULL;
octx->src0_spad.size_per_thread = layout.src0_bytes_per_thread;
octx->dst_spad.size_per_thread = layout.dst_bytes_per_thread;
octx->src0_spad.size = n_threads * layout.src0_bytes_per_thread;
octx->dst_spad.size = n_threads * layout.dst_bytes_per_thread;
octx->src0_spad.data = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_src0);
octx->dst_spad.data = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_dst);
octx->src0_spad.src = NULL;
octx->dst_spad.src = NULL;
}
struct htp_cumsum_context cctx = {
.octx = octx,
.src_row_size = src_row_size,
.dst_row_size = dst_row_size,
.src_row_size_aligned = src_row_size_aligned,
.dst_row_size_aligned = dst_row_size_aligned,
.src_row_size_aligned = layout.src_row_size_aligned,
.dst_row_size_aligned = layout.dst_row_size_aligned,
.rows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div),
.total_rows = nrows,
.row_start = row_start,
};
if (octx->ctx->vtcm_size < spad_per_thread * n_threads) {
if (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst)) {
return HTP_STATUS_NO_SUPPORT;
}
work_queue_run(octx->ctx->work_queue, cumsum_thread_f32, &cctx, n_threads);
} else {
if (kparams->use_dma) {
work_queue_run(octx->ctx->work_queue, cumsum_thread_f32_dma, &cctx, n_threads);
} else {
work_queue_run(octx->ctx->work_queue, cumsum_thread_f32, &cctx, n_threads);
}
return HTP_STATUS_OK;
+49
View File
@@ -0,0 +1,49 @@
#ifndef HTP_CUMSUM_OPS_H
#define HTP_CUMSUM_OPS_H
#include "hex-common.h"
#include "htp-vtcm.h"
#include <stdint.h>
struct htp_cumsum_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_dst;
size_t src_row_size_aligned;
size_t dst_row_size_aligned;
size_t src0_bytes_per_thread;
size_t dst_bytes_per_thread;
};
static inline void htp_cumsum_vtcm_layout_build(
struct htp_cumsum_vtcm_layout * L,
size_t src_row_size,
size_t dst_row_size,
uint32_t n_threads
) {
L->src_row_size_aligned = hex_round_up(src_row_size, 128);
L->dst_row_size_aligned = hex_round_up(dst_row_size, 128);
L->src0_bytes_per_thread = 2 * L->src_row_size_aligned;
L->dst_bytes_per_thread = 2 * L->dst_row_size_aligned;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
struct htp_cumsum_kernel_params {
uint32_t n_threads;
uint32_t total_rows;
uint32_t use_dma;
uint32_t vtcm_size;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_cumsum_kernel_params) <= 128, "htp_cumsum_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_cumsum_kernel_params) <= 128, "htp_cumsum_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_CUMSUM_OPS_H
+39 -42
View File
@@ -10,10 +10,12 @@
#include "htp-ctx.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "htp-vtcm.h"
#include "hvx-types.h"
#include "hex-utils.h"
#include "hvx-copy.h"
#include "dma-queue.h"
#include "diag-ops.h"
#define htp_diag_tensors_preamble \
const struct htp_tensor * restrict src0 = octx->src[0]; \
@@ -33,6 +35,7 @@
struct htp_diag_context {
struct htp_ops_context * octx;
const struct htp_diag_kernel_params * kparams;
size_t src_batch_size;
size_t dst_row_size;
size_t src_batch_size_aligned;
@@ -83,8 +86,8 @@ static void diag_thread_f32_dma(unsigned int nth, unsigned int ith, void * data)
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
for (uint32_t ib = ib0; ib < ib1; ib++) {
const uint32_t i3 = ib / ne02;
const uint32_t i2 = ib % ne02;
const uint32_t i3 = fastdiv(ib, &dctx->kparams->div_ne02);
const uint32_t i2 = ib - i3 * ne02;
const dma_addr_t src_batch = src_data + i3 * nb03 + i2 * nb02;
@@ -134,8 +137,8 @@ static void diag_thread_f32(unsigned int nth, unsigned int ith, void * data) {
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ib0);
for (uint32_t ib = ib0; ib < ib1; ib++) {
const uint32_t i3 = ib / ne02;
const uint32_t i2 = ib % ne02;
const uint32_t i3 = fastdiv(ib, &dctx->kparams->div_ne02);
const uint32_t i2 = ib - i3 * ne02;
const float * restrict src_batch = (const float *)(src_data + i3 * nb03 + i2 * nb02);
@@ -155,29 +158,17 @@ static void diag_thread_f32(unsigned int nth, unsigned int ith, void * data) {
int op_diag_f32(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
const struct htp_diag_kernel_params * kparams =
(const struct htp_diag_kernel_params *) octx->kernel_params;
const uint32_t total_batches = src0->ne[2] * src0->ne[3];
const size_t dst_batch_size = dst->ne[1] * dst->nb[1];
const uint32_t total_batches = kparams->total_batches;
uint32_t batch_start = 0;
uint32_t nbatches = total_batches;
if (octx->ctx->mdev.count > 1) {
bool can_split = htp_tensor_mdev_data_aligned(dst) && (dst->ne[0] == 1 || dst->nb[0] == sizeof(float)) && !htp_tensor_is_permuted(dst);
uint32_t batches_per_chunk = 1;
if (can_split) {
if (dst->ne[2] > 1 && (dst->nb[2] & (HTP_TENSOR_MDEV_LINE_SIZE - 1)) == 0 &&
(dst->ne[3] <= 1 || (dst->nb[3] & (HTP_TENSOR_MDEV_LINE_SIZE - 1)) == 0)) {
batches_per_chunk = 1;
} else if (dst->nb[2] == dst_batch_size &&
(dst->ne[3] <= 1 || dst->nb[3] == dst->nb[2] * dst->ne[2])) {
batches_per_chunk = (dst_batch_size > 0) ? (HEX_L2_LINE_SIZE / hex_gcd_u32(dst_batch_size, HEX_L2_LINE_SIZE)) : 1;
} else {
can_split = false;
}
}
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(total_batches, can_split ? batches_per_chunk : 0, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
const bool can_split = (kparams->can_split != 0) && htp_tensor_mdev_data_aligned(dst);
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(total_batches, can_split ? kparams->batches_per_chunk : 0, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
batch_start = range.start;
nbatches = range.count;
}
@@ -186,43 +177,49 @@ int op_diag_f32(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
const uint32_t n_threads = octx->n_threads;
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, nbatches))) {
return HTP_STATUS_INVAL_PARAMS;
}
const size_t src_batch_size = src0->ne[0] * sizeof(float);
const size_t dst_row_size = dst->ne[0] * sizeof(float);
const size_t src_batch_size_aligned = hex_round_up(src_batch_size, VLEN);
const size_t dst_row_size_aligned = hex_round_up(dst_row_size, VLEN);
const uint32_t n_threads = octx->n_threads;
// 1 src buffer + 1 dst row buffer per thread
const size_t spad_per_thread = src_batch_size_aligned + dst_row_size_aligned;
if (!kparams->use_dma && (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst))) {
return HTP_STATUS_NO_SUPPORT;
}
octx->src0_spad.size_per_thread = src_batch_size_aligned;
octx->dst_spad.size_per_thread = dst_row_size_aligned;
const size_t src_batch_size = src0->ne[0] * sizeof(float);
const size_t dst_row_size = dst->ne[0] * sizeof(float);
octx->src0_spad.size = n_threads * octx->src0_spad.size_per_thread;
octx->dst_spad.size = n_threads * octx->dst_spad.size_per_thread;
struct htp_diag_vtcm_layout layout = { 0 };
if (kparams->use_dma) {
htp_diag_vtcm_layout_build(&layout, src_batch_size, dst_row_size, n_threads);
octx->src0_spad.data = octx->ctx->vtcm_base; octx->src0_spad.src = NULL;
octx->dst_spad.data = octx->src0_spad.data + octx->src0_spad.size; octx->dst_spad.src = NULL;
octx->src0_spad.size_per_thread = layout.src0_bytes_per_thread;
octx->dst_spad.size_per_thread = layout.dst_bytes_per_thread;
octx->src0_spad.size = n_threads * layout.src0_bytes_per_thread;
octx->dst_spad.size = n_threads * layout.dst_bytes_per_thread;
octx->src0_spad.data = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_src0);
octx->dst_spad.data = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_dst);
octx->src0_spad.src = NULL;
octx->dst_spad.src = NULL;
}
struct htp_diag_context dctx = {
.octx = octx,
.kparams = kparams,
.src_batch_size = src_batch_size,
.dst_row_size = dst_row_size,
.src_batch_size_aligned = src_batch_size_aligned,
.dst_row_size_aligned = dst_row_size_aligned,
.src_batch_size_aligned = layout.src_batch_size_aligned,
.dst_row_size_aligned = layout.dst_row_size_aligned,
.batches_per_thread = fastdiv(nbatches + n_threads - 1, &octx->n_threads_div),
.total_batches = nbatches,
.batch_start = batch_start,
};
if (octx->ctx->vtcm_size < spad_per_thread * n_threads) {
if (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst)) {
return HTP_STATUS_NO_SUPPORT;
}
work_queue_run(octx->ctx->work_queue, diag_thread_f32, &dctx, n_threads);
} else {
if (kparams->use_dma) {
work_queue_run(octx->ctx->work_queue, diag_thread_f32_dma, &dctx, n_threads);
} else {
work_queue_run(octx->ctx->work_queue, diag_thread_f32, &dctx, n_threads);
}
return HTP_STATUS_OK;
+54
View File
@@ -0,0 +1,54 @@
#ifndef HTP_DIAG_OPS_H
#define HTP_DIAG_OPS_H
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
#include <stdint.h>
struct htp_diag_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_dst;
size_t src_batch_size_aligned;
size_t dst_row_size_aligned;
size_t src0_bytes_per_thread;
size_t dst_bytes_per_thread;
};
static inline void htp_diag_vtcm_layout_build(
struct htp_diag_vtcm_layout * L,
size_t src_batch_size,
size_t dst_row_size,
uint32_t n_threads
) {
L->src_batch_size_aligned = hex_round_up(src_batch_size, 128);
L->dst_row_size_aligned = hex_round_up(dst_row_size, 128);
L->src0_bytes_per_thread = L->src_batch_size_aligned;
L->dst_bytes_per_thread = L->dst_row_size_aligned;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
struct htp_diag_kernel_params {
uint32_t n_threads;
uint32_t total_batches;
uint32_t use_dma;
uint32_t can_split;
uint32_t batches_per_chunk;
uint32_t vtcm_size;
struct fastdiv_values div_ne02;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_diag_kernel_params) <= 128, "htp_diag_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_diag_kernel_params) <= 128, "htp_diag_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_DIAG_OPS_H
+3 -3
View File
@@ -436,10 +436,10 @@ static inline void dma_sync_write(dma_queue * dma_q, dma_addr_t dst, const void
}
}
#define DMA_CACHE_MAX_SIZE 256U
#define DMA_CACHE_MAX_SIZE 128U
// Fully assoc LRU cache
typedef struct {
typedef struct __attribute__((aligned(128))) {
uint8_t *base;
uint32_t line_size;
uint32_t capacity;
@@ -485,7 +485,7 @@ static inline bool dma_cache_fa_push(dma_queue *q, dma_cache_fa *c, dma_addr_t s
}
// Direct mapped cache
typedef struct {
typedef struct __attribute__((aligned(128))) {
uint8_t *base;
uint32_t line_size;
uint32_t capacity;
+56 -40
View File
@@ -16,6 +16,7 @@
#include "htp-ctx.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "fill-ops.h"
// ggml op_params layout for FILL:
// op_params[0] (as float) - the scalar fill value
@@ -30,21 +31,19 @@
\
const uint32_t nb1 = dst->nb[1]; \
const uint32_t nb2 = dst->nb[2]; \
const uint32_t nb3 = dst->nb[3]; \
\
const uint32_t nr = ne1 * ne2 * ne3;
const uint32_t nb3 = dst->nb[3];
struct htp_fill_context {
struct htp_ops_context * octx;
const struct htp_fill_kernel_params * kparams;
uint32_t nrows_per_thread;
uint32_t total_rows; // ne1 * ne2 * ne3
uint32_t row_start;
bool opt_path;
HVX_Vector splat_vec;
uint32_t elem_size;
};
static void fill_thread(unsigned int nth, unsigned int ith, void * data) {
static void fill_thread_contiguous(unsigned int nth, unsigned int ith, void * data) {
const struct htp_fill_context * fctx = (const struct htp_fill_context *) data;
struct htp_ops_context * octx = fctx->octx;
fill_preamble;
@@ -60,45 +59,59 @@ static void fill_thread(unsigned int nth, unsigned int ith, void * data) {
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir0);
if (fctx->opt_path) {
// Opt path: tensor is fully contiguous, treat as flat array
const uint32_t elem_start = ir0 * ne0;
const uint32_t elem_end = ir1 * ne0;
uint8_t * dst_ptr = (uint8_t *) dst->data + elem_start * fctx->elem_size;
hvx_splat_u(dst_ptr, fctx->splat_vec, elem_end - elem_start, fctx->elem_size);
} else {
// Non-contiguous path: must respect strides
for (uint32_t ir = ir0; ir < ir1; ++ir) {
const uint32_t i1 = ir % ne1;
const uint32_t i2 = (ir / ne1) % ne2;
const uint32_t i3 = ir / (ne1 * ne2);
uint8_t * dst_ptr = (uint8_t *) dst->data + i1*nb1 + i2*nb2 + i3*nb3;
hvx_splat_u(dst_ptr, fctx->splat_vec, ne0, fctx->elem_size);
}
const uint32_t elem_start = ir0 * ne0;
const uint32_t elem_end = ir1 * ne0;
uint8_t * dst_ptr = (uint8_t *) dst->data + elem_start * fctx->elem_size;
hvx_splat_u(dst_ptr, fctx->splat_vec, elem_end - elem_start, fctx->elem_size);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir1);
FARF(HIGH, "fill-contig %u/%u: rows %u:%u\n", ith, nth, ir0, ir1);
}
static void fill_thread_strided(unsigned int nth, unsigned int ith, void * data) {
const struct htp_fill_context * fctx = (const struct htp_fill_context *) data;
struct htp_ops_context * octx = fctx->octx;
const struct htp_fill_kernel_params * kparams = fctx->kparams;
fill_preamble;
// Parallelise over the flat row index spanning ne1*ne2*ne3
const uint32_t ir0 = fctx->row_start + fctx->nrows_per_thread * ith;
const uint32_t ir1 = MIN(ir0 + fctx->nrows_per_thread, fctx->row_start + fctx->total_rows);
if (ir0 >= ir1) {
return;
}
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir0);
for (uint32_t ir = ir0; ir < ir1; ++ir) {
const uint32_t i3 = fastdiv(ir, &kparams->div_ne1_ne2);
const uint32_t rem = ir - i3 * (ne1 * ne2);
const uint32_t i2 = fastdiv(rem, &kparams->div_ne1);
const uint32_t i1 = rem - i2 * ne1;
uint8_t * dst_ptr = (uint8_t *) dst->data + i1*nb1 + i2*nb2 + i3*nb3;
hvx_splat_u(dst_ptr, fctx->splat_vec, ne0, fctx->elem_size);
}
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir1);
FARF(HIGH, "fill %u/%u: rows %u:%u\n", ith, nth, ir0, ir1);
FARF(HIGH, "fill-strided %u/%u: rows %u:%u\n", ith, nth, ir0, ir1);
}
int op_fill(struct htp_ops_context * octx) {
fill_preamble;
if (dst->type != HTP_TYPE_F32 && dst->type != HTP_TYPE_F16) {
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_tensor * dst = octx->dst;
const struct htp_fill_kernel_params * kparams =
(const struct htp_fill_kernel_params *) octx->kernel_params;
if (htp_tensor_is_extended(dst)) {
return HTP_STATUS_NO_SUPPORT;
}
uint32_t row_start = 0;
uint32_t nrows = nr;
uint32_t nrows = kparams->total_rows;
if (octx->ctx->mdev.count > 1) {
const uint32_t row_size = nb1;
const uint32_t rows_per_chunk = (row_size > 0) ? (HEX_L2_LINE_SIZE / hex_gcd_u32(row_size, HEX_L2_LINE_SIZE)) : 1;
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(nr, htp_tensor_mdev_data_aligned(dst) ? rows_per_chunk : 0, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(kparams->total_rows, htp_tensor_mdev_data_aligned(dst) ? kparams->rows_per_chunk : 0, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
row_start = range.start;
nrows = range.count;
}
@@ -107,40 +120,43 @@ int op_fill(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
// nr = ne1*ne2*ne3 (flat row count across all outer dims); parallelise over it.
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, nrows))) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t n_threads = octx->n_threads;
// Optimize if fully contiguous: skip stride arithmetic, treat as flat array
const bool opt_path = (nb2 == nb1 * ne1) && (nb3 == nb2 * ne2);
FARF(HIGH, "fill: (%ux%ux%ux%u) type=%u opt=%d\n",
dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3], dst->type, (int) opt_path);
FARF(HIGH, "fill: (%ux%ux%ux%u) type=%u ktype=%u\n",
dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3], dst->type, kparams->kernel_type);
float val_f32 = 0.f;
memcpy(&val_f32, &octx->op_params[0], sizeof(float));
struct htp_fill_context fctx = {
.octx = octx,
.kparams = kparams,
.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div),
.total_rows = nrows,
.row_start = row_start,
.opt_path = opt_path,
.elem_size = kparams->elem_size,
};
switch (dst->type) {
case HTP_TYPE_F32:
fctx.splat_vec = hvx_vec_splat_f32(val_f32);
fctx.elem_size = sizeof(float);
break;
case HTP_TYPE_F16:
fctx.splat_vec = hvx_vec_splat_f16((_Float16) val_f32);
fctx.elem_size = sizeof(_Float16);
break;
default:
return HTP_STATUS_NO_SUPPORT;
}
work_queue_run(octx->ctx->work_queue, fill_thread, &fctx, n_threads);
work_queue_func_t worker = (kparams->kernel_type == HTP_FILL_KERNEL_CONTIGUOUS)
? fill_thread_contiguous
: fill_thread_strided;
work_queue_run(octx->ctx->work_queue, worker, &fctx, n_threads);
return HTP_STATUS_OK;
}
+29
View File
@@ -0,0 +1,29 @@
#ifndef HTP_FILL_OPS_H
#define HTP_FILL_OPS_H
#include "hex-fastdiv.h"
#include <stdint.h>
enum htp_fill_kernel_type {
HTP_FILL_KERNEL_CONTIGUOUS = 0,
HTP_FILL_KERNEL_STRIDED = 1,
};
struct htp_fill_kernel_params {
uint8_t kernel_type;
uint32_t n_threads;
uint32_t total_rows;
uint32_t elem_size;
uint32_t rows_per_chunk;
struct fastdiv_values div_ne1;
struct fastdiv_values div_ne1_ne2;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_fill_kernel_params) <= 128, "htp_fill_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_fill_kernel_params) <= 128, "htp_fill_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_FILL_OPS_H
+59 -24
View File
@@ -39,6 +39,26 @@
// Must be multiple of 32
#define FLASH_ATTN_BLOCK_SIZE (32 * 2)
// Large scratch lives in ctx->ddr_spad to keep stack usage low.
// Ops can run on the dspqueue callback thread, which has a small stack.
struct hvx_fa_ddr_spad {
__fp16 slopes[512];
uint16_t active_blocks[FA_MAX_KV_BLOCKS];
uint16_t thread_active_blocks[HTP_MAX_NTHREADS][FA_MAX_KV_BLOCKS] __attribute__((aligned(128)));
};
struct hmx_fa_ddr_spad {
uint16_t active_blocks[FA_MAX_KV_BLOCKS];
__fp16 slopes[] __attribute__((aligned(128))); // [g_br]
};
static inline void * fa_get_ddr_spad(const struct htp_ops_context * octx, size_t size) {
if (!octx->ctx->ddr_spad_base || octx->ctx->ddr_spad_size < size) {
return NULL;
}
return octx->ctx->ddr_spad_base;
}
struct htp_fa_context {
const struct htp_ops_context * octx;
@@ -61,7 +81,6 @@ struct htp_fa_context {
uint32_t n_head_log2;
float m0;
float m1;
__fp16 slopes[512];
uint32_t n_blocks;
uint32_t n_active_blocks;
@@ -90,7 +109,9 @@ struct htp_fa_context {
uint8_t * spad_m;
uint8_t * spad_a;
float * spad_sinks;
uint16_t active_blocks[FA_MAX_KV_BLOCKS];
struct hvx_fa_ddr_spad * ddr;
dma_cache_dm * m_cache; // [n_threads]
const struct htp_tensor * k;
const struct htp_tensor * v;
@@ -156,6 +177,7 @@ struct hmx_fa_context {
__fp16 * vtcm_mask_buf; // VTCM mask buffer [Br * m_line], DMA'd per KV block
__fp16 * vtcm_slopes; // ALiBi slopes [g_br]
float * vtcm_sinks; // Attention sinks
__fp16 * ddr_slopes; // ALiBi slopes staging buffer in DDR [g_br]
size_t row_buf_stride; // HVX vectors per row buffer (Bc/64)
size_t mask_buf_row_stride; // elements (__fp16) per row in mask buffer
size_t q_tile_bytes;
@@ -164,7 +186,7 @@ struct hmx_fa_context {
size_t col_vec_bytes;
size_t d_tile_bytes;
bool mask_broadcast; // true when mask->ne[2] == 1 (head-independent, single 2D DMA)
dma_cache_fa m_cache;
dma_cache_fa * m_cache;
};
// Scan mask rows [q_start, q_start + n_rows_q) and build compact list of KV blocks with any entry != -inf.
@@ -308,11 +330,11 @@ static void flash_attn_ext_f16_thread(unsigned int nth, unsigned int ith, void *
uint8_t * spad_m = factx->spad_m + (mask ? factx->size_m_block * HVX_FA_DMA_CACHE_SIZE : 0) * ith;
uint8_t * spad_a = factx->spad_a + factx->size_vkq_acc * ith;
dma_cache_dm m_cache;
dma_cache_dm_init(&m_cache, spad_m, factx->size_m_block, HVX_FA_DMA_CACHE_SIZE);
dma_cache_dm * m_cache = &factx->m_cache[ith];
dma_cache_dm_init(m_cache, spad_m, factx->size_m_block, HVX_FA_DMA_CACHE_SIZE);
uint16_t thread_active_blocks[FA_MAX_KV_BLOCKS];
const uint16_t * active_blocks = factx->shared_active_blocks ? factx->active_blocks : thread_active_blocks;
uint16_t * thread_active_blocks = factx->ddr->thread_active_blocks[ith];
const uint16_t * active_blocks = factx->shared_active_blocks ? factx->ddr->active_blocks : thread_active_blocks;
uint32_t n_active_blocks = factx->n_active_blocks;
dma_addr_t prev_mp_base = 0;
@@ -385,7 +407,7 @@ static void flash_attn_ext_f16_thread(unsigned int nth, unsigned int ith, void *
const uint32_t r_iq1 = (r - r_iq3*neq2*neq1 - r_iq2 * neq1);
heads[g] = r_iq2;
const __fp16 slope = factx->slopes[r_iq2];
const __fp16 slope = factx->ddr->slopes[r_iq2];
slope_vecs[g] = hvx_vec_splat_f16(slope);
S_vec[g] = hvx_vec_splat_f32(0.0f);
@@ -422,7 +444,7 @@ static void flash_attn_ext_f16_thread(unsigned int nth, unsigned int ith, void *
// Mask
if (mask) {
const dma_addr_t m_src = mp_base + ic_start * sizeof(__fp16);
dma_cache_dm_push(dma_q, &m_cache, ib, m_src, current_block_size * 2, current_block_size * 2, current_block_size * 2, 1);
dma_cache_dm_push(dma_q, m_cache, ib, m_src, current_block_size * 2, current_block_size * 2, current_block_size * 2, 1);
}
}
@@ -682,7 +704,7 @@ static void flash_attn_ext_f16_thread(unsigned int nth, unsigned int ith, void *
// Mask
if (mask) {
const dma_addr_t m_src = mp_base + next_ic_start * sizeof(__fp16);
dma_cache_dm_push(dma_q, &m_cache, next_ib, m_src, next_block_size * 2, next_block_size * 2, next_block_size * 2, 1);
dma_cache_dm_push(dma_q, m_cache, next_ib, m_src, next_block_size * 2, next_block_size * 2, next_block_size * 2, 1);
}
}
} // end for g
@@ -1887,7 +1909,7 @@ static __attribute__((noinline)) void fa_compute_slopes(
const float m0 = factx->m0;
const float m1 = factx->m1;
__fp16 temp_slopes[512] __attribute__((aligned(128)));
__fp16 * temp_slopes = factx->ddr_slopes;
if (G <= 32) {
// Fast path: Compute G unique slope values in vector registers
HVX_Vector v_val = hvx_alibi_slopes(kv_head, G, n_head_log2, m0, m1);
@@ -1905,14 +1927,13 @@ static __attribute__((noinline)) void fa_compute_slopes(
}
}
// Allocate stack buffer to avoid scalar writes to VTCM (which generates L2 misses)
__fp16 local_slopes[n_rows_g] __attribute__((aligned(128)));
for (size_t r = 0; r < n_rows_g; ++r) {
local_slopes[r] = temp_slopes[fastmodulo(r, G, &factx->div_G)];
// Replicate the G values in DDR to avoid scalar writes to VTCM (which generates L2 misses)
for (size_t r = G; r < n_rows_g; ++r) {
temp_slopes[r] = temp_slopes[r - G];
}
// Copy to VTCM slopes using HVX block copy (both are aligned to 128 bytes)
hvx_copy_f16_aa((uint8_t *)slopes, (const uint8_t *)local_slopes, n_rows_g);
hvx_copy_f16_aa((uint8_t *)slopes, (const uint8_t *)temp_slopes, n_rows_g);
}
static void fa_push_mask_dma_gqa(
@@ -1958,7 +1979,7 @@ static inline void fa_prefetch_block(dma_queue * dma_q, const struct htp_tensor
if (mask) {
if (__builtin_expect(factx->mask_broadcast, true)) {
const dma_addr_t ms_src = mask->data + q_start * mask->nb[1] + im3 * mask->nb[3] + prefetch_start * sizeof(__fp16);
dma_cache_fa_push(dma_q, &factx->m_cache, ms_src, m_line_bytes, mask->nb[1], prefetch_rows * sizeof(__fp16), n_rows_q);
dma_cache_fa_push(dma_q, factx->m_cache, ms_src, m_line_bytes, mask->nb[1], prefetch_rows * sizeof(__fp16), n_rows_q);
} else {
fa_push_mask_dma_gqa(dma_q, mask, q_start, im3, prefetch_start, kv_head, G, m_line_bytes, prefetch_rows, n_rows_q, factx);
}
@@ -2151,7 +2172,14 @@ int hmx_flash_attn_ext(struct htp_ops_context * octx) {
const size_t m_line_bytes = L.m_line_bytes; // used by the mask DMAs in the KV loop
dma_cache_fa_init(&factx.m_cache, (uint8_t *) factx.vtcm_mask_buf, L.m_buf_slot_bytes, HMX_FA_DMA_CACHE_SIZE);
struct hmx_fa_ddr_spad * ddr = (struct hmx_fa_ddr_spad *) fa_get_ddr_spad(octx, sizeof(struct hmx_fa_ddr_spad) + factx.g_br * sizeof(__fp16));
if (!ddr) {
return HTP_STATUS_INTERNAL_ERR;
}
factx.ddr_slopes = ddr->slopes;
factx.m_cache = &octx->dma_cache_fa[0];
dma_cache_fa_init(factx.m_cache, (uint8_t *) factx.vtcm_mask_buf, L.m_buf_slot_bytes, HMX_FA_DMA_CACHE_SIZE);
// Head-dim padding: the K/V DMA staging buffers and the flat-Q buffer are laid out
// with padded row strides (size_{k,v,q}_row_padded, covering D_pad columns) but the
@@ -2210,7 +2238,7 @@ int hmx_flash_attn_ext(struct htp_ops_context * octx) {
const size_t g_br_actual = hex_align_up(n_rows_g, HMX_FP16_TILE_N_ROWS);
const size_t n_row_tiles = g_br_actual / HMX_FP16_TILE_N_ROWS;
uint16_t active_blocks[FA_MAX_KV_BLOCKS];
uint16_t * active_blocks = ddr->active_blocks;
uint32_t n_active_blocks = factx.n_kv_blocks;
if (mask && factx.mask_broadcast && factx.n_kv_blocks > 1) {
const size_t scratch_bytes = factx.k_tile_bytes * (factx.pipeline ? 2 : 1);
@@ -2252,7 +2280,7 @@ int hmx_flash_attn_ext(struct htp_ops_context * octx) {
if (factx.pipeline && mask) {
if (__builtin_expect(factx.mask_broadcast, true)) {
const dma_addr_t ms_src = mask->data + q_start * mask->nb[1] + im3 * mask->nb[3] + b0_start * sizeof(__fp16);
dma_cache_fa_push(dma_q, &factx.m_cache, ms_src, m_line_bytes, mask->nb[1], b0_rows * sizeof(__fp16), n_rows_q);
dma_cache_fa_push(dma_q, factx.m_cache, ms_src, m_line_bytes, mask->nb[1], b0_rows * sizeof(__fp16), n_rows_q);
} else {
fa_push_mask_dma_gqa(dma_q, mask, q_start, im3, b0_start, kv_head, G, m_line_bytes, b0_rows, n_rows_q, &factx);
}
@@ -2453,7 +2481,7 @@ int hmx_flash_attn_ext(struct htp_ops_context * octx) {
if (mask) {
if (__builtin_expect(factx.mask_broadcast, true)) {
const dma_addr_t ms_src = mask->data + q_start * mask->nb[1] + im3 * mask->nb[3] + kv_start * sizeof(__fp16);
dma_cache_fa_push(dma_q, &factx.m_cache, ms_src, m_line_bytes, mask->nb[1], kv_rows * sizeof(__fp16), n_rows_q);
dma_cache_fa_push(dma_q, factx.m_cache, ms_src, m_line_bytes, mask->nb[1], kv_rows * sizeof(__fp16), n_rows_q);
} else {
fa_push_mask_dma_gqa(dma_q, mask, q_start, im3, kv_start, kv_head, G, m_line_bytes, kv_rows, n_rows_q, &factx);
}
@@ -2577,7 +2605,7 @@ int hmx_flash_attn_ext(struct htp_ops_context * octx) {
if (factx.pipeline && mask) {
if (__builtin_expect(factx.mask_broadcast, true)) {
const dma_addr_t ms_src = mask->data + q_start * mask->nb[1] + im3 * mask->nb[3] + b0_start * sizeof(__fp16);
dma_cache_fa_push(dma_q, &factx.m_cache, ms_src, m_line_bytes, mask->nb[1], b0_rows * sizeof(__fp16), n_rows_q);
dma_cache_fa_push(dma_q, factx.m_cache, ms_src, m_line_bytes, mask->nb[1], b0_rows * sizeof(__fp16), n_rows_q);
} else {
fa_push_mask_dma_gqa(dma_q, mask, q_start, im3, b0_start, next_kv_head, G, m_line_bytes, b0_rows, n_rows_q, &factx);
}
@@ -2680,8 +2708,15 @@ int op_flash_attn_ext(struct htp_ops_context * octx) {
if (n_head > 512) {
return HTP_STATUS_NO_SUPPORT;
}
factx.ddr = (struct hvx_fa_ddr_spad *) fa_get_ddr_spad(octx, sizeof(struct hvx_fa_ddr_spad));
if (!factx.ddr) {
return HTP_STATUS_INTERNAL_ERR;
}
factx.m_cache = octx->dma_cache_dm;
for (uint32_t h = 0; h < n_head; ++h) {
factx.slopes[h] = (__fp16) ((kparams->max_bias > 0.0f) ? alibi_slope(h, factx.n_head_log2, factx.m0, factx.m1) : 1.0f);
factx.ddr->slopes[h] = (__fp16) ((kparams->max_bias > 0.0f) ? alibi_slope(h, factx.n_head_log2, factx.m0, factx.m1) : 1.0f);
}
// total rows in q
@@ -2754,7 +2789,7 @@ int op_flash_attn_ext(struct htp_ops_context * octx) {
if (has_mask && neq1 == 1 && neq3 == 1 && mask->ne[2] == 1 && factx.n_blocks > 1 && factx.n_blocks <= FA_MAX_KV_BLOCKS) {
factx.n_active_blocks = fa_scan_active_blocks(
octx->ctx->dma[0], mask, 0, 1, 0, 0, k->ne[1], FLASH_ATTN_BLOCK_SIZE,
factx.n_blocks, factx.spad_k, factx.size_k_block * 2, factx.active_blocks);
factx.n_blocks, factx.spad_k, factx.size_k_block * 2, factx.ddr->active_blocks);
factx.shared_active_blocks = true;
}
+2 -6
View File
@@ -35,7 +35,6 @@ enum htp_fa_kernel_type {
struct htp_fa_kernel_params {
uint8_t kernel_type; // enum htp_fa_kernel_type
uint8_t head_split; // 1 = partition by KV heads in multicore, 0 = token partition
uint8_t flags; // reserved
uint8_t n_threads; // Number of threads to run
// Common parameters
@@ -49,9 +48,6 @@ struct htp_fa_kernel_params {
float logit_softcap;
uint32_t vtcm_size;
uint32_t qrows;
uint32_t qrows_per_thread;
uint32_t qrow_start;
float m0;
float m1;
uint32_t n_head_log2;
@@ -67,8 +63,6 @@ struct htp_fa_kernel_params {
union {
struct {
uint32_t g_br;
uint32_t row_buf_stride;
uint32_t mask_buf_row_stride;
int32_t mask_broadcast;
int32_t pipeline;
struct fastdiv_values div_G;
@@ -85,6 +79,8 @@ struct htp_fa_kernel_params {
#if defined(__cplusplus)
static_assert(sizeof(struct htp_fa_kernel_params) <= 128, "htp_fa_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_fa_kernel_params) <= 128, "htp_fa_kernel_params is too large for kernel_params blob");
#endif
// VTCM region layout for the HMX flash-attention kernel.
+12 -105
View File
@@ -2270,46 +2270,9 @@ static int gated_delta_net_f32_hmx_chunked(
}
int op_gated_delta_net(struct htp_ops_context * octx) {
const struct htp_tensor * q = octx->src[0];
const struct htp_tensor * k = octx->src[1];
const struct htp_tensor * v = octx->src[2];
const struct htp_tensor * g = octx->src[3];
const struct htp_tensor * beta = octx->src[4];
const struct htp_tensor * state = octx->src[5];
const struct htp_tensor * dst = octx->dst;
const struct htp_tensor * dst = octx->dst;
if (q->type != HTP_TYPE_F32 || k->type != HTP_TYPE_F32 || v->type != HTP_TYPE_F32 ||
g->type != HTP_TYPE_F32 || beta->type != HTP_TYPE_F32 || state->type != HTP_TYPE_F32 ||
dst->type != HTP_TYPE_F32) {
return HTP_STATUS_NO_SUPPORT;
}
const uint32_t S_v = v->ne[0];
const uint32_t H = v->ne[1];
const uint32_t n_tokens = v->ne[2];
const uint32_t n_seqs = v->ne[3];
const uint32_t K = octx->op_params[0];
if (S_v == 0 || S_v > HTP_GDN_MAX_SV || H == 0 || n_tokens == 0 || n_seqs == 0) {
return HTP_STATUS_NO_SUPPORT;
}
if ((g->ne[0] != 1 && g->ne[0] != S_v) || beta->ne[0] != 1) {
return HTP_STATUS_NO_SUPPORT;
}
if (q->ne[0] != S_v || k->ne[0] != S_v || q->ne[1] == 0 || k->ne[1] == 0 ||
q->ne[2] != n_tokens || k->ne[2] != n_tokens || q->ne[3] == 0 || k->ne[3] == 0 ||
(n_seqs % q->ne[3]) != 0 || (n_seqs % k->ne[3]) != 0) {
return HTP_STATUS_NO_SUPPORT;
}
// state holds s0 only: [S_v, S_v, H, n_seqs]
if (state->ne[0] != S_v || state->ne[1] != S_v || state->ne[2] != H || state->ne[3] != n_seqs) {
return HTP_STATUS_NO_SUPPORT;
}
if (dst->ne[0] != S_v * H || dst->ne[1] != n_tokens * n_seqs + S_v * n_seqs * K) {
return HTP_STATUS_NO_SUPPORT;
}
for (int i = 0; i < 5; i++) {
for (int i = 0; i < 6; i++) {
if (htp_tensor_is_extended(octx->src[i])) {
return HTP_STATUS_NO_SUPPORT;
}
@@ -2325,68 +2288,12 @@ int op_gated_delta_net(struct htp_ops_context * octx) {
}
const struct htp_gdn_kernel_params * kparams = (const struct htp_gdn_kernel_params *) octx->kernel_params;
struct htp_gdn_kernel_params kparams_local;
if (!kparams || kparams->S_v == 0) {
const uint32_t rq3 = n_seqs / q->ne[3];
const uint32_t rk3 = n_seqs / k->ne[3];
const uint32_t total_rows = H * n_seqs;
uint32_t n_threads = (total_rows < octx->n_threads) ? total_rows : octx->n_threads;
if (n_threads == 0) {
n_threads = 1;
}
memset(&kparams_local, 0, sizeof(kparams_local));
kparams_local.n_threads = n_threads;
kparams_local.S_v = S_v;
kparams_local.H = H;
kparams_local.n_tokens = n_tokens;
kparams_local.n_seqs = n_seqs;
kparams_local.K = K;
kparams_local.total_rows = total_rows;
kparams_local.rows_per_thread = (total_rows + n_threads - 1) / n_threads;
const bool can_use_hmx = (octx->ctx->hmx_enabled) &&
(S_v % 64 == 0) &&
(n_tokens >= HTP_GDN_MIN_TOKENS) &&
(g->ne[0] == 1) &&
(K == 1);
struct htp_gdn_hmx_vtcm_layout hmx_layout_local;
struct htp_gdn_vtcm_layout hvx_layout_local;
uint32_t n_heads_batch = 1;
if (can_use_hmx && htp_gdn_hmx_solve_layout(&hmx_layout_local, S_v, HTP_GDN_CHUNK_SIZE, total_rows, octx->ctx->vtcm_size, n_threads, true, &n_heads_batch)) {
kparams_local.kernel_type = HTP_GDN_KERNEL_HMX_CHUNKED;
kparams_local.pipeline = hmx_layout_local.pipeline ? 1 : 0;
kparams_local.chunk_size = HTP_GDN_CHUNK_SIZE;
kparams_local.n_chunks = (n_tokens + HTP_GDN_CHUNK_SIZE - 1) / HTP_GDN_CHUNK_SIZE;
kparams_local.n_heads_batch = (uint16_t) n_heads_batch;
kparams_local.vtcm_size = (uint32_t) hmx_layout_local.total_bytes;
kparams_local.state_aligned = (uint32_t) hmx_layout_local.state_f32_bytes;
kparams_local.vtcm_per_thread = (uint32_t) (hmx_layout_local.total_bytes / (n_threads > 0 ? n_threads : 1));
} else {
htp_gdn_vtcm_layout_build(&hvx_layout_local, S_v, n_threads);
kparams_local.kernel_type = HTP_GDN_KERNEL_HVX_RECURRENT;
kparams_local.pipeline = 0;
kparams_local.n_heads_batch = 1;
kparams_local.state_aligned = (uint32_t) hvx_layout_local.state_aligned;
kparams_local.vtcm_per_thread = (uint32_t) hvx_layout_local.bytes_per_thread;
kparams_local.vtcm_size = (uint32_t) hvx_layout_local.total_bytes;
}
kparams_local.kda = (g->ne[0] == S_v) ? 1 : 0;
kparams_local.scale = 1.0f / sqrtf((float) S_v);
kparams_local.state_seq_stride = (uint32_t) (state->nb[3] / sizeof(float));
kparams_local.state_size_per_snap = S_v * S_v * H * n_seqs;
kparams_local.div_H = init_fastdiv_values(H);
kparams_local.div_q1 = init_fastdiv_values(q->ne[1]);
kparams_local.div_k1 = init_fastdiv_values(k->ne[1]);
kparams_local.div_rq3 = init_fastdiv_values(rq3);
kparams_local.div_rk3 = init_fastdiv_values(rk3);
kparams_local.div_n_threads = init_fastdiv_values(n_threads);
kparams = &kparams_local;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t S_v = kparams->S_v;
const uint32_t n_tokens = kparams->n_tokens;
const uint32_t total_rows = kparams->total_rows;
uint32_t row_start = 0;
uint32_t nrows = total_rows;
@@ -2416,16 +2323,16 @@ int op_gated_delta_net(struct htp_ops_context * octx) {
return gated_delta_net_f32_hmx_chunked(octx, kparams, row_start, nrows);
}
const uint32_t n_threads = (nrows < kparams->n_threads) ? nrows : kparams->n_threads;
const uint32_t n_threads = (nrows < octx->n_threads) ? nrows : octx->n_threads;
struct htp_gdn_context gctx;
gctx.octx = octx;
gctx.kparams = kparams;
gctx.row_start = row_start;
gctx.nrows = nrows;
gctx.vtcm_base = octx->ctx->vtcm_base;
htp_gdn_vtcm_layout_build(&gctx.layout, S_v, n_threads);
gctx.vtcm_base = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, gctx.layout.off_state);
if (gctx.layout.total_bytes > octx->ctx->vtcm_size) {
return HTP_STATUS_VTCM_TOO_SMALL;
@@ -2433,10 +2340,10 @@ int op_gated_delta_net(struct htp_ops_context * octx) {
FARF(HIGH, "gated-delta-net-f32: q(%ux%ux%ux%u) k(%ux%ux%ux%u) v(%ux%ux%ux%u) state(%ux%ux%ux%u) -> (%ux%ux%ux%u) : "
"vtcm-size %zu n_threads %u\n",
q->ne[0], q->ne[1], q->ne[2], q->ne[3],
k->ne[0], k->ne[1], k->ne[2], k->ne[3],
v->ne[0], v->ne[1], v->ne[2], v->ne[3],
state->ne[0], state->ne[1], state->ne[2], state->ne[3],
octx->src[0]->ne[0], octx->src[0]->ne[1], octx->src[0]->ne[2], octx->src[0]->ne[3],
octx->src[1]->ne[0], octx->src[1]->ne[1], octx->src[1]->ne[2], octx->src[1]->ne[3],
octx->src[2]->ne[0], octx->src[2]->ne[1], octx->src[2]->ne[2], octx->src[2]->ne[3],
octx->src[5]->ne[0], octx->src[5]->ne[1], octx->src[5]->ne[2], octx->src[5]->ne[3],
dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3],
gctx.layout.total_bytes, n_threads);
@@ -37,13 +37,7 @@ struct htp_gdn_kernel_params {
uint32_t K;
uint32_t total_rows;
uint32_t row_start;
uint32_t nrows;
uint32_t rows_per_thread;
uint32_t kda;
uint32_t state_aligned;
uint32_t vtcm_per_thread;
uint32_t vtcm_size;
uint32_t state_seq_stride;
uint32_t state_size_per_snap;
@@ -55,7 +49,6 @@ struct htp_gdn_kernel_params {
struct fastdiv_values div_k1;
struct fastdiv_values div_rq3;
struct fastdiv_values div_rk3;
struct fastdiv_values div_n_threads;
};
#if defined(__cplusplus)
@@ -67,18 +60,21 @@ _Static_assert(sizeof(struct htp_gdn_kernel_params) <= 128, "htp_gdn_kernel_para
struct htp_gdn_vtcm_layout {
size_t state_aligned;
size_t bytes_per_thread;
size_t off_state;
size_t total_bytes;
};
static inline void htp_gdn_vtcm_layout_build(
struct htp_gdn_vtcm_layout * layout,
struct htp_gdn_vtcm_layout * L,
uint32_t S_v,
uint32_t n_threads
) {
size_t state_bytes = (size_t) S_v * S_v * sizeof(float);
layout->state_aligned = hex_round_up(state_bytes, 128);
layout->bytes_per_thread = 2 * layout->state_aligned;
layout->total_bytes = layout->bytes_per_thread * n_threads;
L->state_aligned = hex_round_up(state_bytes, 128);
L->bytes_per_thread = 2 * L->state_aligned;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_state, L->bytes_per_thread * n_threads);
L->total_bytes = off;
}
struct htp_gdn_hmx_vtcm_layout {
+30 -14
View File
@@ -206,14 +206,22 @@ static void gather_rows_thread_f32(unsigned int nth, unsigned int ith, void * da
struct htp_thread_trace * tr = &task->octx->ctx->trace[ith];
uint8_t * base = task->octx->ctx->vtcm_base + ith * kparams->slice;
HVX_Vector * tab = (HVX_Vector *) base;
HVX_Vector * inc = tab + kparams->vg;
HVX_Vector * cur = inc + kparams->vg;
uint8_t * region_base = (uint8_t *) (cur + kparams->vg);
struct htp_gather_rows_vtcm_layout layout;
htp_gather_rows_vtcm_layout_build(&layout, kparams->vg, kparams->region_size, kparams->nr_max, kparams->ne, 4);
uint8_t * region[2] = { region_base, region_base + kparams->buf_stride };
uint8_t * out[2] = { region[0] + kparams->out_off, region[1] + kparams->out_off };
uint8_t * base = VTCM_LAYOUT_PTR(uint8_t, task->octx->ctx->vtcm_base, (size_t) ith * kparams->slice);
HVX_Vector * tab = VTCM_LAYOUT_PTR(HVX_Vector, base, layout.off_tab);
HVX_Vector * inc = VTCM_LAYOUT_PTR(HVX_Vector, base, layout.off_inc);
HVX_Vector * cur = VTCM_LAYOUT_PTR(HVX_Vector, base, layout.off_cur);
uint8_t * region[2] = {
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_region0),
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_region1),
};
uint8_t * out[2] = {
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_out0),
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_out1),
};
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, (uint16_t) r_beg);
gather_rows_init_tables_f32(tab, inc, kparams, a, b);
@@ -279,14 +287,22 @@ static void gather_rows_thread_f16(unsigned int nth, unsigned int ith, void * da
struct htp_thread_trace * tr = &task->octx->ctx->trace[ith];
uint8_t * base = task->octx->ctx->vtcm_base + ith * kparams->slice;
HVX_Vector * tab = (HVX_Vector *) base;
HVX_Vector * inc = tab + kparams->vg;
HVX_Vector * cur = inc + kparams->vg;
uint8_t * region_base = (uint8_t *) (cur + kparams->vg);
struct htp_gather_rows_vtcm_layout layout;
htp_gather_rows_vtcm_layout_build(&layout, kparams->vg, kparams->region_size, kparams->nr_max, kparams->ne, 2);
uint8_t * region[2] = { region_base, region_base + kparams->buf_stride };
uint8_t * out[2] = { region[0] + kparams->out_off, region[1] + kparams->out_off };
uint8_t * base = VTCM_LAYOUT_PTR(uint8_t, task->octx->ctx->vtcm_base, (size_t) ith * kparams->slice);
HVX_Vector * tab = VTCM_LAYOUT_PTR(HVX_Vector, base, layout.off_tab);
HVX_Vector * inc = VTCM_LAYOUT_PTR(HVX_Vector, base, layout.off_inc);
HVX_Vector * cur = VTCM_LAYOUT_PTR(HVX_Vector, base, layout.off_cur);
uint8_t * region[2] = {
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_region0),
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_region1),
};
uint8_t * out[2] = {
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_out0),
VTCM_LAYOUT_PTR(uint8_t, base, layout.off_out1),
};
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, (uint16_t) r_beg);
gather_rows_init_tables_f16(tab, inc, kparams, a, b);
+38 -9
View File
@@ -2,6 +2,7 @@
#define HTP_GATHER_ROWS_H
#include "hex-common.h"
#include "htp-vtcm.h"
#include <stdint.h>
#include <stdbool.h>
@@ -19,8 +20,6 @@ struct htp_gather_rows_params {
uint32_t v1;
uint32_t span1;
uint32_t region_size;
uint32_t out_off;
uint32_t buf_stride;
uint32_t slice;
uint32_t total_rows;
uint32_t rows_per_thread;
@@ -28,6 +27,40 @@ struct htp_gather_rows_params {
uint8_t pad[3];
};
struct htp_gather_rows_vtcm_layout {
size_t off_tab;
size_t off_inc;
size_t off_cur;
size_t off_region0;
size_t off_out0;
size_t off_region1;
size_t off_out1;
size_t total_per_thread;
};
static inline void htp_gather_rows_vtcm_layout_build(
struct htp_gather_rows_vtcm_layout * L,
uint32_t vg,
uint32_t region_size,
uint32_t nr_max,
uint32_t ne,
uint32_t elem_size) {
const size_t vec_bytes = (size_t) vg * 128;
const size_t region_aligned = hex_round_up(region_size, 128);
const size_t out_aligned = hex_round_up(region_aligned + (size_t) nr_max * ne * elem_size, 128) - region_aligned;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_tab, vec_bytes);
VTCM_LAYOUT_ALLOC(off, off_inc, vec_bytes);
VTCM_LAYOUT_ALLOC(off, off_cur, vec_bytes);
VTCM_LAYOUT_ALLOC(off, off_region0, region_aligned);
VTCM_LAYOUT_ALLOC(off, off_out0, out_aligned);
VTCM_LAYOUT_ALLOC(off, off_region1, region_aligned);
VTCM_LAYOUT_ALLOC(off, off_out1, out_aligned);
L->total_per_thread = off;
}
static inline bool htp_gather_rows_solve_layout(
struct htp_gather_rows_params * kparams,
uint32_t na, uint32_t a_nb1,
@@ -80,8 +113,6 @@ static inline bool htp_gather_rows_solve_layout(
uint32_t v1 = 0;
uint32_t span1 = 0;
uint32_t region_size = 0;
uint32_t out_off = 0;
uint32_t buf_stride = 0;
while (nr_max > 0) {
v1 = hex_round_up((nr_max - 1) * a_nb1 + na * elem_size, 128);
@@ -98,10 +129,10 @@ static inline bool htp_gather_rows_solve_layout(
region_size = v1;
}
out_off = hex_round_up(region_size, 128);
buf_stride = hex_round_up(out_off + nr_max * ne * elem_size, 128);
struct htp_gather_rows_vtcm_layout layout;
htp_gather_rows_vtcm_layout_build(&layout, vg, region_size, nr_max, ne, elem_size);
if ((elem_size != 2 || region_size <= 32768) && fixed + 2 * buf_stride <= slice) {
if ((elem_size != 2 || region_size <= 32768) && layout.total_per_thread <= slice) {
break;
}
@@ -121,8 +152,6 @@ static inline bool htp_gather_rows_solve_layout(
kparams->v1 = v1;
kparams->span1 = span1;
kparams->region_size = region_size;
kparams->out_off = out_off;
kparams->buf_stride = buf_stride;
kparams->slice = slice;
kparams->total_rows = total_rows;
kparams->rows_per_thread = rows_per_thread;
+3 -3
View File
@@ -404,7 +404,7 @@ int op_get_rows(struct htp_ops_context * octx) {
if (octx->ctx->mdev.count > 1) {
uint32_t tasks_per_chunk = 1;
htp_tensor_mdev_rows_per_chunk(dst, dst_row_size / dst->ne[0], dst_row_size, &tasks_per_chunk);
htp_tensor_mdev_rows_per_chunk(dst, (uint32_t) dst->nb[0], dst_row_size, &tasks_per_chunk);
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(total_tasks, tasks_per_chunk, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
task_start = range.start;
tasks = range.count;
@@ -414,7 +414,7 @@ int op_get_rows(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (!htp_ops_context_set_n_threads(octx, (uint32_t) kparams->n_threads)) {
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
@@ -428,7 +428,7 @@ int op_get_rows(struct htp_ops_context * octx) {
grctx.compute_tiled = NULL;
grctx.task_start = task_start;
grctx.tasks = tasks;
grctx.tasks_per_thread = octx->ctx->mdev.count == 1 ? kparams->tasks_per_thread : fastdiv(tasks + n_threads - 1, &octx->n_threads_div);
grctx.tasks_per_thread = fastdiv(tasks + n_threads - 1, &octx->n_threads_div);
grctx.tile_size = 0;
grctx.tile_stride = 0;
grctx.src0_row_size = src0_row_size;
+4 -5
View File
@@ -15,11 +15,10 @@ enum htp_get_rows_kernel_type {
};
struct htp_get_rows_kernel_params {
int32_t n_threads;
int32_t kernel_type;
int32_t total_tasks;
int32_t tasks_per_thread;
int32_t vtcm_size;
uint8_t kernel_type;
uint32_t n_threads;
uint32_t total_tasks;
uint32_t vtcm_size;
// Fastdiv helpers
struct fastdiv_values div_ne10;
@@ -17,11 +17,12 @@
#include "hex-common.h"
#include "htp-tensor.h"
#include "htp-vtcm.h"
#include "glu-ops.h"
#define htp_act_preamble \
const struct htp_tensor * src0 = actx->octx->src[0]; \
const struct htp_tensor * src1 = actx->octx->src[1]; \
const struct htp_tensor * dst = actx->octx->dst; \
#define htp_glu_preamble \
const struct htp_tensor * src0 = gctx->octx->src[0]; \
const struct htp_tensor * src1 = gctx->octx->src[1]; \
const struct htp_tensor * dst = gctx->octx->dst; \
\
const uint32_t ne00 = src0->ne[0]; \
const uint32_t ne01 = src0->ne[1]; \
@@ -53,21 +54,21 @@
const uint32_t nb2 = dst->nb[2]; \
const uint32_t nb3 = dst->nb[3];
struct htp_act_context;
struct htp_glu_context;
typedef void (*glu_compute_f32_fn_t)(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx);
const struct htp_glu_context * gctx);
typedef void (*glu_compute_f16_fn_t)(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx);
const struct htp_glu_context * gctx);
struct htp_act_context {
struct htp_glu_context {
struct htp_ops_context * octx;
void * compute;
@@ -108,53 +109,18 @@ struct htp_act_context {
size_t vtcm_dst_size_per_thread;
};
struct htp_act_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_src1;
size_t off_dst;
size_t src0_bytes_per_thread;
size_t src1_bytes_per_thread;
size_t dst_bytes_per_thread;
uint32_t vtcm_row_per_thread;
};
static inline void htp_act_vtcm_layout_build(struct htp_act_vtcm_layout * L,
size_t src0_row_size_aligned,
size_t src1_row_size_aligned,
size_t dst_row_size_aligned,
uint32_t n_threads,
size_t vtcm_size) {
const size_t spad_size_per_row = src0_row_size_aligned + src1_row_size_aligned + dst_row_size_aligned;
const uint32_t vtcm_row_per_thread = (uint32_t) (vtcm_size / (n_threads * spad_size_per_row));
L->vtcm_row_per_thread = vtcm_row_per_thread;
L->src0_bytes_per_thread = src0_row_size_aligned * vtcm_row_per_thread;
L->src1_bytes_per_thread = src1_row_size_aligned * vtcm_row_per_thread;
L->dst_bytes_per_thread = dst_row_size_aligned * vtcm_row_per_thread;
L->off_src0 = 0;
L->off_src1 = L->off_src0 + L->src0_bytes_per_thread * n_threads;
L->off_dst = L->off_src1 + L->src1_bytes_per_thread * n_threads;
L->total_bytes = L->off_dst + L->dst_bytes_per_thread * n_threads;
}
#define htp_glu_op_preamble \
const size_t src0_row_size_aligned = actx->src0_row_size_aligned; \
const size_t src1_row_size_aligned = actx->src1_row_size_aligned; \
const size_t dst_row_size_aligned = actx->dst_row_size_aligned; \
const int nc = actx->nc;
const size_t src0_row_size_aligned = gctx->src0_row_size_aligned; \
const size_t src1_row_size_aligned = gctx->src1_row_size_aligned; \
const size_t dst_row_size_aligned = gctx->dst_row_size_aligned; \
const int nc = gctx->nc;
// swiglu(x) = x1 * sigmoid(x0)
static void swiglu_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
@@ -172,10 +138,10 @@ static void swiglu_oai_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
const float alpha = ((const float *) (actx->octx->op_params))[2];
const float limit = ((const float *) (actx->octx->op_params))[3];
const float alpha = ((const float *) (gctx->octx->op_params))[2];
const float limit = ((const float *) (gctx->octx->op_params))[3];
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
@@ -201,9 +167,9 @@ static void swiglu_clamp_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
const float limit = ((const float *) (actx->octx->op_params))[3];
const float limit = ((const float *) (gctx->octx->op_params))[3];
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
@@ -455,7 +421,7 @@ static void geglu_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
@@ -472,7 +438,7 @@ static void geglu_quick_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
@@ -489,7 +455,7 @@ static void geglu_erf_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
@@ -501,12 +467,124 @@ static void geglu_erf_f32(const float * restrict src0,
}
}
static inline void hvx_reglu_f32_aa(uint8_t * restrict dst, const uint8_t * restrict src0, const uint8_t * restrict src1, uint32_t n) {
assert((unsigned long) dst % 128 == 0);
assert((unsigned long) src0 % 128 == 0);
assert((unsigned long) src1 % 128 == 0);
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
const HVX_Vector * restrict vsrc0 = (const HVX_Vector *) src0;
const HVX_Vector * restrict vsrc1 = (const HVX_Vector *) src1;
const uint32_t epv = 128 / sizeof(float);
const uint32_t nvec = n / epv;
const uint32_t nloe = n % epv;
const HVX_Vector v_zero = Q6_V_vzero();
uint32_t i = 0;
_Pragma("unroll(4)")
for (; i < nvec; i++) {
HVX_Vector x = Q6_Vsf_vmax_VsfVsf(vsrc0[i], v_zero);
vdst[i] = hvx_vec_mul_f32_f32(x, vsrc1[i]);
}
if (nloe) {
HVX_Vector x = Q6_Vsf_vmax_VsfVsf(vsrc0[i], v_zero);
HVX_Vector res = hvx_vec_mul_f32_f32(x, vsrc1[i]);
hvx_vec_store_a((void *) &vdst[i], nloe * sizeof(float), res);
}
}
// reglu(x, g) = relu(x) * g
static void reglu_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
hvx_reglu_f32_aa(dst_ptr, src0_ptr, src1_ptr, nc);
}
}
static __attribute__((noinline)) void hvx_sigglu_f32_vec(HVX_Vector * restrict vdst,
const HVX_Vector * restrict vsrc0,
const HVX_Vector * restrict vsrc1,
uint32_t nvec) {
const HVX_Vector v_one = hvx_vec_splat_f32(1.0f);
const HVX_Vector v_max_exp = hvx_vec_splat_f32(87.0f);
const HVX_Vector v_min_exp = hvx_vec_splat_f32(-87.0f);
for (uint32_t i = 0; i < nvec; i++) {
HVX_Vector sig = hvx_vec_fast_sigmoid_f32_guard(vsrc0[i], v_one, v_max_exp, v_min_exp);
vdst[i] = hvx_vec_mul_f32_f32(sig, vsrc1[i]);
}
}
static __attribute__((noinline)) void hvx_sigglu_f32_tail(HVX_Vector * restrict vdst,
const HVX_Vector * restrict vsrc0,
const HVX_Vector * restrict vsrc1,
uint32_t nloe) {
const HVX_Vector v_one = hvx_vec_splat_f32(1.0f);
const HVX_Vector v_max_exp = hvx_vec_splat_f32(87.0f);
const HVX_Vector v_min_exp = hvx_vec_splat_f32(-87.0f);
HVX_Vector sig = hvx_vec_fast_sigmoid_f32_guard(vsrc0[0], v_one, v_max_exp, v_min_exp);
HVX_Vector res = hvx_vec_mul_f32_f32(sig, vsrc1[0]);
hvx_vec_store_a((void *) vdst, nloe * sizeof(float), res);
}
static inline void hvx_sigglu_f32_aa(uint8_t * restrict dst, const uint8_t * restrict src0, const uint8_t * restrict src1, uint32_t n) {
assert((unsigned long) dst % 128 == 0);
assert((unsigned long) src0 % 128 == 0);
assert((unsigned long) src1 % 128 == 0);
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
const HVX_Vector * restrict vsrc0 = (const HVX_Vector *) src0;
const HVX_Vector * restrict vsrc1 = (const HVX_Vector *) src1;
const uint32_t epv = 128 / sizeof(float);
const uint32_t nvec = n / epv;
const uint32_t nloe = n % epv;
if (nvec) {
hvx_sigglu_f32_vec(vdst, vsrc0, vsrc1, nvec);
}
if (nloe) {
hvx_sigglu_f32_tail(vdst + nvec, vsrc0 + nvec, vsrc1 + nvec, nloe);
}
}
// sigglu(x, g) = sigmoid(x) * g
static void sigglu_f32(const float * restrict src0,
const float * restrict src1,
float * restrict dst,
const uint32_t num_rows,
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
hvx_sigglu_f32_aa(dst_ptr, src0_ptr, src1_ptr, nc);
}
}
// swiglu(x) = x1 * sigmoid(x0)
static void swiglu_f16(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
@@ -524,10 +602,10 @@ static void swiglu_oai_f16(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
const _Float16 alpha = (_Float16) ((const float *) (actx->octx->op_params))[2];
const _Float16 limit = (_Float16) ((const float *) (actx->octx->op_params))[3];
const _Float16 alpha = (_Float16) ((const float *) (gctx->octx->op_params))[2];
const _Float16 limit = (_Float16) ((const float *) (gctx->octx->op_params))[3];
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
@@ -553,9 +631,9 @@ static void swiglu_clamp_f16(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
const _Float16 limit = (_Float16) ((const float *) (actx->octx->op_params))[3];
const _Float16 limit = (_Float16) ((const float *) (gctx->octx->op_params))[3];
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
@@ -574,7 +652,7 @@ static void geglu_f16(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_act_context * actx) {
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
@@ -586,56 +664,155 @@ static void geglu_f16(const _Float16 * restrict src0,
}
}
static inline void hvx_reglu_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src0, const uint8_t * restrict src1, uint32_t n) {
assert((unsigned long) dst % 128 == 0);
assert((unsigned long) src0 % 128 == 0);
assert((unsigned long) src1 % 128 == 0);
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
const HVX_Vector * restrict vsrc0 = (const HVX_Vector *) src0;
const HVX_Vector * restrict vsrc1 = (const HVX_Vector *) src1;
const uint32_t epv = 128 / sizeof(_Float16);
const uint32_t nvec = n / epv;
const uint32_t nloe = n % epv;
const HVX_Vector v_zero = Q6_V_vzero();
uint32_t i = 0;
_Pragma("unroll(4)")
for (; i < nvec; i++) {
HVX_Vector x = Q6_Vhf_vmax_VhfVhf(vsrc0[i], v_zero);
vdst[i] = hvx_vec_mul_f16_f16(x, vsrc1[i]);
}
if (nloe) {
HVX_Vector x = Q6_Vhf_vmax_VhfVhf(vsrc0[i], v_zero);
HVX_Vector res = hvx_vec_mul_f16_f16(x, vsrc1[i]);
hvx_vec_store_a((void *) &vdst[i], nloe * sizeof(_Float16), res);
}
}
// reglu(x, g) = relu(x) * g
static void reglu_f16(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
hvx_reglu_f16_aa(dst_ptr, src0_ptr, src1_ptr, nc);
}
}
static __attribute__((noinline)) void hvx_sigglu_f16_vec(HVX_Vector * restrict vdst,
const HVX_Vector * restrict vsrc0,
const HVX_Vector * restrict vsrc1,
uint32_t nvec) {
for (uint32_t i = 0; i < nvec; i++) {
HVX_Vector sig = hvx_vec_fast_sigmoid_f16(vsrc0[i]);
vdst[i] = hvx_vec_mul_f16_f16(sig, vsrc1[i]);
}
}
static __attribute__((noinline)) void hvx_sigglu_f16_tail(HVX_Vector * restrict vdst,
const HVX_Vector * restrict vsrc0,
const HVX_Vector * restrict vsrc1,
uint32_t nloe) {
HVX_Vector sig = hvx_vec_fast_sigmoid_f16(vsrc0[0]);
HVX_Vector res = hvx_vec_mul_f16_f16(sig, vsrc1[0]);
hvx_vec_store_a((void *) vdst, nloe * sizeof(_Float16), res);
}
static inline void hvx_sigglu_f16_aa(uint8_t * restrict dst, const uint8_t * restrict src0, const uint8_t * restrict src1, uint32_t n) {
assert((unsigned long) dst % 128 == 0);
assert((unsigned long) src0 % 128 == 0);
assert((unsigned long) src1 % 128 == 0);
HVX_Vector * restrict vdst = (HVX_Vector *) dst;
const HVX_Vector * restrict vsrc0 = (const HVX_Vector *) src0;
const HVX_Vector * restrict vsrc1 = (const HVX_Vector *) src1;
const uint32_t epv = 128 / sizeof(_Float16);
const uint32_t nvec = n / epv;
const uint32_t nloe = n % epv;
if (nvec) {
hvx_sigglu_f16_vec(vdst, vsrc0, vsrc1, nvec);
}
if (nloe) {
hvx_sigglu_f16_tail(vdst + nvec, vsrc0 + nvec, vsrc1 + nvec, nloe);
}
}
// sigglu(x, g) = sigmoid(x) * g
static void sigglu_f16(const _Float16 * restrict src0,
const _Float16 * restrict src1,
_Float16 * restrict dst,
const uint32_t num_rows,
const struct htp_glu_context * gctx) {
htp_glu_op_preamble;
for (uint32_t ib = 0; ib < num_rows; ib++) {
const uint8_t * restrict src0_ptr = (const uint8_t *) src0 + (ib * src0_row_size_aligned);
const uint8_t * restrict src1_ptr = (const uint8_t *) src1 + (ib * src1_row_size_aligned);
uint8_t * restrict dst_ptr = (uint8_t *) dst + (ib * dst_row_size_aligned);
hvx_sigglu_f16_aa(dst_ptr, src0_ptr, src1_ptr, nc);
}
}
#define DEFINE_GLU_PER_THREAD(TYPE, SUFFIX) \
static void glu_##SUFFIX##_per_thread(unsigned int nth, unsigned int ith, void * data) { \
struct htp_act_context * actx = (struct htp_act_context *) data; \
htp_act_preamble; \
struct htp_glu_context * gctx = (struct htp_glu_context *) data; \
htp_glu_preamble; \
\
struct htp_thread_trace * tr = actx->octx->ctx ? &actx->octx->ctx->trace[ith] : NULL; \
struct htp_thread_trace * tr = gctx->octx->ctx ? &gctx->octx->ctx->trace[ith] : NULL; \
\
size_t src0_row_size = actx->src0_row_size; \
size_t src1_row_size = actx->src1_row_size; \
size_t dst_row_size = actx->dst_row_size; \
size_t src0_row_size = gctx->src0_row_size; \
size_t src1_row_size = gctx->src1_row_size; \
size_t dst_row_size = gctx->dst_row_size; \
\
size_t src0_row_stride = actx->src0_row_stride; \
size_t src1_row_stride = actx->src1_row_stride; \
size_t src0_row_stride = gctx->src0_row_stride; \
size_t src1_row_stride = gctx->src1_row_stride; \
\
const uint32_t src0_nrows = actx->src0_nrows; \
const uint32_t src0_nrows_per_thread = actx->src0_nrows_per_thread; \
const uint32_t src0_nrows = gctx->src0_nrows; \
const uint32_t src0_nrows_per_thread = gctx->src0_nrows_per_thread; \
\
const uint32_t src0_start_row = actx->row_start + src0_nrows_per_thread * ith; \
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, actx->row_start + src0_nrows); \
const uint32_t src0_start_row = gctx->row_start + src0_nrows_per_thread * ith; \
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, gctx->row_start + src0_nrows); \
\
/* no work for this thread */ \
if (src0_start_row >= src0_end_row) { \
return; \
} \
\
const dma_addr_t data_src0 = actx->data_src0; \
const dma_addr_t data_src1 = actx->data_src1; \
const dma_addr_t data_dst = actx->data_dst; \
const dma_addr_t data_src0 = gctx->data_src0; \
const dma_addr_t data_src1 = gctx->data_src1; \
const dma_addr_t data_dst = gctx->data_dst; \
\
const size_t src0_row_size_aligned = actx->src0_row_size_aligned; \
const size_t src1_row_size_aligned = actx->src1_row_size_aligned; \
const size_t dst_row_size_aligned = actx->dst_row_size_aligned; \
const size_t src0_row_size_aligned = gctx->src0_row_size_aligned; \
const size_t src1_row_size_aligned = gctx->src1_row_size_aligned; \
const size_t dst_row_size_aligned = gctx->dst_row_size_aligned; \
\
uint8_t * restrict src0_spad_data = actx->vtcm_src0 + (ith * actx->vtcm_src0_size_per_thread); \
uint8_t * restrict src1_spad_data = actx->vtcm_src1 + (ith * actx->vtcm_src1_size_per_thread); \
uint8_t * restrict dst_spad_data = actx->vtcm_dst + (ith * actx->vtcm_dst_size_per_thread); \
uint8_t * restrict src0_spad_data = gctx->vtcm_src0 + (ith * gctx->vtcm_src0_size_per_thread); \
uint8_t * restrict src1_spad_data = gctx->vtcm_src1 + (ith * gctx->vtcm_src1_size_per_thread); \
uint8_t * restrict dst_spad_data = gctx->vtcm_dst + (ith * gctx->vtcm_dst_size_per_thread); \
\
size_t src0_spad_half_size = actx->src0_spad_half_size; \
size_t src1_spad_half_size = actx->src1_spad_half_size; \
size_t dst_spad_half_size = actx->dst_spad_half_size; \
size_t src0_spad_half_size = gctx->src0_spad_half_size; \
size_t src1_spad_half_size = gctx->src1_spad_half_size; \
size_t dst_spad_half_size = gctx->dst_spad_half_size; \
\
const int BLOCK = actx->block; \
if (BLOCK == 0) { \
FARF(ERROR, "%s : VTCM reservation %zu is too small, needed %zu\n", \
actx->op_str, actx->vtcm_src0_size_per_thread, src0_row_size_aligned); \
return; \
} \
const int BLOCK = gctx->block; \
\
dma_queue * dma_q = actx->octx->ctx->dma[ith]; \
glu_compute_##SUFFIX##_fn_t compute = (glu_compute_##SUFFIX##_fn_t) actx->compute; \
dma_queue * dma_q = gctx->octx->ctx->dma[ith]; \
glu_compute_##SUFFIX##_fn_t compute = (glu_compute_##SUFFIX##_fn_t) gctx->compute; \
\
for (uint32_t ir = src0_start_row, spad_idx = 0; ir < src0_end_row && spad_idx < 2; ir += BLOCK, spad_idx++) { \
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir); \
@@ -662,7 +839,7 @@ static void geglu_f16(const _Float16 * restrict src0,
TYPE * src1_spad = (TYPE *) dma_queue_pop(dma_q).dst; \
\
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, ir); \
compute(src0_spad, src1_spad, dst_spad, block_size, actx); \
compute(src0_spad, src1_spad, dst_spad, block_size, gctx); \
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, ir); \
\
dma_queue_push(dma_q, dma_make_data(data_dst + (ir * dst_row_size), dst_spad), \
@@ -685,16 +862,11 @@ static void geglu_f16(const _Float16 * restrict src0,
DEFINE_GLU_PER_THREAD(float, f32)
DEFINE_GLU_PER_THREAD(_Float16, f16)
static int execute_op_activations_f32(struct htp_ops_context * octx) {
static int execute_op_glu_f32(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * src1 = octx->src[1];
const struct htp_tensor * dst = octx->dst;
if ((dst->ne[0] * SIZEOF_FP32) != dst->nb[1]) {
FARF(ERROR, "Non-contiguous dst is not supported at this time \n");
return HTP_STATUS_NO_SUPPORT;
}
glu_compute_f32_fn_t compute_fn = NULL;
const char * op_type = NULL;
@@ -729,11 +901,27 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
op_type = "geglu-erf-f32";
break;
case HTP_OP_GLU_REGLU:
compute_fn = reglu_f32;
op_type = "reglu-f32";
break;
case HTP_OP_GLU_SIGMOID:
compute_fn = sigglu_f32;
op_type = "sigglu-f32";
break;
default:
FARF(ERROR, "Unsupported activations Op %u\n", octx->op);
FARF(ERROR, "Unsupported GLU Op %u\n", octx->op);
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_glu_kernel_params * kparams = (const struct htp_glu_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t src0_nrows = src0->ne[1] * src0->ne[2] * src0->ne[3];
const size_t dst_row_size = dst->ne[0] * SIZEOF_FP32;
@@ -762,17 +950,16 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
const size_t src0_row_stride = src0->nb[1];
const size_t src1_row_stride = src1 ? src1->nb[1] : src0->nb[1];
const size_t src0_row_size_aligned = hex_round_up(src0_row_size, VLEN);
const size_t src1_row_size_aligned = hex_round_up(src1_row_size, VLEN);
const size_t dst_row_size_aligned = hex_round_up(dst_row_size, VLEN);
struct htp_glu_vtcm_layout L;
htp_glu_vtcm_layout_build(&L, dst_row_size, n_threads, kparams->vtcm_row_per_thread);
struct htp_act_vtcm_layout L;
htp_act_vtcm_layout_build(&L, src0_row_size_aligned, src1_row_size_aligned, dst_row_size_aligned, n_threads,
octx->ctx->vtcm_size);
const size_t src0_row_size_aligned = L.row_size_aligned;
const size_t src1_row_size_aligned = L.row_size_aligned;
const size_t dst_row_size_aligned = L.row_size_aligned;
// Make sure the reserved vtcm size is sufficient
if (L.vtcm_row_per_thread == 0) {
FARF(ERROR, "act-%s : current VTCM reservation %zu is too small for even 1 row per thread, needed at least %zu\n", op_type, octx->ctx->vtcm_size,
if (kparams->vtcm_row_per_thread == 0 || octx->ctx->vtcm_size < kparams->vtcm_size) {
FARF(ERROR, "glu-%s : current VTCM reservation %zu is too small for even 1 row per thread, needed at least %zu\n", op_type, octx->ctx->vtcm_size,
(src0_row_size_aligned + src1_row_size_aligned + dst_row_size_aligned) * n_threads);
return HTP_STATUS_VTCM_TOO_SMALL;
}
@@ -789,58 +976,53 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
}
// Prepare context
struct htp_act_context actx;
actx.octx = octx;
actx.compute = (void *) compute_fn;
actx.op_str = op_type;
struct htp_glu_context gctx;
gctx.octx = octx;
gctx.compute = (void *) compute_fn;
gctx.op_str = op_type;
actx.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
gctx.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
actx.src0_row_size = src0_row_size;
actx.src1_row_size = src1_row_size;
actx.dst_row_size = dst_row_size;
gctx.src0_row_size = src0_row_size;
gctx.src1_row_size = src1_row_size;
gctx.dst_row_size = dst_row_size;
actx.src0_row_size_aligned = src0_row_size_aligned;
actx.src1_row_size_aligned = src1_row_size_aligned;
actx.dst_row_size_aligned = dst_row_size_aligned;
gctx.src0_row_size_aligned = src0_row_size_aligned;
gctx.src1_row_size_aligned = src1_row_size_aligned;
gctx.dst_row_size_aligned = dst_row_size_aligned;
actx.src0_row_stride = src0_row_stride;
actx.src1_row_stride = src1_row_stride;
gctx.src0_row_stride = src0_row_stride;
gctx.src1_row_stride = src1_row_stride;
uint8_t * const base = (uint8_t *) octx->ctx->vtcm_base;
actx.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0);
actx.vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src1);
actx.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst);
gctx.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0);
gctx.vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src1);
gctx.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst);
actx.vtcm_src0_size_per_thread = L.src0_bytes_per_thread;
actx.vtcm_src1_size_per_thread = L.src1_bytes_per_thread;
actx.vtcm_dst_size_per_thread = L.dst_bytes_per_thread;
gctx.vtcm_src0_size_per_thread = (uint32_t) L.src0_bytes_per_thread;
gctx.vtcm_src1_size_per_thread = (uint32_t) L.src1_bytes_per_thread;
gctx.vtcm_dst_size_per_thread = (uint32_t) L.dst_bytes_per_thread;
actx.src0_spad_half_size = L.src0_bytes_per_thread / 2;
actx.src1_spad_half_size = L.src1_bytes_per_thread / 2;
actx.dst_spad_half_size = L.dst_bytes_per_thread / 2;
gctx.src0_spad_half_size = gctx.vtcm_src0_size_per_thread >> 1;
gctx.src1_spad_half_size = gctx.vtcm_src1_size_per_thread >> 1;
gctx.dst_spad_half_size = gctx.vtcm_dst_size_per_thread >> 1;
actx.block = actx.src0_spad_half_size / actx.src0_row_size_aligned;
actx.src0_nrows = nrows;
actx.row_start = row_start;
gctx.block = L.block;
gctx.src0_nrows = nrows;
gctx.row_start = row_start;
actx.nc = dst->ne[0];
gctx.nc = dst->ne[0];
// Addresses and GLU logic
dma_addr_t data_src0 = src0->data;
dma_addr_t data_src1 = src1 ? src1->data : 0;
if (!src1 && (octx->op == HTP_OP_GLU_SWIGLU ||
octx->op == HTP_OP_GLU_SWIGLU_OAI ||
octx->op == HTP_OP_GLU_SWIGLU_CLAMP ||
octx->op == HTP_OP_GLU_GEGLU ||
octx->op == HTP_OP_GLU_GEGLU_QUICK ||
octx->op == HTP_OP_GLU_GEGLU_ERF)) {
if (!src1) {
const int32_t swapped = octx->op_params[1];
data_src1 = data_src0;
actx.src1_row_size = actx.src0_row_size;
gctx.src1_row_size = gctx.src0_row_size;
size_t nc_in_bytes = actx.nc * SIZEOF_FP32;
size_t nc_in_bytes = gctx.nc * SIZEOF_FP32;
if (swapped) {
data_src0 += nc_in_bytes;
} else {
@@ -848,24 +1030,19 @@ static int execute_op_activations_f32(struct htp_ops_context * octx) {
}
}
actx.data_src0 = data_src0;
actx.data_src1 = data_src1;
actx.data_dst = dst->data;
gctx.data_src0 = data_src0;
gctx.data_src1 = data_src1;
gctx.data_dst = dst->data;
work_queue_run(octx->ctx->work_queue, (worker_callback_t)glu_f32_per_thread, &actx, n_threads);
work_queue_run(octx->ctx->work_queue, (worker_callback_t)glu_f32_per_thread, &gctx, n_threads);
return HTP_STATUS_OK;
}
static int execute_op_activations_f16(struct htp_ops_context * octx) {
static int execute_op_glu_f16(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * src1 = octx->src[1];
const struct htp_tensor * dst = octx->dst;
if ((dst->ne[0] * SIZEOF_FP16) != dst->nb[1]) {
FARF(ERROR, "Non-contiguous dst is not supported at this time \n");
return HTP_STATUS_NO_SUPPORT;
}
glu_compute_f16_fn_t compute_fn = NULL;
const char * op_type = NULL;
@@ -890,11 +1067,27 @@ static int execute_op_activations_f16(struct htp_ops_context * octx) {
op_type = "geglu-f16";
break;
case HTP_OP_GLU_REGLU:
compute_fn = reglu_f16;
op_type = "reglu-f16";
break;
case HTP_OP_GLU_SIGMOID:
compute_fn = sigglu_f16;
op_type = "sigglu-f16";
break;
default:
FARF(ERROR, "Unsupported activations Op %u\n", octx->op);
FARF(ERROR, "Unsupported GLU Op %u\n", octx->op);
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_glu_kernel_params * kparams = (const struct htp_glu_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t src0_nrows = src0->ne[1] * src0->ne[2] * src0->ne[3];
const size_t dst_row_size = dst->ne[0] * SIZEOF_FP16;
@@ -923,17 +1116,16 @@ static int execute_op_activations_f16(struct htp_ops_context * octx) {
const size_t src0_row_stride = src0->nb[1];
const size_t src1_row_stride = src1 ? src1->nb[1] : src0->nb[1];
const size_t src0_row_size_aligned = hex_round_up(src0_row_size, VLEN);
const size_t src1_row_size_aligned = hex_round_up(src1_row_size, VLEN);
const size_t dst_row_size_aligned = hex_round_up(dst_row_size, VLEN);
struct htp_glu_vtcm_layout L;
htp_glu_vtcm_layout_build(&L, dst_row_size, n_threads, kparams->vtcm_row_per_thread);
struct htp_act_vtcm_layout L;
htp_act_vtcm_layout_build(&L, src0_row_size_aligned, src1_row_size_aligned, dst_row_size_aligned, n_threads,
octx->ctx->vtcm_size);
const size_t src0_row_size_aligned = L.row_size_aligned;
const size_t src1_row_size_aligned = L.row_size_aligned;
const size_t dst_row_size_aligned = L.row_size_aligned;
// Make sure the reserved vtcm size is sufficient
if (L.vtcm_row_per_thread == 0) {
FARF(ERROR, "act-%s : current VTCM reservation %zu is too small for even 1 row per thread, needed at least %zu\n", op_type, octx->ctx->vtcm_size,
if (kparams->vtcm_row_per_thread == 0 || octx->ctx->vtcm_size < kparams->vtcm_size) {
FARF(ERROR, "glu-%s : current VTCM reservation %zu is too small for even 1 row per thread, needed at least %zu\n", op_type, octx->ctx->vtcm_size,
(src0_row_size_aligned + src1_row_size_aligned + dst_row_size_aligned) * n_threads);
return HTP_STATUS_VTCM_TOO_SMALL;
}
@@ -950,56 +1142,53 @@ static int execute_op_activations_f16(struct htp_ops_context * octx) {
}
// Prepare context
struct htp_act_context actx;
actx.octx = octx;
actx.compute = (void *) compute_fn;
actx.op_str = op_type;
struct htp_glu_context gctx;
gctx.octx = octx;
gctx.compute = (void *) compute_fn;
gctx.op_str = op_type;
actx.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
gctx.src0_nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
actx.src0_row_size = src0_row_size;
actx.src1_row_size = src1_row_size;
actx.dst_row_size = dst_row_size;
gctx.src0_row_size = src0_row_size;
gctx.src1_row_size = src1_row_size;
gctx.dst_row_size = dst_row_size;
actx.src0_row_size_aligned = src0_row_size_aligned;
actx.src1_row_size_aligned = src1_row_size_aligned;
actx.dst_row_size_aligned = dst_row_size_aligned;
gctx.src0_row_size_aligned = src0_row_size_aligned;
gctx.src1_row_size_aligned = src1_row_size_aligned;
gctx.dst_row_size_aligned = dst_row_size_aligned;
actx.src0_row_stride = src0_row_stride;
actx.src1_row_stride = src1_row_stride;
gctx.src0_row_stride = src0_row_stride;
gctx.src1_row_stride = src1_row_stride;
uint8_t * const base = (uint8_t *) octx->ctx->vtcm_base;
actx.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0);
actx.vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src1);
actx.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst);
gctx.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0);
gctx.vtcm_src1 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src1);
gctx.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst);
actx.vtcm_src0_size_per_thread = L.src0_bytes_per_thread;
actx.vtcm_src1_size_per_thread = L.src1_bytes_per_thread;
actx.vtcm_dst_size_per_thread = L.dst_bytes_per_thread;
gctx.vtcm_src0_size_per_thread = (uint32_t) L.src0_bytes_per_thread;
gctx.vtcm_src1_size_per_thread = (uint32_t) L.src1_bytes_per_thread;
gctx.vtcm_dst_size_per_thread = (uint32_t) L.dst_bytes_per_thread;
actx.src0_spad_half_size = L.src0_bytes_per_thread / 2;
actx.src1_spad_half_size = L.src1_bytes_per_thread / 2;
actx.dst_spad_half_size = L.dst_bytes_per_thread / 2;
gctx.src0_spad_half_size = gctx.vtcm_src0_size_per_thread >> 1;
gctx.src1_spad_half_size = gctx.vtcm_src1_size_per_thread >> 1;
gctx.dst_spad_half_size = gctx.vtcm_dst_size_per_thread >> 1;
actx.block = actx.src0_spad_half_size / actx.src0_row_size_aligned;
actx.src0_nrows = nrows;
actx.row_start = row_start;
gctx.block = L.block;
gctx.src0_nrows = nrows;
gctx.row_start = row_start;
actx.nc = dst->ne[0];
gctx.nc = dst->ne[0];
// Addresses and GLU logic
dma_addr_t data_src0 = src0->data;
dma_addr_t data_src1 = src1 ? src1->data : 0;
if (!src1 && (octx->op == HTP_OP_GLU_SWIGLU ||
octx->op == HTP_OP_GLU_SWIGLU_OAI ||
octx->op == HTP_OP_GLU_SWIGLU_CLAMP ||
octx->op == HTP_OP_GLU_GEGLU)) {
if (!src1) {
const int32_t swapped = octx->op_params[1];
data_src1 = data_src0;
actx.src1_row_size = actx.src0_row_size;
gctx.src1_row_size = gctx.src0_row_size;
size_t nc_in_bytes = actx.nc * SIZEOF_FP16;
size_t nc_in_bytes = gctx.nc * SIZEOF_FP16;
if (swapped) {
data_src0 += nc_in_bytes;
} else {
@@ -1007,22 +1196,22 @@ static int execute_op_activations_f16(struct htp_ops_context * octx) {
}
}
actx.data_src0 = data_src0;
actx.data_src1 = data_src1;
actx.data_dst = dst->data;
gctx.data_src0 = data_src0;
gctx.data_src1 = data_src1;
gctx.data_dst = dst->data;
work_queue_run(octx->ctx->work_queue, (worker_callback_t)glu_f16_per_thread, &actx, n_threads);
work_queue_run(octx->ctx->work_queue, (worker_callback_t)glu_f16_per_thread, &gctx, n_threads);
return HTP_STATUS_OK;
}
int op_activations(struct htp_ops_context * octx) {
int op_glu(struct htp_ops_context * octx) {
switch (octx->src[0]->type) {
case HTP_TYPE_F32:
return execute_op_activations_f32(octx);
return execute_op_glu_f32(octx);
case HTP_TYPE_F16:
return execute_op_activations_f16(octx);
return execute_op_glu_f16(octx);
default:
return HTP_STATUS_NO_SUPPORT;
+76
View File
@@ -0,0 +1,76 @@
#ifndef HTP_GLU_OPS_H
#define HTP_GLU_OPS_H
#include "hex-common.h"
#include "htp-ops.h"
#include "htp-vtcm.h"
#include <stdint.h>
struct htp_glu_kernel_params {
uint32_t n_threads;
uint32_t vtcm_row_per_thread;
uint32_t vtcm_size;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_glu_kernel_params) <= 128, "htp_glu_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_glu_kernel_params) <= 128, "htp_glu_kernel_params is too large for kernel_params blob");
#endif
static inline bool htp_op_is_glu(uint32_t opcode) {
switch (opcode) {
case HTP_OP_GLU_SWIGLU:
case HTP_OP_GLU_SWIGLU_OAI:
case HTP_OP_GLU_SWIGLU_CLAMP:
case HTP_OP_GLU_GEGLU:
case HTP_OP_GLU_GEGLU_QUICK:
case HTP_OP_GLU_GEGLU_ERF:
case HTP_OP_GLU_REGLU:
case HTP_OP_GLU_SIGMOID:
return true;
default:
return false;
}
}
struct htp_glu_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_src1;
size_t off_dst;
size_t row_size_aligned;
size_t src0_bytes_per_thread;
size_t src1_bytes_per_thread;
size_t dst_bytes_per_thread;
uint32_t vtcm_row_per_thread;
uint32_t block;
};
static inline void htp_glu_vtcm_layout_build(
struct htp_glu_vtcm_layout * L,
size_t dst_row_size,
uint32_t n_threads,
uint32_t vtcm_row_per_thread
) {
const size_t row_size_aligned = hex_round_up(dst_row_size, 128);
L->row_size_aligned = row_size_aligned;
L->vtcm_row_per_thread = vtcm_row_per_thread;
L->block = vtcm_row_per_thread >> 1;
L->src0_bytes_per_thread = row_size_aligned * vtcm_row_per_thread;
L->src1_bytes_per_thread = row_size_aligned * vtcm_row_per_thread;
L->dst_bytes_per_thread = row_size_aligned * vtcm_row_per_thread;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_src1, L->src1_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
#endif // HTP_GLU_OPS_H
+4
View File
@@ -17,6 +17,10 @@
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef HEX_L2_LINE_SIZE
#define HEX_L2_LINE_SIZE 128
#endif
static inline uint32_t hex_ceil_pow2(uint32_t x) {
if (x <= 1) { return 1; }
int p = 2;
+5 -3
View File
@@ -44,12 +44,14 @@ struct htp_thread_trace {
};
static inline void htp_trace_event(struct htp_thread_trace * tr, uint16_t id, uint16_t info, uint32_t type) {
if (tr->count < tr->max_events) {
uint32_t i = tr->count;
if (!tr->max_events) {
return;
}
uint32_t i = tr->count++;
if (i < tr->max_events) {
tr->events[i].id = id;
tr->events[i].info = info | (type == HTP_TRACE_EVT_STOP ? 0x8000 : 0);
tr->events[i].cycles = (uint32_t) hex_get_cycles();
tr->count++;
}
}
+16 -3
View File
@@ -12,8 +12,10 @@
#include <assert.h>
#include <dspqueue.h>
#include <stdatomic.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#ifndef HTP_MAX_NTHREADS
#define HTP_MAX_NTHREADS 10
@@ -66,14 +68,18 @@ struct htp_ops_context {
// TODO convert these to an array
struct htp_spad src0_spad;
struct htp_spad src1_spad;
struct htp_spad src2_spad;
struct htp_spad src3_spad;
struct htp_spad dst_spad;
uint32_t flags;
uint32_t n_threads;
struct fastdiv_values n_threads_div;
int status;
// Must stay last: not cleared by htp_ops_context_reset(), ops init the caches they use
union {
dma_cache_dm dma_cache_dm[HTP_MAX_NTHREADS];
dma_cache_fa dma_cache_fa[HTP_MAX_NTHREADS];
} __attribute__((aligned(128)));
};
// Main context for htp DSP backend
@@ -118,6 +124,13 @@ struct htp_context {
size_t footprint;
};
static inline void htp_ops_context_reset(struct htp_ops_context * octx, struct htp_context * ctx) {
memset(octx, 0, offsetof(struct htp_ops_context, dma_cache_dm));
octx->ctx = ctx;
octx->n_threads = ctx->n_threads;
octx->n_threads_div = ctx->n_threads_div;
}
static inline bool htp_ops_context_set_n_threads(struct htp_ops_context * octx, uint32_t n_threads) {
if (n_threads == 0 || n_threads > octx->ctx->n_threads) {
return false;
@@ -148,7 +161,7 @@ int op_unary(struct htp_ops_context * octx);
int op_sum(struct htp_ops_context * octx);
int op_sum_rows(struct htp_ops_context * octx);
int op_argmax(struct htp_ops_context * octx);
int op_activations(struct htp_ops_context * octx);
int op_glu(struct htp_ops_context * octx);
int op_softmax(struct htp_ops_context * octx);
int op_add_id(struct htp_ops_context * octx);
int op_rope(struct htp_ops_context * octx);
+8 -10
View File
@@ -38,11 +38,6 @@ enum htp_data_type {
HTP_TYPE_INVALID
};
// Constants for internal types
#define QK_Q8_0_TILED 128 // 32x32 Q8_0 tiled layout
// Do not reorder first 4 (used as an index)
enum htp_op_code {
HTP_OP_MUL = 0,
@@ -115,6 +110,8 @@ enum htp_op_code {
HTP_OP_UNARY_GELU_QUICK,
HTP_OP_IM2COL_3D,
HTP_OP_HADAMARD,
HTP_OP_GLU_REGLU,
HTP_OP_GLU_SIGMOID,
HTP_OP_INVALID
};
@@ -125,8 +122,8 @@ enum htp_op_code {
#define HTP_OP_MAX_PARAMS 16 // aka GGML_MAX_OP_PARAMS
#define HTP_OP_MAX_KERN_PARAMS 32
#define HTP_OP_MAX_BUFS 16
#define HTP_OP_MAX_TENSORS 8192 // must stay under 64K (uint16)
#define HTP_OP_MAX_BUFS 64
#define HTP_OP_MAX_TENSORS 65534 // must stay under 64K (uint16)
#define HTP_FENCE_TIMEOUT (1000000000ULL)
#define HTP_FENCE_SLOT_SIZE 128
@@ -136,9 +133,10 @@ enum htp_op_code {
#define HTP_MMAP_MAX_VMEM (2147483648u)
enum htp_tensor_flags {
HTP_TENSOR_WEIGHT = (1U << 0), // Tensor buffer model weight data (not compute)
HTP_TENSOR_TILED = (1U << 1), // Tensor is in tiled format
HTP_TENSOR_FENCE = (1U << 2) // Tensor is synchronization fence (explicitly managed)
HTP_TENSOR_WEIGHT = (1U << 0), // Tensor buffer model weight data (not compute)
HTP_TENSOR_TILED = (1U << 1), // Tensor is in tiled format
HTP_TENSOR_FENCE = (1U << 2), // Tensor is synchronization fence (explicitly managed)
HTP_TENSOR_FUSEABLE = (1U << 3), // Tensor can be fused (host-only)
};
enum htp_buf_flags {
@@ -233,7 +233,7 @@ static inline void quantize_block_f32_q8_0_tiled(float * restrict x, uint8_t * r
static void quantize_row_f32_q8_0_tiled(float * restrict x, uint8_t * restrict y, uint32_t k) {
assert(k % 32 == 0);
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (k + qk - 1) / qk;
for (uint32_t i = 0; i < nb; i++) {
@@ -244,7 +244,7 @@ static void quantize_row_f32_q8_0_tiled(float * restrict x, uint8_t * restrict y
static void quantize_row_f32_q8_1_tiled(float * restrict x, uint8_t * restrict y, uint32_t k) {
assert(k % 32 == 0);
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (k + qk - 1) / qk;
for (uint32_t i = 0; i < nb; i++) {
@@ -255,7 +255,7 @@ static void quantize_row_f32_q8_1_tiled(float * restrict x, uint8_t * restrict y
static void quantize_row_f32_q8_1_s16_tiled(float * restrict x, uint8_t * restrict y, uint32_t k) {
assert(k % 32 == 0);
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (k + qk - 1) / qk;
for (uint32_t i = 0; i < nb; i++) {
@@ -310,7 +310,7 @@ static inline void quantize_block_f16_f16_tiled(const __fp16 * restrict x, uint8
static void quantize_row_f32_f16_tiled(const float * restrict x, uint8_t * restrict y, uint32_t k) {
assert(k % 32 == 0);
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (k + qk - 1) / qk;
for (uint32_t i = 0; i < nb; i++) {
@@ -321,7 +321,7 @@ static void quantize_row_f32_f16_tiled(const float * restrict x, uint8_t * restr
static void quantize_row_f16_f16_tiled(const __fp16 * restrict x, uint8_t * restrict y, uint32_t k) {
assert(k % 32 == 0);
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (k + qk - 1) / qk;
for (uint32_t i = 0; i < nb; i++) {
@@ -1963,7 +1963,7 @@ static inline void quantize_f32_q8_0_tiled_block_kernel(
uint32_t c
) {
(void) tmp_data;
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne0 + qk - 1) / qk;
for (uint32_t ib = ib_first; ib < ib_last; ++ib) {
@@ -1993,7 +1993,7 @@ static inline void quantize_f32_q8_1_tiled_block_kernel(
uint32_t c
) {
(void) tmp_data;
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne0 + qk - 1) / qk;
for (uint32_t ib = ib_first; ib < ib_last; ++ib) {
@@ -2023,7 +2023,7 @@ static inline void quantize_f32_q8_1_s16_tiled_block_kernel(
uint32_t c
) {
(void) tmp_data;
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne0 + qk - 1) / qk;
for (uint32_t ib = ib_first; ib < ib_last; ++ib) {
@@ -2053,7 +2053,7 @@ static inline void quantize_f32_f16_tiled_block_kernel(
uint32_t c
) {
(void) tmp_data;
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne0 + qk - 1) / qk;
for (uint32_t ib = ib_first; ib < ib_last; ++ib) {
@@ -2083,7 +2083,7 @@ static inline void quantize_f16_f16_tiled_block_kernel(
uint32_t c
) {
(void) tmp_data;
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne0 + qk - 1) / qk;
for (uint32_t ib = ib_first; ib < ib_last; ++ib) {
+10 -2
View File
@@ -11,7 +11,8 @@
static inline void hvx_fast_rms_norm_f32(const uint8_t * restrict src,
uint8_t * restrict dst,
const int num_elems,
float epsilon) {
float epsilon,
float scale) {
const HVX_Vector * restrict v_src = (HVX_Vector *) src;
HVX_Vector * restrict v_dst = (HVX_Vector *) dst;
@@ -48,6 +49,9 @@ static inline void hvx_fast_rms_norm_f32(const uint8_t * restrict src,
// Scale full vectors
HVX_Vector scale_v = hvx_vec_rsqrt_f32(Q6_Vsf_equals_Vqf32(mean_epsilon_v));
if (scale != 0.0f) {
scale_v = Q6_Vsf_equals_Vqf32(Q6_Vqf32_vmpy_VsfVsf(scale_v, hvx_vec_splat_f32(scale)));
}
#pragma unroll(4)
for (int i = 0; i < nvec; i++) {
@@ -72,7 +76,8 @@ static inline void hvx_fast_rms_norm_mul_f32(const uint8_t * restrict src,
const uint8_t * restrict weight,
uint8_t * restrict dst,
const int num_elems,
float epsilon) {
float epsilon,
float scale) {
const HVX_Vector * restrict v_src = (const HVX_Vector *) src;
const HVX_Vector * restrict v_weight = (const HVX_Vector *) weight;
HVX_Vector * restrict v_dst = (HVX_Vector *) dst;
@@ -109,6 +114,9 @@ static inline void hvx_fast_rms_norm_mul_f32(const uint8_t * restrict src,
// Scale and multiply
HVX_Vector scale_v = hvx_vec_rsqrt_f32(Q6_Vsf_equals_Vqf32(mean_epsilon_v));
if (scale != 0.0f) {
scale_v = Q6_Vsf_equals_Vqf32(Q6_Vqf32_vmpy_VsfVsf(scale_v, hvx_vec_splat_f32(scale)));
}
#pragma unroll(4)
for (int i = 0; i < nvec; i++) {
+8
View File
@@ -68,6 +68,14 @@ static inline HVX_Vector hvx_vec_tanh_f32(HVX_Vector x) {
return Q6_Vsf_equals_Vqf32(res);
}
static inline HVX_Vector hvx_vec_silu_f32(HVX_Vector x) {
HVX_Vector one = hvx_vec_splat_f32(1.0f);
HVX_Vector max_exp = hvx_vec_splat_f32(87.f);
HVX_Vector min_exp = hvx_vec_splat_f32(-87.f);
HVX_Vector sig = hvx_vec_fast_sigmoid_f32_guard(x, one, max_exp, min_exp);
return Q6_Vsf_equals_Vqf32(Q6_Vqf32_vmpy_VsfVsf(x, sig));
}
#define hvx_sigmoid_loop_body(dst_type, src_type, vec_store) \
do { \
dst_type * restrict vdst = (dst_type *) dst; \
+38 -34
View File
@@ -768,19 +768,13 @@ int op_im2col(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const struct htp_tensor * dst = octx->dst;
uint32_t row_base = 0;
uint32_t nrows = kparams->total_rows;
if (octx->ctx->mdev.count > 1) {
const uint32_t row_size = dst->nb[2];
const uint32_t rows_per_chunk = (row_size > 0) ? (HEX_L2_LINE_SIZE / hex_gcd_u32(row_size, HEX_L2_LINE_SIZE)) : 1;
const struct htp_tensor_mdev_range range =
htp_tensor_mdev_partition(kparams->total_rows, htp_tensor_mdev_data_aligned(dst) ? rows_per_chunk : 0,
htp_tensor_mdev_partition(kparams->total_rows, htp_tensor_mdev_data_aligned(dst) ? kparams->rows_per_chunk : 0,
octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
row_base = range.start;
nrows = range.count;
@@ -790,20 +784,27 @@ int op_im2col(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (!htp_ops_context_set_n_threads(octx, MIN((uint32_t) kparams->n_threads, nrows))) {
return HTP_STATUS_INVAL_PARAMS;
}
struct htp_im2col_vtcm_layout layout;
htp_im2col_vtcm_layout_build(&layout, kparams->src_row_bytes, kparams->dst_row_bytes, kparams->n_threads);
struct htp_im2col_context ictx = { 0 };
uint8_t * const base = octx->ctx->vtcm_base;
const uint32_t pth = MIN(octx->n_threads, nrows);
const uint32_t pth = octx->n_threads;
ictx.octx = octx;
ictx.pe_row_base = row_base;
ictx.pe_nrows = nrows;
ictx.pe_rows_per_thread = (nrows + pth - 1) / pth;
ictx.pe_rows_per_thread = fastdiv(nrows + pth - 1, &octx->n_threads_div);
ictx.pe_src_row_bytes = kparams->src_row_bytes;
ictx.pe_dst_row_bytes = kparams->dst_row_bytes;
ictx.pe_vtcm_src = VTCM_LAYOUT_PTR(uint8_t, base, kparams->off_src);
ictx.pe_vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, kparams->off_dst);
ictx.pe_src_size_per_thread = kparams->src_bytes_per_thread;
ictx.pe_dst_size_per_thread = kparams->dst_bytes_per_thread;
ictx.pe_vtcm_src = VTCM_LAYOUT_PTR(uint8_t, base, layout.off_src);
ictx.pe_vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, layout.off_dst);
ictx.pe_src_size_per_thread = layout.src_bytes_per_thread;
ictx.pe_dst_size_per_thread = layout.dst_bytes_per_thread;
ictx.pe_owb = kparams->owb;
ictx.pe_wb = kparams->wb;
ictx.pe_nbpr = kparams->nbpr;
@@ -821,9 +822,10 @@ int op_im2col(struct htp_ops_context * octx) {
ictx.patch_stride = kparams->patch_stride;
for (uint32_t ith = 0; ith < pth; ith++) {
uint32_t r = row_base + ictx.pe_rows_per_thread * ith;
ictx.thread_ioh[ith] = r % kparams->OH;
ictx.thread_in[ith] = r / kparams->OH;
const uint32_t r = row_base + ictx.pe_rows_per_thread * ith;
const uint32_t in = fastdiv(r, &kparams->div_OH);
ictx.thread_ioh[ith] = r - in * kparams->OH;
ictx.thread_in[ith] = in;
}
ictx.dst_elem = dst->type == HTP_TYPE_F16 ? sizeof(__fp16) : sizeof(float);
@@ -850,19 +852,13 @@ int op_im2col_3d(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const struct htp_tensor * dst = octx->dst;
uint32_t row_base = 0;
uint32_t nrows = kparams->total_rows;
if (octx->ctx->mdev.count > 1) {
const uint32_t row_size = dst->nb[2];
const uint32_t rows_per_chunk = (row_size > 0) ? (HEX_L2_LINE_SIZE / hex_gcd_u32(row_size, HEX_L2_LINE_SIZE)) : 1;
const struct htp_tensor_mdev_range range =
htp_tensor_mdev_partition(kparams->total_rows, htp_tensor_mdev_data_aligned(dst) ? rows_per_chunk : 0,
htp_tensor_mdev_partition(kparams->total_rows, htp_tensor_mdev_data_aligned(dst) ? kparams->rows_per_chunk : 0,
octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
row_base = range.start;
nrows = range.count;
@@ -872,20 +868,27 @@ int op_im2col_3d(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (!htp_ops_context_set_n_threads(octx, MIN((uint32_t) kparams->n_threads, nrows))) {
return HTP_STATUS_INVAL_PARAMS;
}
struct htp_im2col_vtcm_layout layout;
htp_im2col_vtcm_layout_build(&layout, kparams->src_row_bytes, kparams->dst_row_bytes, kparams->n_threads);
struct htp_im2col_context ictx = { 0 };
uint8_t * const base = octx->ctx->vtcm_base;
const uint32_t pth = MIN(octx->n_threads, nrows);
const uint32_t pth = octx->n_threads;
ictx.octx = octx;
ictx.pe_row_base = row_base;
ictx.pe_nrows = nrows;
ictx.pe_rows_per_thread = (nrows + pth - 1) / pth;
ictx.pe_rows_per_thread = fastdiv(nrows + pth - 1, &octx->n_threads_div);
ictx.pe_src_row_bytes = kparams->src_row_bytes;
ictx.pe_dst_row_bytes = kparams->dst_row_bytes;
ictx.pe_vtcm_src = VTCM_LAYOUT_PTR(uint8_t, base, kparams->off_src);
ictx.pe_vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, kparams->off_dst);
ictx.pe_src_size_per_thread = kparams->src_bytes_per_thread;
ictx.pe_dst_size_per_thread = kparams->dst_bytes_per_thread;
ictx.pe_vtcm_src = VTCM_LAYOUT_PTR(uint8_t, base, layout.off_src);
ictx.pe_vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, layout.off_dst);
ictx.pe_src_size_per_thread = layout.src_bytes_per_thread;
ictx.pe_dst_size_per_thread = layout.dst_bytes_per_thread;
ictx.pe_owb = kparams->owb;
ictx.pe_wb = kparams->wb;
ictx.pe_nbpr = kparams->nbpr;
@@ -903,11 +906,12 @@ int op_im2col_3d(struct htp_ops_context * octx) {
ictx.patch_stride = kparams->patch_stride;
for (uint32_t ith = 0; ith < pth; ith++) {
uint32_t rem = row_base + ictx.pe_rows_per_thread * ith;
ictx.thread_ioh[ith] = rem % kparams->OH;
rem /= kparams->OH;
ictx.thread_iod[ith] = rem % kparams->OD;
ictx.thread_in[ith] = rem / kparams->OD;
const uint32_t rem = row_base + ictx.pe_rows_per_thread * ith;
const uint32_t q_oh = fastdiv(rem, &kparams->div_OH);
ictx.thread_ioh[ith] = rem - q_oh * kparams->OH;
const uint32_t in = fastdiv(q_oh, &kparams->div_OD);
ictx.thread_iod[ith] = q_oh - in * kparams->OD;
ictx.thread_in[ith] = in;
}
ictx.dst_elem = dst->type == HTP_TYPE_F16 ? sizeof(__fp16) : sizeof(float);
+16 -15
View File
@@ -2,6 +2,8 @@
#define HTP_IM2COL_OPS_H
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
#include <stdint.h>
enum htp_im2col_kernel_type {
@@ -11,38 +13,33 @@ enum htp_im2col_kernel_type {
};
struct htp_im2col_vtcm_layout {
uint32_t off_src;
uint32_t off_dst;
size_t total_bytes;
size_t off_src;
size_t off_dst;
uint32_t src_bytes_per_thread;
uint32_t dst_bytes_per_thread;
uint32_t total_bytes;
};
static inline void htp_im2col_vtcm_layout_build(
struct htp_im2col_vtcm_layout * layout,
struct htp_im2col_vtcm_layout * L,
uint32_t src_row_bytes,
uint32_t dst_row_bytes,
uint32_t n_threads) {
layout->src_bytes_per_thread = 2 * src_row_bytes + 256;
layout->dst_bytes_per_thread = 2 * dst_row_bytes;
L->src_bytes_per_thread = 2 * src_row_bytes + 256;
L->dst_bytes_per_thread = 2 * dst_row_bytes;
layout->off_src = 0;
layout->off_dst = layout->off_src + layout->src_bytes_per_thread * n_threads;
layout->total_bytes = layout->off_dst + layout->dst_bytes_per_thread * n_threads;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src, (size_t) L->src_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, (size_t) L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
struct htp_im2col_kernel_params {
uint8_t kernel_type;
uint8_t is_2d;
uint8_t is_3d;
uint8_t n_threads;
uint32_t vtcm_size;
uint32_t off_src;
uint32_t off_dst;
uint32_t src_bytes_per_thread;
uint32_t dst_bytes_per_thread;
uint32_t src_row_bytes;
uint32_t dst_row_bytes;
@@ -57,6 +54,10 @@ struct htp_im2col_kernel_params {
uint32_t OD, OH, OW;
uint32_t patch_stride;
uint32_t total_rows;
uint32_t rows_per_chunk;
struct fastdiv_values div_OH;
struct fastdiv_values div_OD;
};
#if defined(__cplusplus)
+4 -7
View File
@@ -955,7 +955,9 @@ static int execute_op(struct htp_ops_context * octx) {
case HTP_OP_GLU_GEGLU:
case HTP_OP_GLU_GEGLU_QUICK:
case HTP_OP_GLU_GEGLU_ERF:
return op_activations(octx);
case HTP_OP_GLU_REGLU:
case HTP_OP_GLU_SIGMOID:
return op_glu(octx);
case HTP_OP_SOFTMAX:
return op_softmax(octx);
@@ -1244,8 +1246,6 @@ static int proc_op_req(struct htp_ops_context * octx, struct htp_buf_desc * bufs
octx->src0_spad.src = NULL;
octx->src1_spad.src = NULL;
octx->src2_spad.src = NULL;
octx->src3_spad.src = NULL;
octx->dst_spad.src = NULL;
return octx->status;
@@ -1306,10 +1306,7 @@ static void process_opbatch(struct htp_context * ctx, const struct htp_opbatch_r
prep_tensors(ctx, bufs, tens, n_tens);
struct htp_ops_context *octx = &ctx->octx;
memset(octx, 0, sizeof(*octx));
octx->n_threads = ctx->n_threads;
octx->n_threads_div = ctx->n_threads_div;
octx->ctx = ctx;
htp_ops_context_reset(octx, ctx);
mdev_group_init(ctx, req);
+9 -9
View File
@@ -1816,7 +1816,7 @@ static int hvx_mm_matmul(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne10 + qk - 1) / qk;
const uint32_t total_nb = act_nrows * nb;
@@ -1886,7 +1886,7 @@ static int hvx_mm_matmul(struct htp_ops_context * octx) {
mmctx->vtcm_src0_stride = src0_row_size_padded;
mmctx->vtcm_act_stride = act_row_size;
if (kparams->kernel_type == HTP_MM_KERNEL_HVX_QUANT_BLOCK || kparams->kernel_type == HTP_MM_KERNEL_HVX_QUANT_ROW) {
mmctx->vtcm_act_raw_stride = hex_round_up(ne10 * sizeof(float), QK_Q8_0_TILED * sizeof(float));
mmctx->vtcm_act_raw_stride = htp_mm_act_raw_row_size(ne10);
} else if (kparams->kernel_type == HTP_MM_KERNEL_HVX_F16_F16_VTCM) {
mmctx->vtcm_act_raw_stride = hex_round_up(ne10 * sizeof(float), 128);
} else {
@@ -1904,7 +1904,7 @@ static int hvx_mm_matmul(struct htp_ops_context * octx) {
if (need_quant) {
hvx_mm_transfer_act_dma(octx, kparams, act, mmctx->vtcm_act_raw, mmctx->vtcm_act_raw_stride, m_start, cur_m_rows);
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne10 + qk - 1) / qk;
const uint32_t total_nb = cur_m_rows * nb;
uint32_t quant_tasks;
@@ -3914,7 +3914,7 @@ static int hvx_mm_matmul_id(
const struct htp_tensor * restrict ids = octx->src[2];
const size_t src0_row_size = nb01;
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (ne10 + qk - 1) / qk;
const uint32_t total_nb = act_nrows * nb;
@@ -3966,7 +3966,7 @@ static int hvx_mm_matmul_id(
mmctx->vtcm_src0_stride = src0_row_size_padded;
mmctx->vtcm_act_stride = act_row_size;
mmctx->vtcm_act_raw_stride = hex_round_up(ne10 * sizeof(float), QK_Q8_0_TILED * sizeof(float));
mmctx->vtcm_act_raw_stride = htp_mm_act_raw_row_size(ne10);
mmctx->vtcm_src0_size_per_thread = fastdiv(L.src0_bytes, &octx->n_threads_div);
mmctx->vtcm_act_size_per_thread = L.act_bytes;
@@ -4081,7 +4081,7 @@ static int hvx_mm_matmul_id_nx(
const struct htp_tensor * restrict ids = octx->src[n_weights + 1];
const size_t src0_row_size = src0->nb[1];
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (act->ne[0] + qk - 1) / qk;
const uint32_t total_nb = act_nrows * nb;
@@ -4124,7 +4124,7 @@ static int hvx_mm_matmul_id_nx(
mmctx->vtcm_src0_stride = 0;
mmctx->vtcm_act_stride = act_row_size;
mmctx->vtcm_act_raw_stride = hex_round_up(act->ne[0] * sizeof(float), QK_Q8_0_TILED * sizeof(float));
mmctx->vtcm_act_raw_stride = htp_mm_act_raw_row_size(act->ne[0]);
mmctx->vtcm_src0_size_per_thread = fastdiv(L.src0_bytes, &octx->n_threads_div);
mmctx->vtcm_act_size_per_thread = L.act_bytes;
@@ -4474,7 +4474,7 @@ static int op_matmul_nx_impl(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
const uint32_t qk = QK_Q8_0_TILED;
const uint32_t qk = HTP_MM_ACT_BLOCK_K;
const uint32_t nb = (act->ne[0] + qk - 1) / qk;
const uint32_t total_nb = act_nrows * nb;
@@ -4518,7 +4518,7 @@ static int op_matmul_nx_impl(struct htp_ops_context * octx) {
mmctx->vtcm_src0_stride = 0;
mmctx->vtcm_act_stride = act_row_size;
mmctx->vtcm_act_raw_stride = hex_round_up(act->ne[0] * sizeof(float), QK_Q8_0_TILED * sizeof(float));
mmctx->vtcm_act_raw_stride = htp_mm_act_raw_row_size(act->ne[0]);
mmctx->vtcm_src0_size_per_thread = fastdiv(L.src0_bytes, &octx->n_threads_div);
mmctx->vtcm_act_size_per_thread = L.act_bytes;
+12 -10
View File
@@ -25,6 +25,7 @@ extern "C" {
#define HTP_MM_WEIGHT_ALIGNED_TILE_SIZE_Q2_0 640
// --- Activation Tiled Block Sizes (including padding) ---
#define HTP_MM_ACT_BLOCK_K 128
#define HTP_MM_ACT_TILE_SIZE_Q8_0 1152
#define HTP_MM_ACT_TILE_SIZE_Q8_1 1280
#define HTP_MM_ACT_TILE_SIZE_F16 2048
@@ -74,10 +75,7 @@ struct htp_mm_kernel_params {
int32_t aligned_tile_size; // Aligned weight tile size (padded to 128)
int32_t act_row_size; // Row size for activation scratchpad
int32_t vtcm_size; // Total required scratchpad size in VTCM
int32_t vtcm_src0_size; // src0 scratchpad size in VTCM
int32_t vtcm_act_size; // activation scratchpad size in VTCM
int32_t vtcm_bias_size; // bias scratchpad size in VTCM (fused only)
int32_t vtcm_dst_size; // dst scratchpad size in VTCM
// Precomputed division values
struct fastdiv_values div_ne12_ne1;
@@ -192,19 +190,19 @@ static inline bool htp_mm_weight_has_offset(int weight_type) {
// --- Activation/Row Size Helpers ---
static inline size_t htp_mm_q8_0_tiled_row_size(uint32_t ne) {
const uint32_t ne_padded = ((ne + 127) / 128) * 128;
const uint32_t ne_padded = hex_round_up(ne, HTP_MM_ACT_BLOCK_K);
const uint32_t nb_32 = ne_padded / 32;
return nb_32 * HTP_MM_ACT_TILE_SIZE_Q8_0;
}
static inline size_t htp_mm_q8_1_tiled_row_size(uint32_t ne) {
const uint32_t ne_padded = ((ne + 127) / 128) * 128;
const uint32_t ne_padded = hex_round_up(ne, HTP_MM_ACT_BLOCK_K);
const uint32_t nb_32 = ne_padded / 32;
return nb_32 * HTP_MM_ACT_TILE_SIZE_Q8_1;
}
static inline size_t htp_mm_f16_tiled_row_size(uint32_t ne) {
const uint32_t ne_padded = ((ne + 127) / 128) * 128;
const uint32_t ne_padded = hex_round_up(ne, HTP_MM_ACT_BLOCK_K);
const uint32_t nb_32 = ne_padded / 32;
return nb_32 * HTP_MM_ACT_TILE_SIZE_F16;
}
@@ -216,6 +214,10 @@ static inline size_t htp_mm_tiled_act_row_size(int weight_type, uint32_t ne) {
return htp_mm_weight_has_offset(weight_type) ? htp_mm_q8_1_tiled_row_size(ne) : htp_mm_q8_0_tiled_row_size(ne);
}
static inline size_t htp_mm_act_raw_row_size(uint32_t ne) {
return hex_round_up(ne, HTP_MM_ACT_BLOCK_K) * sizeof(float);
}
static inline size_t htp_mm_round_up(size_t n, size_t m) {
return ((n + m - 1) / m) * m;
}
@@ -445,7 +447,7 @@ static inline void htp_mm_hvx_vtcm_layout_build(
size_t tiled_act_row_size = htp_mm_tiled_act_row_size(wtype, ne10);
size_t q_act_sz = hex_round_up(tiled_act_row_size * act_nrows, 128);
size_t raw_row_size = hex_round_up(ne10 * sizeof(float), QK_Q8_0_TILED * sizeof(float));
size_t raw_row_size = htp_mm_act_raw_row_size(ne10);
src0_sz = weight_sz_per_thread * n_threads; // shared single-weight prefetch buffer
act_sz = q_act_sz; // quantized activation buffer
@@ -461,7 +463,7 @@ static inline void htp_mm_hvx_vtcm_layout_build(
act_sz = htp_mm_round_up(act_row_size_tiled * act_nrows, 256);
size_t raw_row_size = hex_round_up(ne10 * sizeof(float), QK_Q8_0_TILED * sizeof(float));
size_t raw_row_size = htp_mm_act_raw_row_size(ne10);
src0_sz = src0_sz_per_thread * n_threads;
dst_sz = 0;
@@ -502,7 +504,7 @@ static inline void htp_mm_hvx_vtcm_layout_build(
size_t dst_slice_per_thread = (dst_nrows > 0 && act_nrows == 1) ? htp_mm_round_up((dst_row_size + n_threads - 1) / n_threads, 128) : 0;
dst_sz = dst_slice_per_thread * n_threads;
size_t raw_row_size = hex_round_up(ne10 * sizeof(float), QK_Q8_0_TILED * sizeof(float));
size_t raw_row_size = htp_mm_act_raw_row_size(ne10);
act_raw_sz = hex_round_up(raw_row_size * act_nrows, 128);
break;
}
@@ -582,7 +584,7 @@ static inline bool htp_mm_hvx_solve_vtcm_params(
size_t eff_row_size = row_size;
if (kernel_type == HTP_MM_KERNEL_HVX_QUANT_ROW || kernel_type == HTP_MM_KERNEL_HVX_QUANT_BLOCK) {
eff_row_size += hex_round_up(ne10 * sizeof(float), QK_Q8_0_TILED * sizeof(float));
eff_row_size += htp_mm_act_raw_row_size(ne10);
}
uint32_t m_chunk = (uint32_t) (avail_act / eff_row_size);
+80 -67
View File
@@ -17,18 +17,28 @@
#include "htp-ctx.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "htp-vtcm.h"
#include "pad-ops.h"
/* Circular wrap: maps any integer x into [0, n) */
static inline uint32_t wrap_around(int32_t x, uint32_t n) {
return (uint32_t)(((x % (int32_t)n) + (int32_t)n) % (int32_t)n);
static inline uint32_t wrap_around(int32_t x, uint32_t n, const struct fastdiv_values * div_n) {
if (x >= 0) {
const uint32_t ux = (uint32_t) x;
return ux < n ? ux : fastmodulo(ux, n, div_n);
}
const uint32_t ux = (uint32_t) (-x);
const uint32_t rem = ux < n ? ux : fastmodulo(ux, n, div_n);
return rem ? (n - rem) : 0;
}
/* Decompose a flat dst row index into (i1, i2, i3) */
static inline void pad_decompose_row(uint32_t ir, uint32_t ne1, uint32_t ne2,
const struct htp_pad_kernel_params * kparams,
uint32_t *i1, uint32_t *i2, uint32_t *i3) {
*i1 = ir % ne1;
*i2 = (ir / ne1) % ne2;
*i3 = ir / (ne1 * ne2);
*i3 = fastdiv(ir, &kparams->div_ne1_ne2);
const uint32_t rem = ir - (*i3) * (ne1 * ne2);
*i2 = fastdiv(rem, &kparams->div_ne1);
*i1 = rem - (*i2) * ne1;
}
/* Return non-zero if row (i1,i2,i3) falls in the non-padded interior */
@@ -62,25 +72,28 @@ static inline dma_addr_t pad_src_row_data(const struct htp_tensor * src,
/* Compute the DDR src row pointer for a circular row (wrap-around indexing) */
static inline const uint8_t * pad_circ_src_row_ptr(const struct htp_tensor * src,
const struct htp_pad_kernel_params * kparams,
uint32_t i1, uint32_t i2, uint32_t i3,
int32_t lp1, int32_t lp2, int32_t lp3) {
return (const uint8_t *) src->data
+ wrap_around((int32_t)i1 - lp1, src->ne[1]) * src->nb[1]
+ wrap_around((int32_t)i2 - lp2, src->ne[2]) * src->nb[2]
+ wrap_around((int32_t)i3 - lp3, src->ne[3]) * src->nb[3];
+ wrap_around((int32_t)i1 - lp1, src->ne[1], &kparams->div_ne01) * src->nb[1]
+ wrap_around((int32_t)i2 - lp2, src->ne[2], &kparams->div_ne02) * src->nb[2]
+ wrap_around((int32_t)i3 - lp3, src->ne[3], &kparams->div_ne03) * src->nb[3];
}
static inline dma_addr_t pad_circ_src_row_data(const struct htp_tensor * src,
const struct htp_pad_kernel_params * kparams,
uint32_t i1, uint32_t i2, uint32_t i3,
int32_t lp1, int32_t lp2, int32_t lp3) {
return src->data
+ wrap_around((int32_t)i1 - lp1, src->ne[1]) * src->nb[1]
+ wrap_around((int32_t)i2 - lp2, src->ne[2]) * src->nb[2]
+ wrap_around((int32_t)i3 - lp3, src->ne[3]) * src->nb[3];
+ wrap_around((int32_t)i1 - lp1, src->ne[1], &kparams->div_ne01) * src->nb[1]
+ wrap_around((int32_t)i2 - lp2, src->ne[2], &kparams->div_ne02) * src->nb[2]
+ wrap_around((int32_t)i3 - lp3, src->ne[3], &kparams->div_ne03) * src->nb[3];
}
struct htp_pad_context {
struct htp_ops_context * octx;
const struct htp_pad_kernel_params * kparams;
int32_t lp0, rp0;
int32_t lp1, rp1;
@@ -152,7 +165,7 @@ static void pad_job_per_thread_hvx(unsigned int nth, unsigned int ith, void * da
for (uint32_t dst_row = row_start; dst_row < row_end; dst_row++) {
uint32_t i1, i2, i3;
pad_decompose_row(dst_row, ne1, ne2, &i1, &i2, &i3);
pad_decompose_row(dst_row, ne1, ne2, pctx->kparams, &i1, &i2, &i3);
uint8_t * dst_ptr = (uint8_t *) dst->data + i1 * nb1 + i2 * nb2 + i3 * nb3;
@@ -219,7 +232,7 @@ static void pad_job_per_thread_hvx_dma(unsigned int nth, unsigned int ith, void
dst_row_size, dst_row_size_aligned, dst_row_size, 0);
uint32_t i1, i2, i3;
pad_decompose_row(ir, ne1, ne2, &i1, &i2, &i3);
pad_decompose_row(ir, ne1, ne2, pctx->kparams, &i1, &i2, &i3);
const int interior = pad_is_interior(i1, i2, i3,
lp1, rp1, ne1,
lp2, rp2, ne2,
@@ -246,7 +259,7 @@ static void pad_job_per_thread_hvx_dma(unsigned int nth, unsigned int ith, void
uint8_t * src_spad_cur = (uint8_t *) dma_queue_pop(dma_q).dst;
uint32_t i1, i2, i3;
pad_decompose_row(ir, ne1, ne2, &i1, &i2, &i3);
pad_decompose_row(ir, ne1, ne2, pctx->kparams, &i1, &i2, &i3);
const dma_addr_t dst_data = dst->data + i1 * nb1 + i2 * nb2 + i3 * nb3;
@@ -278,7 +291,7 @@ static void pad_job_per_thread_hvx_dma(unsigned int nth, unsigned int ith, void
const uint32_t next_row = ir + 2;
if (next_row < row_end) {
uint32_t ni1, ni2, ni3;
pad_decompose_row(next_row, ne1, ne2, &ni1, &ni2, &ni3);
pad_decompose_row(next_row, ne1, ne2, pctx->kparams, &ni1, &ni2, &ni3);
const int next_interior = pad_is_interior(ni1, ni2, ni3,
lp1, rp1, ne1,
lp2, rp2, ne2,
@@ -315,10 +328,10 @@ static void pad_job_per_thread_hvx_circular(unsigned int nth, unsigned int ith,
for (uint32_t dst_row = row_start; dst_row < row_end; dst_row++) {
uint32_t i1, i2, i3;
pad_decompose_row(dst_row, ne1, ne2, &i1, &i2, &i3);
pad_decompose_row(dst_row, ne1, ne2, pctx->kparams, &i1, &i2, &i3);
uint8_t * dst_ptr = (uint8_t *) dst->data + i1 * nb1 + i2 * nb2 + i3 * nb3;
const uint8_t * src_row = pad_circ_src_row_ptr(src, i1, i2, i3, lp1, lp2, lp3);
const uint8_t * src_row = pad_circ_src_row_ptr(src, pctx->kparams, i1, i2, i3, lp1, lp2, lp3);
if (nb00 == type_size) {
@@ -393,8 +406,8 @@ static void pad_job_per_thread_hvx_circular_dma(unsigned int nth, unsigned int i
dst_row_size, dst_row_size_aligned, dst_row_size, 0);
uint32_t pi1, pi2, pi3;
pad_decompose_row(ir, ne1, ne2, &pi1, &pi2, &pi3);
const dma_addr_t src_data = pad_circ_src_row_data(src, pi1, pi2, pi3, lp1, lp2, lp3);
pad_decompose_row(ir, ne1, ne2, pctx->kparams, &pi1, &pi2, &pi3);
const dma_addr_t src_data = pad_circ_src_row_data(src, pctx->kparams, pi1, pi2, pi3, lp1, lp2, lp3);
dma_queue_push(dma_q,
dma_make_data(src_spad_cur, src_data),
src_row_size_aligned, src_row_size, src_row_size, 1);
@@ -411,7 +424,7 @@ static void pad_job_per_thread_hvx_circular_dma(unsigned int nth, unsigned int i
uint8_t * src_spad_cur = (uint8_t *) dma_queue_pop(dma_q).dst;
uint32_t i1, i2, i3;
pad_decompose_row(ir, ne1, ne2, &i1, &i2, &i3);
pad_decompose_row(ir, ne1, ne2, pctx->kparams, &i1, &i2, &i3);
const dma_addr_t dst_data = dst->data + i1 * nb1 + i2 * nb2 + i3 * nb3;
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) ir);
@@ -455,8 +468,8 @@ static void pad_job_per_thread_hvx_circular_dma(unsigned int nth, unsigned int i
const uint32_t next_row = ir + 2;
if (next_row < row_end) {
uint32_t nri1, nri2, nri3;
pad_decompose_row(next_row, ne1, ne2, &nri1, &nri2, &nri3);
const dma_addr_t next_src_data = pad_circ_src_row_data(src, nri1, nri2, nri3, lp1, lp2, lp3);
pad_decompose_row(next_row, ne1, ne2, pctx->kparams, &nri1, &nri2, &nri3);
const dma_addr_t next_src_data = pad_circ_src_row_data(src, pctx->kparams, nri1, nri2, nri3, lp1, lp2, lp3);
dma_queue_push(dma_q,
dma_make_data(src_spad_cur, next_src_data),
src_row_size_aligned, src_row_size, src_row_size, 1);
@@ -475,15 +488,8 @@ static void pad_job_per_thread_hvx_circular_dma(unsigned int nth, unsigned int i
int op_pad(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
// Only F32 supported
size_t type_size;
switch (src0->type) {
case HTP_TYPE_F32: type_size = 4; break;
default:
FARF(ERROR, "pad-hvx: unsupported type %u\n", src0->type);
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_pad_kernel_params * kparams =
(const struct htp_pad_kernel_params *) octx->kernel_params;
const int32_t lp0 = octx->op_params[0];
const int32_t rp0 = octx->op_params[1];
@@ -495,11 +501,10 @@ int op_pad(struct htp_ops_context * octx) {
const int32_t rp3 = octx->op_params[7];
const int32_t circular = octx->op_params[8];
const uint32_t ne0 = dst->ne[0];
const uint32_t ne00 = src0->ne[0];
const uint32_t total_dst_rows = dst->ne[1] * dst->ne[2] * dst->ne[3];
const size_t dst_row_size = (size_t)ne0 * type_size;
const uint32_t total_dst_rows = kparams->total_rows;
const size_t type_size = kparams->elem_size;
const size_t src_row_size = src0->ne[0] * type_size;
const size_t dst_row_size = dst->ne[0] * type_size;
uint32_t row_start = 0;
uint32_t nrows = total_dst_rows;
@@ -516,60 +521,68 @@ int op_pad(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, nrows))) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t n_threads = octx->n_threads;
const size_t src_row_size = (size_t)ne00 * type_size;
const size_t src_row_size_aligned = hex_round_up(src_row_size, VLEN);
const size_t dst_row_size_aligned = hex_round_up(dst_row_size, VLEN);
// Total VTCM needed: 2 buffers (ping+pong) for src and dst, per thread
const size_t vtcm_needed = (size_t)n_threads * 2 * (src_row_size_aligned + dst_row_size_aligned);
const int use_dma = (src0->nb[0] == (uint32_t)type_size) && (ne00 >= 512) &&
(octx->ctx->vtcm_size >= vtcm_needed);
if (!use_dma && (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst))) {
if (!kparams->use_dma && (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst))) {
return HTP_STATUS_NO_SUPPORT;
}
if (use_dma) {
octx->src0_spad.size_per_thread = 2 * src_row_size_aligned;
octx->dst_spad.size_per_thread = 2 * dst_row_size_aligned;
octx->src0_spad.size = n_threads * octx->src0_spad.size_per_thread;
octx->dst_spad.size = n_threads * octx->dst_spad.size_per_thread;
octx->src0_spad.data = octx->ctx->vtcm_base;
octx->dst_spad.data = octx->src0_spad.data + octx->src0_spad.size;
struct htp_pad_vtcm_layout layout = { 0 };
if (kparams->use_dma) {
htp_pad_vtcm_layout_build(&layout, src_row_size, dst_row_size, n_threads);
octx->src0_spad.size_per_thread = layout.src0_bytes_per_thread;
octx->dst_spad.size_per_thread = layout.dst_bytes_per_thread;
octx->src0_spad.size = n_threads * layout.src0_bytes_per_thread;
octx->dst_spad.size = n_threads * layout.dst_bytes_per_thread;
octx->src0_spad.data = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_src0);
octx->dst_spad.data = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_dst);
octx->src0_spad.src = NULL;
octx->dst_spad.src = NULL;
}
struct htp_pad_context pctx = {
.octx = octx,
.octx = octx,
.kparams = kparams,
.lp0 = lp0, .rp0 = rp0,
.lp1 = lp1, .rp1 = rp1,
.lp2 = lp2, .rp2 = rp2,
.lp3 = lp3, .rp3 = rp3,
.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div),
.total_dst_rows = nrows,
.row_start = row_start,
.type_size = type_size,
.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div),
.total_dst_rows = nrows,
.row_start = row_start,
.type_size = type_size,
.src_row_size = src_row_size,
.src_row_size_aligned = src_row_size_aligned,
.src_row_size_aligned = layout.src_row_size_aligned,
.dst_row_size = dst_row_size,
.dst_row_size_aligned = dst_row_size_aligned,
.dst_row_size_aligned = layout.dst_row_size_aligned,
};
FARF(HIGH, "pad-hvx%s%s: (%ux%ux%ux%u) -> (%ux%ux%ux%u) pads=(%d,%d,%d,%d,%d,%d,%d,%d)\n",
circular ? "-circ" : "",
use_dma ? "-dma" : "",
circular ? "-circ" : "",
kparams->use_dma ? "-dma" : "",
src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3],
dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3],
lp0, rp0, lp1, rp1, lp2, rp2, lp3, rp3);
if (circular && use_dma) { work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx_circular_dma, &pctx, n_threads); }
else if (circular) { work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx_circular, &pctx, n_threads); }
else if (use_dma) { work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx_dma, &pctx, n_threads); }
else { work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx, &pctx, n_threads); }
switch (kparams->kernel_type) {
case HTP_PAD_KERNEL_HVX_CIRCULAR_DMA:
work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx_circular_dma, &pctx, n_threads);
break;
case HTP_PAD_KERNEL_HVX_CIRCULAR:
work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx_circular, &pctx, n_threads);
break;
case HTP_PAD_KERNEL_HVX_DMA:
work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx_dma, &pctx, n_threads);
break;
default:
work_queue_run(octx->ctx->work_queue, pad_job_per_thread_hvx, &pctx, n_threads);
break;
}
return HTP_STATUS_OK;
}
+65
View File
@@ -0,0 +1,65 @@
#ifndef HTP_PAD_OPS_H
#define HTP_PAD_OPS_H
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
#include <stdint.h>
enum htp_pad_kernel_type {
HTP_PAD_KERNEL_HVX = 0,
HTP_PAD_KERNEL_HVX_DMA = 1,
HTP_PAD_KERNEL_HVX_CIRCULAR = 2,
HTP_PAD_KERNEL_HVX_CIRCULAR_DMA = 3,
};
struct htp_pad_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_dst;
size_t src_row_size_aligned;
size_t dst_row_size_aligned;
size_t src0_bytes_per_thread;
size_t dst_bytes_per_thread;
};
static inline void htp_pad_vtcm_layout_build(
struct htp_pad_vtcm_layout * L,
size_t src_row_size,
size_t dst_row_size,
uint32_t n_threads
) {
L->src_row_size_aligned = hex_round_up(src_row_size, 128);
L->dst_row_size_aligned = hex_round_up(dst_row_size, 128);
L->src0_bytes_per_thread = 2 * L->src_row_size_aligned;
L->dst_bytes_per_thread = 2 * L->dst_row_size_aligned;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
struct htp_pad_kernel_params {
uint8_t kernel_type;
uint32_t n_threads;
uint32_t total_rows;
uint32_t use_dma;
uint32_t elem_size;
uint32_t vtcm_size;
struct fastdiv_values div_ne1;
struct fastdiv_values div_ne1_ne2;
struct fastdiv_values div_ne01;
struct fastdiv_values div_ne02;
struct fastdiv_values div_ne03;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_pad_kernel_params) <= 128, "htp_pad_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_pad_kernel_params) <= 128, "htp_pad_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_PAD_OPS_H
+27 -36
View File
@@ -247,6 +247,7 @@ typedef void (*pool_plane_fn_t)(const float * src, float * dst, const struct htp
struct pool_2d_context {
struct htp_ops_context * octx;
const struct htp_pool_2d_kernel_params * kparams;
struct htp_pool_vtcm_layout layout;
pool_plane_fn_t pool_plane;
uint32_t n_threads;
uint32_t plane_start;
@@ -257,6 +258,7 @@ struct pool_2d_context {
static void pool_2d_thread(unsigned int nth, unsigned int ith, void * data) {
struct pool_2d_context * ctx = (struct pool_2d_context *) data;
const struct htp_pool_2d_kernel_params * p = ctx->kparams;
const struct htp_pool_vtcm_layout * L = &ctx->layout;
const struct htp_tensor * src0 = ctx->octx->src[0];
const struct htp_tensor * dst = ctx->octx->dst;
pool_plane_fn_t pool_plane = ctx->pool_plane;
@@ -271,15 +273,14 @@ static void pool_2d_thread(unsigned int nth, unsigned int ith, void * data) {
struct htp_thread_trace * tr = &ctx->octx->ctx->trace[ith];
dma_queue * dma_queue = ctx->octx->ctx->dma[ith];
const uint32_t src_spad_half = p->src_plane_bytes_aligned;
const uint32_t dst_spad_half = p->dst_plane_bytes_aligned;
const uint32_t src_bytes_per_thread = 2 * src_spad_half;
const uint32_t dst_bytes_per_thread = 2 * dst_spad_half;
const size_t off_dst = (size_t) ctx->n_threads * src_bytes_per_thread;
const uint32_t src_plane_bytes = L->src_plane_bytes;
const uint32_t dst_plane_bytes = L->dst_plane_bytes;
const uint32_t src_spad_half = (uint32_t) L->src_spad_half_size;
const uint32_t dst_spad_half = (uint32_t) L->dst_spad_half_size;
uint8_t * vtcm_base = (uint8_t *) ctx->octx->ctx->vtcm_base;
uint8_t * src_spad = vtcm_base + ith * src_bytes_per_thread;
uint8_t * dst_spad = vtcm_base + off_dst + ith * dst_bytes_per_thread;
uint8_t * src_spad = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, L->off_src) + ith * L->src_bytes_per_thread;
uint8_t * dst_spad = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, L->off_dst) + ith * L->dst_bytes_per_thread;
float * srcb2[2] = { (float *) src_spad, (float *) (src_spad + src_spad_half) };
float * dstb2[2] = { (float *) dst_spad, (float *) (dst_spad + dst_spad_half) };
@@ -290,14 +291,14 @@ static void pool_2d_thread(unsigned int nth, unsigned int ith, void * data) {
for (uint32_t i = 0; i < total && i < 2; ++i) {
dma_queue_push(dma_queue,
dma_make_data(dst->data, dstb2[i]),
p->dst_plane_bytes, dst_spad_half,
p->dst_plane_bytes, 0);
dst_plane_bytes, dst_spad_half,
dst_plane_bytes, 0);
const dma_addr_t src_addr = src0->data + (first + i) * p->src_plane_bytes;
const dma_addr_t src_addr = src0->data + (first + i) * src_plane_bytes;
dma_queue_push(dma_queue,
dma_make_data(srcb2[i], src_addr),
src_spad_half, p->src_plane_bytes,
p->src_plane_bytes, 1);
src_spad_half, src_plane_bytes,
src_plane_bytes, 1);
}
for (uint32_t i = 0; i < total; ++i) {
@@ -313,18 +314,18 @@ static void pool_2d_thread(unsigned int nth, unsigned int ith, void * data) {
pool_plane(srcb, dstb, p);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) plane);
const dma_addr_t dst_addr = dst->data + plane * p->dst_plane_bytes;
const dma_addr_t dst_addr = dst->data + plane * dst_plane_bytes;
dma_queue_push(dma_queue,
dma_make_data(dst_addr, dstb),
p->dst_plane_bytes, dst_spad_half,
p->dst_plane_bytes, 1);
dst_plane_bytes, dst_spad_half,
dst_plane_bytes, 1);
if (i + 2 < total) {
const dma_addr_t next_src_addr = src0->data + (plane + 2) * p->src_plane_bytes;
const dma_addr_t next_src_addr = src0->data + (plane + 2) * src_plane_bytes;
dma_queue_push(dma_queue,
dma_make_data(srcb, next_src_addr),
src_spad_half, p->src_plane_bytes,
p->src_plane_bytes, 1);
src_spad_half, src_plane_bytes,
src_plane_bytes, 1);
}
}
@@ -337,22 +338,15 @@ static void pool_2d_thread(unsigned int nth, unsigned int ith, void * data) {
}
int op_pool_2d(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
const struct htp_pool_2d_kernel_params * p =
(const struct htp_pool_2d_kernel_params *) octx->kernel_params;
if (src0->type != HTP_TYPE_F32 || dst->type != HTP_TYPE_F32 ||
(p->pool_op != HTP_POOL_AVG && p->pool_op != HTP_POOL_MAX)) {
return HTP_STATUS_NO_SUPPORT;
}
uint32_t plane_start = 0;
uint32_t plane_count = p->planes;
if (octx->ctx->mdev.count > 1) {
const uint32_t planes_per_chunk = (p->dst_plane_bytes > 0) ? (HEX_L2_LINE_SIZE / hex_gcd_u32(p->dst_plane_bytes, HEX_L2_LINE_SIZE)) : 1;
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(
plane_count, htp_tensor_mdev_data_aligned(dst) ? planes_per_chunk : 0,
plane_count, htp_tensor_mdev_data_aligned(dst) ? p->planes_per_chunk : 0,
octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
plane_start = range.start;
plane_count = range.count;
@@ -369,16 +363,12 @@ int op_pool_2d(struct htp_ops_context * octx) {
const uint32_t planes_per_thread = fastdiv(plane_count + n_threads - 1, &octx->n_threads_div);
pool_plane_fn_t pool_plane;
if (p->global_path) {
pool_plane = pool_plane_global;
} else if (p->block_path) {
pool_plane = pool_plane_block;
} else if (p->narrow_path) {
pool_plane = pool_plane_hvx_narrow;
} else if (p->fast_path) {
pool_plane = pool_plane_hvx;
} else {
pool_plane = pool_plane_general;
switch (p->kernel_type) {
case HTP_POOL_KERNEL_GLOBAL: pool_plane = pool_plane_global; break;
case HTP_POOL_KERNEL_BLOCK: pool_plane = pool_plane_block; break;
case HTP_POOL_KERNEL_HVX_NARROW: pool_plane = pool_plane_hvx_narrow; break;
case HTP_POOL_KERNEL_HVX: pool_plane = pool_plane_hvx; break;
default: pool_plane = pool_plane_general; break;
}
struct pool_2d_context ctx = {
@@ -390,6 +380,7 @@ int op_pool_2d(struct htp_ops_context * octx) {
.plane_count = plane_count,
.planes_per_thread = planes_per_thread,
};
htp_pool_vtcm_layout_build(&ctx.layout, p->src_x, p->src_y, p->dst_x, p->dst_y, n_threads);
work_queue_run(octx->ctx->work_queue, pool_2d_thread, &ctx, n_threads);
return HTP_STATUS_OK;
}
+37 -27
View File
@@ -7,8 +7,18 @@
#include <string.h>
#include "hex-common.h"
#include "htp-vtcm.h"
enum htp_pool_kernel_type {
HTP_POOL_KERNEL_GENERAL = 0,
HTP_POOL_KERNEL_HVX,
HTP_POOL_KERNEL_HVX_NARROW,
HTP_POOL_KERNEL_GLOBAL,
HTP_POOL_KERNEL_BLOCK,
};
struct htp_pool_2d_kernel_params {
uint8_t kernel_type;
uint32_t src_x;
uint32_t src_y;
uint32_t dst_x;
@@ -19,17 +29,10 @@ struct htp_pool_2d_kernel_params {
uint32_t stride_y;
int32_t pad_x;
int32_t pad_y;
uint32_t src_plane_bytes;
uint32_t dst_plane_bytes;
uint32_t src_plane_bytes_aligned;
uint32_t dst_plane_bytes_aligned;
uint32_t n_threads;
uint32_t planes;
uint32_t planes_per_chunk;
uint32_t pool_op;
uint32_t fast_path;
uint32_t narrow_path;
uint32_t global_path;
uint32_t block_path;
uint32_t avg_divide_count;
uint32_t ox_lo;
uint32_t ox_hi;
@@ -46,12 +49,36 @@ struct htp_pool_vtcm_layout {
size_t total_bytes;
size_t off_src;
size_t off_dst;
uint32_t src_plane_bytes;
uint32_t dst_plane_bytes;
size_t src_bytes_per_thread;
size_t dst_bytes_per_thread;
size_t src_spad_half_size;
size_t dst_spad_half_size;
};
static inline void htp_pool_vtcm_layout_build(
struct htp_pool_vtcm_layout * L,
uint32_t src_x,
uint32_t src_y,
uint32_t dst_x,
uint32_t dst_y,
uint32_t n_threads
) {
// Full-plane double buffering (256 bytes guard space for vector loads)
L->src_plane_bytes = src_x * src_y * sizeof(float);
L->dst_plane_bytes = dst_x * dst_y * sizeof(float);
L->src_spad_half_size = hex_round_up(L->src_plane_bytes + 256, 128);
L->dst_spad_half_size = hex_round_up(L->dst_plane_bytes, 128);
L->src_bytes_per_thread = 2 * L->src_spad_half_size;
L->dst_bytes_per_thread = 2 * L->dst_spad_half_size;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src, L->src_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
static inline bool htp_pool_solve_layout(
struct htp_pool_vtcm_layout * layout,
uint32_t src_x,
@@ -61,25 +88,8 @@ static inline bool htp_pool_solve_layout(
uint32_t n_threads,
size_t vtcm_budget
) {
// Full-plane double buffering (256 bytes guard space for vector loads)
const size_t src_plane_bytes = (size_t) src_x * src_y * sizeof(float);
const size_t dst_plane_bytes = (size_t) dst_x * dst_y * sizeof(float);
const size_t src_plane_aligned = hex_round_up((uint32_t) src_plane_bytes + 256, 128);
const size_t dst_plane_aligned = hex_round_up((uint32_t) dst_plane_bytes, 128);
const size_t spad_per_thread = 2 * (src_plane_aligned + dst_plane_aligned);
if (spad_per_thread * n_threads > vtcm_budget) {
return false;
}
layout->src_spad_half_size = src_plane_aligned;
layout->dst_spad_half_size = dst_plane_aligned;
layout->src_bytes_per_thread = 2 * src_plane_aligned;
layout->dst_bytes_per_thread = 2 * dst_plane_aligned;
layout->off_src = 0;
layout->off_dst = layout->src_bytes_per_thread * n_threads;
layout->total_bytes = layout->off_dst + layout->dst_bytes_per_thread * n_threads;
return true;
htp_pool_vtcm_layout_build(layout, src_x, src_y, dst_x, dst_y, n_threads);
return layout->total_bytes <= vtcm_budget;
}
#endif // HTP_POOL_OPS_H
+24 -30
View File
@@ -16,14 +16,11 @@
#include "hex-profile.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "repeat-ops.h"
struct htp_repeat_context {
struct htp_ops_context * octx;
uint32_t nr0;
uint32_t nr1;
uint32_t nr2;
uint32_t nr3;
struct htp_ops_context * octx;
const struct htp_repeat_kernel_params * kparams;
uint32_t nrows_per_thread;
uint32_t total_dst_rows; // ne1 * ne2 * ne3
@@ -35,6 +32,7 @@ struct htp_repeat_context {
static void repeat_job_per_thread(unsigned int nth, unsigned int ith, void * data) {
const struct htp_repeat_context * rctx = (const struct htp_repeat_context *) data;
struct htp_ops_context * octx = rctx->octx;
const struct htp_repeat_kernel_params * kparams = rctx->kparams;
const struct htp_tensor * src = octx->src[0];
const struct htp_tensor * dst = octx->dst;
@@ -58,29 +56,30 @@ static void repeat_job_per_thread(unsigned int nth, unsigned int ith, void * dat
const uint32_t nb2 = dst->nb[2];
const uint32_t nb3 = dst->nb[3];
const uint32_t nr0 = rctx->nr0;
const uint32_t nr1 = rctx->nr1;
const uint32_t nr2 = rctx->nr2;
const uint32_t nr3 = rctx->nr3;
const uint32_t nr0 = kparams->nr0;
const size_t row_bytes = ne00 * rctx->type_size;
const uint32_t row_start = rctx->row_start + rctx->nrows_per_thread * ith;
const uint32_t row_end = MIN(row_start + rctx->nrows_per_thread, rctx->row_start + rctx->total_dst_rows);
if (row_start >= row_end) {
return;
}
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, row_start);
for (uint32_t dst_row = row_start; dst_row < row_end; dst_row++) {
// Decompose flat dst row index into (i1, i2, i3)
const uint32_t i1 = dst_row % ne1;
const uint32_t i2 = (dst_row / ne1) % ne2;
const uint32_t i3 = dst_row / (ne1 * ne2);
const uint32_t dst_row_div_ne1 = fastdiv(dst_row, &kparams->div_ne1);
const uint32_t i1 = dst_row - dst_row_div_ne1 * ne1;
const uint32_t i3 = fastdiv(dst_row, &kparams->div_ne12);
const uint32_t i2 = dst_row_div_ne1 - i3 * ne2;
// Map to source indices (tiling)
const uint32_t k1 = i1 % ne01;
const uint32_t k2 = i2 % ne02;
const uint32_t k3 = i3 % ne03;
const uint32_t k1 = fastmodulo(i1, ne01, &kparams->div_ne01);
const uint32_t k2 = fastmodulo(i2, ne02, &kparams->div_ne02);
const uint32_t k3 = fastmodulo(i3, ne03, &kparams->div_ne03);
const uint8_t * src_row = (const uint8_t *) src->data + k1 * nb01 + k2 * nb02 + k3 * nb03;
uint8_t * dst_base = (uint8_t *) dst->data + i1 * nb1 + i2 * nb2 + i3 * nb3;
@@ -104,15 +103,6 @@ int op_repeat(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0];
const struct htp_tensor * dst = octx->dst;
// Validate that dst dims are multiples of src dims
if (dst->ne[0] % src0->ne[0] != 0 ||
dst->ne[1] % src0->ne[1] != 0 ||
dst->ne[2] % src0->ne[2] != 0 ||
dst->ne[3] % src0->ne[3] != 0) {
FARF(ERROR, "repeat: dst dims must be multiples of src dims\n");
return HTP_STATUS_INVAL_PARAMS;
}
size_t type_size;
switch (src0->type) {
case HTP_TYPE_F32: type_size = 4; break;
@@ -126,6 +116,13 @@ int op_repeat(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_repeat_kernel_params * kparams =
(const struct htp_repeat_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t total_dst_rows = dst->ne[1] * dst->ne[2] * dst->ne[3];
const size_t dst_row_size = dst->ne[0] * type_size;
@@ -148,10 +145,7 @@ int op_repeat(struct htp_ops_context * octx) {
struct htp_repeat_context rctx = {
.octx = octx,
.nr0 = dst->ne[0] / src0->ne[0],
.nr1 = dst->ne[1] / src0->ne[1],
.nr2 = dst->ne[2] / src0->ne[2],
.nr3 = dst->ne[3] / src0->ne[3],
.kparams = kparams,
.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div),
.total_dst_rows = nrows,
.row_start = row_start,
@@ -161,7 +155,7 @@ int op_repeat(struct htp_ops_context * octx) {
FARF(HIGH, "repeat: (%ux%ux%ux%u) -> (%ux%ux%ux%u) nr=(%u,%u,%u,%u)\n",
src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3],
dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3],
rctx.nr0, rctx.nr1, rctx.nr2, rctx.nr3);
kparams->nr0, kparams->nr1, kparams->nr2, kparams->nr3);
work_queue_run(octx->ctx->work_queue, repeat_job_per_thread, &rctx, n_threads);
+27
View File
@@ -0,0 +1,27 @@
#ifndef HTP_REPEAT_OPS_H
#define HTP_REPEAT_OPS_H
#include "hex-fastdiv.h"
#include <stdint.h>
struct htp_repeat_kernel_params {
uint32_t n_threads;
uint32_t nr0;
uint32_t nr1;
uint32_t nr2;
uint32_t nr3;
struct fastdiv_values div_ne1;
struct fastdiv_values div_ne12;
struct fastdiv_values div_ne01;
struct fastdiv_values div_ne02;
struct fastdiv_values div_ne03;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_repeat_kernel_params) <= 128, "htp_repeat_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_repeat_kernel_params) <= 128, "htp_repeat_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_REPEAT_OPS_H
+48 -60
View File
@@ -17,16 +17,15 @@
#include "hex-profile.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "roll-ops.h"
struct htp_roll_context {
struct htp_ops_context * octx;
const struct htp_roll_kernel_params * kparams;
uint32_t row_start;
uint32_t nrows;
uint32_t nrows_per_thread;
struct fastdiv_values div_ne1;
struct fastdiv_values div_ne2_ne1;
};
static inline uint32_t htp_roll_wrap(int32_t i, uint32_t ne) {
@@ -39,30 +38,32 @@ static inline uint32_t htp_roll_wrap(int32_t i, uint32_t ne) {
return (uint32_t) i;
}
#define htp_roll_preamble \
const struct htp_tensor * src0 = octx->src[0]; \
const struct htp_tensor * dst = octx->dst; \
\
const uint32_t ne0 = dst->ne[0]; \
const uint32_t ne1 = dst->ne[1]; \
const uint32_t ne2 = dst->ne[2]; \
const uint32_t ne3 = dst->ne[3]; \
\
const uint32_t nb01 = src0->nb[1]; \
const uint32_t nb02 = src0->nb[2]; \
const uint32_t nb03 = src0->nb[3]; \
\
const uint32_t nb1 = dst->nb[1]; \
const uint32_t nb2 = dst->nb[2]; \
const uint32_t nb3 = dst->nb[3]; \
\
const int32_t s0 = octx->op_params[0]; \
const int32_t s1 = octx->op_params[1]; \
const int32_t s2 = octx->op_params[2]; \
const int32_t s3 = octx->op_params[3]; \
\
const uint32_t i0_src0 = htp_roll_wrap(-s0, ne0); \
const uint32_t n0 = ne0 - i0_src0;
#define htp_roll_preamble \
const struct htp_tensor * src0 = octx->src[0]; \
const struct htp_tensor * dst = octx->dst; \
const struct htp_roll_kernel_params * kparams = \
(const struct htp_roll_kernel_params *) octx->kernel_params; \
\
const uint32_t ne0 = dst->ne[0]; \
const uint32_t ne1 = dst->ne[1]; \
const uint32_t ne2 = dst->ne[2]; \
const uint32_t ne3 = dst->ne[3]; \
\
const uint32_t nb01 = src0->nb[1]; \
const uint32_t nb02 = src0->nb[2]; \
const uint32_t nb03 = src0->nb[3]; \
\
const uint32_t nb1 = dst->nb[1]; \
const uint32_t nb2 = dst->nb[2]; \
const uint32_t nb3 = dst->nb[3]; \
\
const int32_t s0 = octx->op_params[0]; \
const int32_t s1 = octx->op_params[1]; \
const int32_t s2 = octx->op_params[2]; \
const int32_t s3 = octx->op_params[3]; \
\
const uint32_t i0_src0 = kparams->i0_src0; \
const uint32_t n0 = kparams->n0;
#define htp_roll_dma_preamble dma_queue * q = octx->ctx->dma[0];
@@ -91,10 +92,10 @@ static inline void roll_dma_push_rows(dma_queue * q,
uint32_t src_row,
uint32_t nrows,
uint32_t row_size,
uint32_t i0_src0) {
uint32_t i0_src0,
uint32_t n0) {
const dma_addr_t dst_base = dst->data + (size_t) dst_row * row_size;
const dma_addr_t src_base = src0->data + (size_t) src_row * row_size;
const uint32_t n0 = src0->ne[0] - i0_src0;
roll_dma_push(q, dst_base, src_base + (size_t) i0_src0 * sizeof(float),
row_size, row_size, n0 * sizeof(float), nrows);
@@ -125,7 +126,7 @@ static int roll_dma_f32_contiguous(struct htp_ops_context * octx) {
const uint32_t row_size = ne0 * sizeof(float);
if (s1 == 0 && s2 == 0 && s3 == 0) {
roll_dma_push_rows(q, dst, src0, 0, 0, ne1 * ne2 * ne3, row_size, i0_src0);
roll_dma_push_rows(q, dst, src0, 0, 0, ne1 * ne2 * ne3, row_size, i0_src0, n0);
dma_queue_flush(q);
return HTP_STATUS_OK;
}
@@ -139,9 +140,9 @@ static int roll_dma_f32_contiguous(struct htp_ops_context * octx) {
const uint32_t n2_first = ne2 - i2_src0;
roll_dma_push_rows(q, dst, src0, dst_row0, src_row0, n2_first * ne1,
row_size, i0_src0);
row_size, i0_src0, n0);
roll_dma_push_rows(q, dst, src0, dst_row0 + n2_first * ne1, i03 * ne2 * ne1,
i2_src0 * ne1, row_size, i0_src0);
i2_src0 * ne1, row_size, i0_src0, n0);
}
dma_queue_flush(q);
@@ -159,9 +160,9 @@ static int roll_dma_f32_contiguous(struct htp_ops_context * octx) {
const uint32_t src_row0 = (i03 * ne2 + i02) * ne1;
roll_dma_push_rows(q, dst, src0, dst_row0, src_row0 + i1_src0,
n1_first, row_size, i0_src0);
n1_first, row_size, i0_src0, n0);
roll_dma_push_rows(q, dst, src0, dst_row0 + n1_first, src_row0,
i1_src0, row_size, i0_src0);
i1_src0, row_size, i0_src0, n0);
}
}
@@ -214,9 +215,9 @@ static void roll_thread_f32(unsigned int nth, unsigned int ith, void * data) {
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, row_start);
for (uint32_t row = row_start; row < row_end; row++) {
const uint32_t i3 = fastdiv(row, &rctx->div_ne2_ne1);
const uint32_t i3 = fastdiv(row, &kparams->div_ne2_ne1);
const uint32_t rem = row - i3 * ne2 * ne1;
const uint32_t i2 = fastdiv(rem, &rctx->div_ne1);
const uint32_t i2 = fastdiv(rem, &kparams->div_ne1);
const uint32_t i1 = rem - i2 * ne1;
const uint32_t i01 = htp_roll_wrap((int32_t) i1 - s1, ne1);
@@ -245,23 +246,14 @@ static void roll_thread_f32(unsigned int nth, unsigned int ith, void * data) {
int execute_op_roll_f32(struct htp_ops_context * octx) {
htp_roll_preamble;
if (src0->type != HTP_TYPE_F32 || dst->type != HTP_TYPE_F32) {
FARF(ERROR, "roll: unsupported type %u -> %u\n", src0->type, dst->type);
return HTP_STATUS_NO_SUPPORT;
if (kparams->kernel_type == HTP_ROLL_KERNEL_DMA_CONTIGUOUS) {
return roll_dma_f32_contiguous(octx);
}
if (kparams->kernel_type == HTP_ROLL_KERNEL_DMA_STRIDED) {
return roll_dma_f32_strided(octx);
}
if (src0->nb[0] != sizeof(float) || dst->nb[0] != sizeof(float)) {
FARF(ERROR, "roll: unsupported nb0 %u -> %u\n", src0->nb[0], dst->nb[0]);
return HTP_STATUS_NO_SUPPORT;
}
if (src0->ne[0] != ne0 || src0->ne[1] != ne1 ||
src0->ne[2] != ne2 || src0->ne[3] != ne3) {
FARF(ERROR, "roll: shape mismatch\n");
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t total_rows = ne1 * ne2 * ne3;
const uint32_t total_rows = kparams->total_rows;
const size_t dst_row_size = ne0 * sizeof(float);
uint32_t row_start = 0;
@@ -279,25 +271,21 @@ int execute_op_roll_f32(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (octx->ctx->mdev.count <= 1) {
if (htp_tensor_is_contiguous(src0, sizeof(float)) && htp_tensor_is_contiguous(dst, sizeof(float))) {
return roll_dma_f32_contiguous(octx);
}
return roll_dma_f32_strided(octx);
}
if (htp_tensor_is_extended(src0) || htp_tensor_is_extended(dst)) {
return HTP_STATUS_NO_SUPPORT;
}
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, nrows))) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t n_threads = octx->n_threads;
struct htp_roll_context rctx = {
.octx = octx,
.kparams = kparams,
.row_start = row_start,
.nrows = nrows,
.nrows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div),
.div_ne1 = init_fastdiv_values(dst->ne[1]),
.div_ne2_ne1 = init_fastdiv_values(dst->ne[2] * dst->ne[1]),
};
work_queue_run(octx->ctx->work_queue, roll_thread_f32, &rctx, n_threads);
+30
View File
@@ -0,0 +1,30 @@
#ifndef HTP_ROLL_OPS_H
#define HTP_ROLL_OPS_H
#include "hex-fastdiv.h"
#include <stdint.h>
enum htp_roll_kernel_type {
HTP_ROLL_KERNEL_DMA_CONTIGUOUS = 1,
HTP_ROLL_KERNEL_DMA_STRIDED = 2,
HTP_ROLL_KERNEL_HVX = 3,
};
struct htp_roll_kernel_params {
uint8_t kernel_type;
uint32_t n_threads;
uint32_t total_rows;
uint32_t i0_src0;
uint32_t n0;
struct fastdiv_values div_ne1;
struct fastdiv_values div_ne2_ne1;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_roll_kernel_params) <= 128, "htp_roll_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_roll_kernel_params) <= 128, "htp_roll_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_ROLL_OPS_H
+9 -15
View File
@@ -700,15 +700,6 @@ static int execute_op_rope_f32(struct htp_ops_context * octx) {
const struct htp_tensor * src2 = octx->src[2];
const struct htp_tensor * dst = octx->dst;
switch (octx->op) {
case HTP_OP_ROPE:
break;
default:
FARF(ERROR, "Unsupported Op %u\n", octx->op);
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_rope_kernel_params * kparams = (const struct htp_rope_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
@@ -746,20 +737,23 @@ static int execute_op_rope_f32(struct htp_ops_context * octx) {
const size_t dst_row_size = dst->ne[0] * sizeof(float);
const size_t dst_row_stride = dst->nb[1];
struct htp_rope_vtcm_layout layout;
htp_rope_vtcm_layout_build(&layout, src0->ne[0], kparams->n_threads, src2 ? src2->ne[0] : 0);
struct htp_rope_context rctx;
memset(&rctx, 0, sizeof(struct htp_rope_context));
rctx.octx = octx;
rctx.vtcm_base = (uint8_t *) octx->ctx->vtcm_base;
rctx.spad_per_thread = kparams->spad_per_thread;
rctx.theta_cache_offset = kparams->theta_cache_offset;
rctx.vtcm_base = VTCM_LAYOUT_PTR(uint8_t, octx->ctx->vtcm_base, layout.off_spad);
rctx.spad_per_thread = layout.bytes_per_thread;
rctx.theta_cache_offset = layout.theta_cache_size_aligned;
if (src2) {
dma_queue * dma_q = octx->ctx->dma[0];
const size_t ff_size = src2->ne[0] * sizeof(float);
float * vtcm_freq_factors = (float *) (rctx.vtcm_base + kparams->freq_factors_offset);
float * vtcm_freq_factors = VTCM_LAYOUT_PTR(float, octx->ctx->vtcm_base, layout.off_freq_factors);
dma_queue_push(dma_q, dma_make_data(vtcm_freq_factors, src2->data),
kparams->freq_factors_size, 0, ff_size, 1);
layout.freq_factors_size_aligned, 0, ff_size, 1);
dma_queue_pop(dma_q);
rctx.freq_factors = vtcm_freq_factors;
}
@@ -791,7 +785,7 @@ static int execute_op_rope_f32(struct htp_ops_context * octx) {
rctx.src0_row_stride = src0_row_stride;
rctx.dst_row_size = dst_row_size;
rctx.dst_row_stride = dst_row_stride;
rctx.src0_row_size_aligned = kparams->src0_row_size_aligned;
rctx.src0_row_size_aligned = layout.src0_row_size_aligned;
rctx.src0_nrows = nrows;
rctx.nrows = nrows;
+13 -13
View File
@@ -3,6 +3,7 @@
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-vtcm.h"
#define HTP_ROPE_SPAD_BLOCK 8
#define HTP_ROPE_SPAD_NSLOTS 4
@@ -10,14 +11,7 @@
struct htp_rope_kernel_params {
uint32_t n_threads;
uint32_t src0_nrows;
uint32_t src0_nrows_per_thread;
uint32_t vtcm_size;
uint32_t spad_per_thread;
uint32_t theta_cache_offset;
uint32_t src0_row_size_aligned;
uint32_t freq_factors_offset;
uint32_t freq_factors_size;
struct fastdiv_values div_ne2_ne1;
struct fastdiv_values div_ne1;
@@ -31,6 +25,8 @@ _Static_assert(sizeof(struct htp_rope_kernel_params) <= 128, "htp_rope_kernel_pa
struct htp_rope_vtcm_layout {
size_t total_bytes;
size_t off_spad;
size_t off_freq_factors;
size_t bytes_per_thread;
size_t theta_cache_size_aligned;
size_t src0_row_size_aligned;
@@ -38,7 +34,7 @@ struct htp_rope_vtcm_layout {
};
static inline void htp_rope_vtcm_layout_build(
struct htp_rope_vtcm_layout * layout,
struct htp_rope_vtcm_layout * L,
uint32_t ne00,
uint32_t n_threads,
uint32_t n_freq_factors
@@ -48,11 +44,15 @@ static inline void htp_rope_vtcm_layout_build(
const size_t theta_cache_size_aligned = hex_round_up((uint32_t) src0_row_size, 256);
const size_t freq_factors_size_aligned = hex_round_up(n_freq_factors * sizeof(float), 256);
layout->src0_row_size_aligned = src0_row_size_aligned;
layout->theta_cache_size_aligned = theta_cache_size_aligned;
layout->freq_factors_size_aligned = freq_factors_size_aligned;
layout->bytes_per_thread = theta_cache_size_aligned + HTP_ROPE_SPAD_NROWS * src0_row_size_aligned;
layout->total_bytes = layout->bytes_per_thread * n_threads + freq_factors_size_aligned;
L->src0_row_size_aligned = src0_row_size_aligned;
L->theta_cache_size_aligned = theta_cache_size_aligned;
L->freq_factors_size_aligned = freq_factors_size_aligned;
L->bytes_per_thread = theta_cache_size_aligned + HTP_ROPE_SPAD_NROWS * src0_row_size_aligned;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_spad, L->bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC_OPTIONAL(off, off_freq_factors, freq_factors_size_aligned, n_freq_factors > 0);
L->total_bytes = off;
}
static inline uint8_t * rope_spad_slot(uint8_t * base, uint32_t slot, size_t row_size_aligned) {
+4 -10
View File
@@ -79,8 +79,10 @@ static void set_rows_thread_dma_##TYPE_NAME##_##IDX_TYPE(unsigned int nth, unsig
const uint32_t ir1 = MIN(ir0 + dr, srctx->task_start + srctx->tasks); \
dma_queue * dma_q = octx->ctx->dma[ith]; \
const struct htp_set_rows_vtcm_layout * vtcm_layout = &srctx->vtcm_layout; \
uint8_t * vtcm_src0 = srctx->vtcm_base + vtcm_layout->off_src0 + ith * vtcm_layout->src0_bytes_per_thread; \
uint8_t * vtcm_dst = srctx->vtcm_base + vtcm_layout->off_dst + ith * vtcm_layout->dst_bytes_per_thread; \
uint8_t * vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, srctx->vtcm_base, vtcm_layout->off_src0) + \
ith * vtcm_layout->src0_bytes_per_thread; \
uint8_t * vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, srctx->vtcm_base, vtcm_layout->off_dst) + \
ith * vtcm_layout->dst_bytes_per_thread; \
const uint32_t src0_row_size = ne00 * sizeof(float); \
const uint32_t dst_row_size = htp_tensor_get_row_size(octx->dst->type, ne00); \
const uint32_t nrows_per_thread = ir1 - ir0; \
@@ -188,14 +190,6 @@ int op_set_rows(struct htp_ops_context * octx) {
const struct htp_set_rows_kernel_params * kparams = (const struct htp_set_rows_kernel_params *)octx->kernel_params;
set_rows_preamble;
if (octx->src[0]->type != HTP_TYPE_F32) {
return HTP_STATUS_NO_SUPPORT;
}
if (octx->dst->type != HTP_TYPE_F32 && octx->dst->type != HTP_TYPE_F16 && octx->dst->type != HTP_TYPE_Q8_0) {
return HTP_STATUS_NO_SUPPORT;
}
if (htp_tensor_is_extended(octx->src[1])) {
return HTP_STATUS_NO_SUPPORT;
}
+16 -34
View File
@@ -2,18 +2,13 @@
#define HTP_SET_ROWS_OPS_H
#include "hex-fastdiv.h"
#include "htp-tensor.h"
#include "htp-vtcm.h"
struct htp_set_rows_kernel_params {
int32_t n_threads;
int32_t total_tasks;
int32_t tasks_per_thread;
int32_t vtcm_size;
// Fastdiv helpers
struct fastdiv_values div_ne11;
struct fastdiv_values div_ne12;
struct fastdiv_values div_tasks_per_thread;
struct fastdiv_values div_ne02;
uint32_t n_threads;
uint32_t total_tasks;
uint32_t vtcm_size;
};
struct htp_set_rows_vtcm_layout {
@@ -29,40 +24,27 @@ struct htp_set_rows_vtcm_layout {
};
static inline void htp_set_rows_vtcm_layout_build(
struct htp_set_rows_vtcm_layout * vtcm_layout,
struct htp_set_rows_vtcm_layout * L,
int dst_type,
uint32_t ne00,
uint32_t n_threads) {
size_t src0_row_size = ne00 * 4;
size_t dst_row_size = 0;
switch (dst_type) {
case 0: // HTP_TYPE_F32
dst_row_size = ne00 * 4;
break;
case 1: // HTP_TYPE_F16
dst_row_size = ne00 * 2;
break;
case 8: // HTP_TYPE_Q8_0
dst_row_size = (ne00 / 32) * 34;
break;
default:
dst_row_size = 0;
break;
}
size_t src0_row_size = ne00 * sizeof(float);
size_t dst_row_size = htp_tensor_get_row_size(dst_type, ne00);
size_t src0_row_size_aligned = (src0_row_size + 255) & ~255;
size_t dst_row_size_aligned = (dst_row_size + 255) & ~255;
vtcm_layout->src0_spad_half_size = src0_row_size_aligned;
vtcm_layout->dst_spad_half_size = dst_row_size_aligned;
L->src0_spad_half_size = src0_row_size_aligned;
L->dst_spad_half_size = dst_row_size_aligned;
vtcm_layout->src0_bytes_per_thread = src0_row_size_aligned * 2;
vtcm_layout->dst_bytes_per_thread = dst_row_size_aligned * 2;
L->src0_bytes_per_thread = src0_row_size_aligned * 2;
L->dst_bytes_per_thread = dst_row_size_aligned * 2;
vtcm_layout->off_src0 = 0;
vtcm_layout->off_dst = vtcm_layout->off_src0 + vtcm_layout->src0_bytes_per_thread * n_threads;
vtcm_layout->total_bytes = vtcm_layout->off_dst + vtcm_layout->dst_bytes_per_thread * n_threads;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
L->total_bytes = off;
}
#if defined(__cplusplus)
+21 -17
View File
@@ -496,7 +496,7 @@ static int execute_op_softmax_f32(struct htp_ops_context * octx) {
return HTP_STATUS_INVAL_PARAMS;
}
if (kparams->kernel_id >= HTP_SOFTMAX_KERNEL_COUNT) {
if (kparams->kernel_type >= HTP_SOFTMAX_KERNEL_COUNT) {
return HTP_STATUS_INVAL_PARAMS;
}
@@ -532,34 +532,38 @@ static int execute_op_softmax_f32(struct htp_ops_context * octx) {
const uint32_t n_threads = octx->n_threads;
uint8_t * const vtcm_base = (uint8_t *) octx->ctx->vtcm_base;
const uint32_t off_src0 = 0;
const uint32_t off_dst = off_src0 + kparams->vtcm_src0_size_per_thread * kparams->n_threads;
const uint32_t off_src1 = off_dst + kparams->vtcm_dst_size_per_thread * kparams->n_threads;
struct htp_softmax_vtcm_layout layout;
htp_softmax_vtcm_layout_build(&layout,
src0->ne[0],
kparams->use_src1 ? octx->src[1]->ne[0] : 0,
kparams->use_src1 != 0,
kparams->use_f16 != 0,
kparams->n_threads);
struct htp_softmax_context smctx = {
.octx = octx,
.kparams = kparams,
.compute = (void *) softmax_kernels[kparams->kernel_id],
.compute = (void *) softmax_kernels[kparams->kernel_type],
.data_src0 = src0->data,
.data_src1 = kparams->use_src1 ? octx->src[1]->data : 0,
.data_dst = dst->data,
.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, off_src0),
.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, off_dst),
.vtcm_src1 = VTCM_LAYOUT_PTR_OPTIONAL(uint8_t, vtcm_base, off_src1, kparams->use_src1),
.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, layout.off_src0),
.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, vtcm_base, layout.off_dst),
.vtcm_src1 = VTCM_LAYOUT_PTR_OPTIONAL(uint8_t, vtcm_base, layout.off_src1, kparams->use_src1),
.vtcm_src0_size_per_thread = kparams->vtcm_src0_size_per_thread,
.vtcm_src1_size_per_thread = kparams->vtcm_src1_size_per_thread,
.vtcm_dst_size_per_thread = kparams->vtcm_dst_size_per_thread,
.vtcm_src0_size_per_thread = (uint32_t) layout.src0_bytes_per_thread,
.vtcm_src1_size_per_thread = (uint32_t) layout.src1_bytes_per_thread,
.vtcm_dst_size_per_thread = (uint32_t) layout.dst_bytes_per_thread,
.src0_spad_half_size = kparams->src0_spad_half_size,
.src1_spad_half_size = kparams->src1_spad_half_size,
.dst_spad_half_size = kparams->dst_spad_half_size,
.src0_spad_half_size = (uint32_t) layout.src0_spad_half_size,
.src1_spad_half_size = (uint32_t) layout.src1_spad_half_size,
.dst_spad_half_size = (uint32_t) layout.dst_spad_half_size,
.src0_row_size_aligned = kparams->src0_row_size_aligned,
.src1_row_size_aligned = kparams->src1_row_size_aligned,
.dst_row_size_aligned = kparams->dst_row_size_aligned,
.src0_row_size_aligned = (uint32_t) layout.src0_spad_half_size,
.src1_row_size_aligned = (uint32_t) layout.src1_spad_half_size,
.dst_row_size_aligned = (uint32_t) layout.dst_spad_half_size,
.use_f16 = kparams->use_f16 != 0,
+15 -27
View File
@@ -7,8 +7,9 @@
#include <math.h>
#include "hex-fastdiv.h"
#include "hex-common.h"
#include "htp-vtcm.h"
enum htp_softmax_kernel_id {
enum htp_softmax_kernel_type {
HTP_SOFTMAX_KERNEL_NOMASK = 0,
HTP_SOFTMAX_KERNEL_MASK_F32,
HTP_SOFTMAX_KERNEL_MASK_F16,
@@ -16,28 +17,14 @@ enum htp_softmax_kernel_id {
};
struct htp_softmax_kernel_params {
uint8_t kernel_type;
uint32_t n_threads;
uint32_t src0_nrows;
uint32_t src0_nrows_per_thread;
uint32_t vtcm_size;
uint32_t vtcm_src0_size_per_thread;
uint32_t vtcm_src1_size_per_thread;
uint32_t vtcm_dst_size_per_thread;
uint32_t src0_row_size_aligned;
uint32_t src1_row_size_aligned;
uint32_t dst_row_size_aligned;
uint32_t src0_spad_half_size;
uint32_t src1_spad_half_size;
uint32_t dst_spad_half_size;
uint32_t n_head;
uint32_t n_head_log2;
uint32_t use_src1;
uint32_t use_f16;
uint32_t kernel_id;
float scale;
float max_bias;
@@ -72,7 +59,7 @@ struct htp_softmax_vtcm_layout {
};
static inline void htp_softmax_vtcm_layout_build(
struct htp_softmax_vtcm_layout * layout,
struct htp_softmax_vtcm_layout * L,
uint32_t ne00,
uint32_t ne10,
bool use_src1,
@@ -87,20 +74,21 @@ static inline void htp_softmax_vtcm_layout_build(
size_t dst_row_size_aligned = hex_round_up(dst_row_size, 128);
size_t src1_row_size_aligned = use_src1 ? hex_round_up(src1_row_size, 128) : 0;
layout->src0_spad_half_size = src0_row_size_aligned;
layout->dst_spad_half_size = dst_row_size_aligned;
layout->src1_spad_half_size = src1_row_size_aligned;
L->src0_spad_half_size = src0_row_size_aligned;
L->dst_spad_half_size = dst_row_size_aligned;
L->src1_spad_half_size = src1_row_size_aligned;
// Double buffering: 2 half-buffers per thread
layout->src0_bytes_per_thread = src0_row_size_aligned * 2;
layout->dst_bytes_per_thread = dst_row_size_aligned * 2;
layout->src1_bytes_per_thread = src1_row_size_aligned * 2;
L->src0_bytes_per_thread = src0_row_size_aligned * 2;
L->dst_bytes_per_thread = dst_row_size_aligned * 2;
L->src1_bytes_per_thread = src1_row_size_aligned * 2;
layout->off_src0 = 0;
layout->off_dst = layout->off_src0 + layout->src0_bytes_per_thread * n_threads;
layout->off_src1 = layout->off_dst + layout->dst_bytes_per_thread * n_threads;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes_per_thread * n_threads);
VTCM_LAYOUT_ALLOC_OPTIONAL(off, off_src1, L->src1_bytes_per_thread * n_threads, use_src1);
layout->total_bytes = layout->off_src1 + layout->src1_bytes_per_thread * n_threads;
L->total_bytes = off;
}
#endif // HTP_SOFTMAX_OPS_H
+32 -41
View File
@@ -13,14 +13,16 @@
#include "htp-tensor.h"
#include "hvx-types.h"
#include "hvx-utils.h"
#include "solve-tri-ops.h"
struct htp_solve_tri_context {
struct htp_ops_context * octx;
uint32_t jobs_per_thread;
uint32_t total_jobs;
uint32_t job_start;
uint32_t k_chunks;
uint32_t col_block;
struct htp_ops_context * octx;
const struct htp_solve_tri_kernel_params * kparams;
uint32_t jobs_per_thread;
uint32_t total_jobs;
uint32_t job_start;
uint32_t k_chunks;
uint32_t col_block;
};
static inline void solve_tri_row_scalar(const float * A_row,
@@ -80,6 +82,7 @@ static inline void solve_tri_row_hvx(const float * A_row,
static void solve_tri_batch_thread_f32(unsigned int nth, unsigned int ith, void * data) {
struct htp_solve_tri_context * sctx = (struct htp_solve_tri_context *) data;
struct htp_ops_context * octx = sctx->octx;
const struct htp_solve_tri_kernel_params * kparams = sctx->kparams;
const struct htp_tensor * src0 = octx->src[0]; // A
const struct htp_tensor * src1 = octx->src[1]; // B
@@ -91,7 +94,7 @@ static void solve_tri_batch_thread_f32(unsigned int nth, unsigned int ith, void
const uint32_t ne02 = src0->ne[2];
const uint32_t col_block = VLEN_FP32;
const uint32_t k_full = (k / col_block) * col_block;
const uint32_t k_full = k & ~(col_block - 1);
const uint32_t start_batch = sctx->job_start + sctx->jobs_per_thread * ith;
const uint32_t end_batch = MIN(start_batch + sctx->jobs_per_thread, sctx->job_start + sctx->total_jobs);
@@ -100,7 +103,7 @@ static void solve_tri_batch_thread_f32(unsigned int nth, unsigned int ith, void
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) start_batch);
for (uint32_t batch = start_batch; batch < end_batch; ++batch) {
const uint32_t i03 = batch / ne02;
const uint32_t i03 = fastdiv(batch, &kparams->div_ne02);
const uint32_t i02 = batch - i03 * ne02;
const float * A_batch =
@@ -141,6 +144,7 @@ static void solve_tri_batch_thread_f32(unsigned int nth, unsigned int ith, void
static void solve_tri_chunk_thread_f32(unsigned int nth, unsigned int ith, void * data) {
struct htp_solve_tri_context * sctx = (struct htp_solve_tri_context *) data;
struct htp_ops_context * octx = sctx->octx;
const struct htp_solve_tri_kernel_params * kparams = sctx->kparams;
const struct htp_tensor * src0 = octx->src[0]; // A
const struct htp_tensor * src1 = octx->src[1]; // B
@@ -158,10 +162,10 @@ static void solve_tri_chunk_thread_f32(unsigned int nth, unsigned int ith, void
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) start_job);
for (uint32_t job = start_job; job < end_job; ++job) {
const uint32_t batch = job / sctx->k_chunks;
const uint32_t batch = fastdiv(job, &kparams->div_k_chunks);
const uint32_t chunk = job - batch * sctx->k_chunks;
const uint32_t i03 = batch / ne02;
const uint32_t i03 = fastdiv(batch, &kparams->div_ne02);
const uint32_t i02 = batch - i03 * ne02;
const float * A_batch =
@@ -198,36 +202,17 @@ int op_solve_tri(struct htp_ops_context * octx) {
const struct htp_tensor * src0 = octx->src[0]; // A
const struct htp_tensor * src1 = octx->src[1]; // B
const struct htp_tensor * dst = octx->dst; // X
if (src0->type != HTP_TYPE_F32 || src1->type != HTP_TYPE_F32 || dst->type != HTP_TYPE_F32) {
return HTP_STATUS_NO_SUPPORT;
}
// left=true, lower=true, uni=false only
if (src0->ne[0] != src0->ne[1]) {
return HTP_STATUS_INVAL_PARAMS;
}
if (src0->ne[1] != src1->ne[1]) {
return HTP_STATUS_INVAL_PARAMS;
}
if (src0->ne[2] != src1->ne[2] || src0->ne[3] != src1->ne[3]) {
return HTP_STATUS_INVAL_PARAMS;
}
if (dst->ne[0] != src1->ne[0] || dst->ne[1] != src1->ne[1] || dst->ne[2] != src1->ne[2] ||
dst->ne[3] != src1->ne[3]) {
return HTP_STATUS_INVAL_PARAMS;
}
const struct htp_solve_tri_kernel_params * kparams =
(const struct htp_solve_tri_kernel_params *) octx->kernel_params;
if (htp_tensor_is_extended(src0) || htp_tensor_is_extended(src1) || htp_tensor_is_extended(dst)) {
return HTP_STATUS_NO_SUPPORT;
}
const uint32_t k = src1->ne[0];
const uint32_t col_block = VLEN_FP32;
const uint32_t k_chunks = (k + col_block - 1) / col_block;
const uint32_t total_batches = src0->ne[2] * src0->ne[3];
const bool batched = total_batches >= (uint32_t) octx->n_threads;
const uint32_t col_block = kparams->col_block;
const uint32_t k_chunks = kparams->k_chunks;
const uint32_t total_batches = kparams->total_batches;
const bool batched = (kparams->batched != 0);
FARF(HIGH, "solve-tri: (%ux%ux%ux%u) x (%ux%ux%ux%u) -> (%ux%ux%ux%u) : batched %d\n",
src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3],
@@ -239,9 +224,7 @@ int op_solve_tri(struct htp_ops_context * octx) {
uint32_t njobs = total_batches;
if (octx->ctx->mdev.count > 1) {
const uint32_t batch_size = dst->nb[2];
const uint32_t batches_per_chunk = (batch_size > 0) ? (HEX_L2_LINE_SIZE / hex_gcd_u32(batch_size, HEX_L2_LINE_SIZE)) : 1;
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(total_batches, htp_tensor_mdev_data_aligned(dst) ? batches_per_chunk : 0, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
const struct htp_tensor_mdev_range range = htp_tensor_mdev_partition(total_batches, htp_tensor_mdev_data_aligned(dst) ? kparams->batches_per_chunk : 0, octx->ctx->mdev.idx, octx->ctx->mdev.count, &octx->ctx->mdev.count_div);
job_start = range.start;
njobs = range.count;
}
@@ -250,11 +233,15 @@ int op_solve_tri(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
// Batch-level parallelism
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, njobs))) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t n_threads = octx->n_threads;
struct htp_solve_tri_context sctx = {
.octx = octx,
.kparams = kparams,
.jobs_per_thread = fastdiv(njobs + n_threads - 1, &octx->n_threads_div),
.total_jobs = njobs,
.job_start = job_start,
@@ -264,8 +251,7 @@ int op_solve_tri(struct htp_ops_context * octx) {
work_queue_run(octx->ctx->work_queue, solve_tri_batch_thread_f32, &sctx, n_threads);
} else {
// Chunk-level parallelism
const uint32_t total_jobs = total_batches * k_chunks;
const uint32_t total_jobs = kparams->total_jobs;
uint32_t job_start = 0;
uint32_t njobs = total_jobs;
@@ -281,10 +267,15 @@ int op_solve_tri(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
if (!htp_ops_context_set_n_threads(octx, MIN(kparams->n_threads, njobs))) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t n_threads = octx->n_threads;
struct htp_solve_tri_context sctx = {
.octx = octx,
.kparams = kparams,
.jobs_per_thread = fastdiv(njobs + n_threads - 1, &octx->n_threads_div),
.total_jobs = njobs,
.job_start = job_start,
+26
View File
@@ -0,0 +1,26 @@
#ifndef HTP_SOLVE_TRI_OPS_H
#define HTP_SOLVE_TRI_OPS_H
#include "hex-fastdiv.h"
#include <stdint.h>
struct htp_solve_tri_kernel_params {
uint32_t n_threads;
uint32_t total_batches;
uint32_t total_jobs;
uint32_t k_chunks;
uint32_t col_block;
uint32_t batched;
uint32_t batches_per_chunk;
struct fastdiv_values div_ne02;
struct fastdiv_values div_k_chunks;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_solve_tri_kernel_params) <= 128, "htp_solve_tri_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_solve_tri_kernel_params) <= 128, "htp_solve_tri_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_SOLVE_TRI_OPS_H
+47 -38
View File
@@ -135,6 +135,13 @@ static inline void hvx_ssm_conv_unpack_to_T(const float * raw, float * T, uint32
}
}
static __attribute__((noinline)) void hvx_ssm_conv_silu_vtcm(float * restrict buf, uint32_t n_vecs) {
HVX_Vector * restrict vbuf = (HVX_Vector *) buf;
for (uint32_t i = 0; i < n_vecs; ++i) {
vbuf[i] = hvx_vec_silu_f32(vbuf[i]);
}
}
// Decode dot product specialization for d_conv == 4: multiply in the raw channel-major layout,
// then deinterleave the products so each vector holds one tap of 32 channels, and sum.
// Keeps both operands in DMA layout - no transpose, no scratch.
@@ -189,9 +196,10 @@ static void ssm_conv_thread_f32_decode(unsigned int nth, unsigned int ith, void
dma_queue * dma_q = octx->ctx->dma[ith];
const uint32_t d_conv = kparams->d_conv;
const uint32_t d_inner = kparams->d_inner;
const uint32_t n_s = kparams->n_s;
const uint32_t d_conv = kparams->d_conv;
const uint32_t d_inner = kparams->d_inner;
const uint32_t n_s = kparams->n_s;
const bool apply_silu = kparams->silu != 0;
const uint32_t dr = scctx->nrows_per_thread;
const uint32_t ir0 = scctx->row_start + dr * ith;
@@ -232,7 +240,7 @@ static void ssm_conv_thread_f32_decode(unsigned int nth, unsigned int ith, void
// raw_dot keeps both operands in the DMA layout, so src1 needs no prep pass
const bool raw_dot = (d_conv == 4) && (d_inner_per_thread % VLEN_FP32 == 0);
const uint32_t n_tiles = (d_inner_per_thread + d_inner_tile - 1) / d_inner_tile;
const uint32_t n_tiles = fastdiv(d_inner_per_thread + d_inner_tile - 1, &kparams->div_d_inner_tile);
const uint32_t n_chunks = n_s * n_tiles;
const size_t row_bytes = d_conv * sizeof(float);
@@ -295,21 +303,18 @@ static void ssm_conv_thread_f32_decode(unsigned int nth, unsigned int ith, void
hvx_ssm_conv_unpack_to_T(src0_tile_raw[c & 1], src0_T, tile_n, tile_stride, d_conv);
for (uint32_t cb = 0; cb < tile_n; cb += VLEN_FP32) {
const uint32_t cb_n = MIN(VLEN_FP32, tile_n - cb);
HVX_Vector acc = hvx_vec_splat_f32(0.0f);
for (uint32_t j = 0; j < d_conv; ++j) {
HVX_Vector x = *(const HVX_Vector *)(src0_T + j * tile_stride + cb);
HVX_Vector w = *(const HVX_Vector *)(src1_T + j * d_inner_stride + tile_off + cb);
acc = Q6_Vqf32_vadd_Vqf32Vqf32(acc, Q6_Vqf32_vmpy_VsfVsf(x, w));
}
HVX_Vector y = Q6_Vsf_equals_Vqf32(acc);
if (cb_n == VLEN_FP32) {
*(HVX_Vector *)(out + cb) = y;
} else {
hvx_vec_store_u(out + cb, cb_n * sizeof(float), y);
}
*(HVX_Vector *)(out + cb) = Q6_Vsf_equals_Vqf32(acc);
}
}
if (apply_silu) {
hvx_ssm_conv_silu_vtcm(out, hex_round_up(tile_n, VLEN_FP32) / VLEN_FP32);
}
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) i3);
const dma_addr_t dst_ddr = dst->data + i3 * dst_stride_seq_bytes + (ir0 + tile_off) * sizeof(float);
@@ -352,11 +357,12 @@ static void ssm_conv_thread_f32_prefill(unsigned int nth, unsigned int ith, void
dma_queue * dma_q = octx->ctx->dma[ith];
const uint32_t d_conv = kparams->d_conv;
const uint32_t d_inner = kparams->d_inner;
const uint32_t n_t = kparams->n_t;
const uint32_t n_s = kparams->n_s;
const uint32_t ncs = src0->ne[0];
const uint32_t d_conv = kparams->d_conv;
const uint32_t d_inner = kparams->d_inner;
const uint32_t n_t = kparams->n_t;
const uint32_t n_s = kparams->n_s;
const uint32_t ncs = src0->ne[0];
const bool apply_silu = kparams->silu != 0;
const uint32_t dr = scctx->nrows_per_thread;
const uint32_t ir0 = scctx->row_start + dr * ith;
@@ -397,7 +403,7 @@ static void ssm_conv_thread_f32_prefill(unsigned int nth, unsigned int ith, void
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
const uint32_t n_tiles = (d_inner_per_thread + d_inner_tile - 1) / d_inner_tile;
const uint32_t n_tiles = fastdiv(d_inner_per_thread + d_inner_tile - 1, &kparams->div_d_inner_tile);
const uint32_t n_chunks = n_s * n_tiles;
const size_t row_bytes = ncs * sizeof(float);
@@ -513,10 +519,14 @@ static void ssm_conv_thread_f32_prefill(unsigned int nth, unsigned int ith, void
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) tile_off);
}
if (apply_silu) {
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) tile_off);
hvx_ssm_conv_silu_vtcm(out, n_t * (dst_tile_stride / C_TILE));
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) tile_off);
}
// Writeback dst_tile VTCM -> DDR via 2D DMA
dma_queue_push(dma_q,
dma_make_data(dst->data + i3 * dst_stride_seq_bytes + (ir0 + tile_off) * sizeof(float),
(uint8_t *) out),
dma_queue_push(dma_q, dma_make_data(dst->data + i3 * dst_stride_seq_bytes + (ir0 + tile_off) * sizeof(float), (uint8_t *) out),
dst_stride_token_bytes, dst_tile_stride * sizeof(float), tile_n * sizeof(float), n_t);
if (c + 2 < n_chunks) {
@@ -547,13 +557,8 @@ int op_ssm_conv_f32(struct htp_ops_context * octx) {
const struct htp_tensor * src1 = octx->src[1];
const struct htp_tensor * dst = octx->dst;
if (src0->type != HTP_TYPE_F32 || src1->type != HTP_TYPE_F32 || dst->type != HTP_TYPE_F32) {
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_ssm_conv_kernel_params * kparams = (const struct htp_ssm_conv_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
@@ -582,26 +587,30 @@ int op_ssm_conv_f32(struct htp_ops_context * octx) {
return HTP_STATUS_VTCM_TOO_SMALL;
}
const uint32_t n_threads = octx->n_threads;
const uint32_t n_threads = octx->n_threads;
const uint32_t raw_rpt = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
const uint32_t d_inner_per_thread = hex_round_up(raw_rpt, VLEN_FP32);
octx->src0_spad.size_per_thread = kparams->vtcm_src0_size_per_thread;
octx->src1_spad.size_per_thread = kparams->vtcm_src1_size_per_thread;
octx->dst_spad.size_per_thread = kparams->vtcm_dst_size_per_thread;
struct htp_ssm_conv_vtcm_layout L;
htp_ssm_conv_vtcm_layout_build(&L, d_inner_per_thread, kparams->d_conv, kparams->n_t, kparams->d_inner_tile, n_threads);
octx->src0_spad.size = kparams->vtcm_src0_size;
octx->src1_spad.size = kparams->vtcm_src1_size;
octx->dst_spad.size = kparams->vtcm_dst_size;
uint8_t * const base = (uint8_t *) octx->ctx->vtcm_base;
octx->src0_spad.data = octx->ctx->vtcm_base;
octx->src1_spad.data = octx->src0_spad.data + octx->src0_spad.size;
octx->dst_spad.data = octx->src1_spad.data + octx->src1_spad.size;
octx->src0_spad.size_per_thread = L.src0_bytes_per_thread;
octx->src1_spad.size_per_thread = L.src1_bytes_per_thread;
octx->dst_spad.size_per_thread = L.dst_bytes_per_thread;
octx->src0_spad.size = L.src0_bytes;
octx->src1_spad.size = L.src1_bytes;
octx->dst_spad.size = L.dst_bytes;
octx->src0_spad.data = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0);
octx->src1_spad.data = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src1);
octx->dst_spad.data = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst);
octx->src0_spad.src = NULL;
octx->src1_spad.src = NULL;
octx->dst_spad.src = NULL;
const uint32_t raw_rpt = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
const uint32_t d_inner_per_thread = hex_round_up(raw_rpt, VLEN_FP32);
struct htp_ssm_conv_context scctx = {
.octx = octx,
.kparams = kparams,
+55 -7
View File
@@ -3,8 +3,10 @@
#include <stdint.h>
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-ops.h"
#include "htp-vtcm.h"
struct htp_ssm_conv_kernel_params {
uint32_t n_threads;
@@ -14,16 +16,62 @@ struct htp_ssm_conv_kernel_params {
uint32_t n_s;
uint32_t d_inner_tile;
uint32_t vtcm_src0_size_per_thread;
uint32_t vtcm_src1_size_per_thread;
uint32_t vtcm_dst_size_per_thread;
uint32_t vtcm_src0_size;
uint32_t vtcm_src1_size;
uint32_t vtcm_dst_size;
uint32_t vtcm_size;
uint32_t silu;
struct fastdiv_values div_d_inner_tile;
};
struct htp_ssm_conv_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_src1;
size_t off_dst;
size_t src0_bytes_per_thread;
size_t src1_bytes_per_thread;
size_t dst_bytes_per_thread;
size_t src0_bytes;
size_t src1_bytes;
size_t dst_bytes;
};
static inline void htp_ssm_conv_vtcm_layout_build(
struct htp_ssm_conv_vtcm_layout * L,
uint32_t d_inner_per_thread,
uint32_t d_conv,
uint32_t n_t,
uint32_t d_inner_tile,
uint32_t n_threads
) {
const size_t src1_raw_bytes = hex_round_up((size_t) d_inner_per_thread * d_conv * sizeof(float), 128) + 128;
const size_t src1_T_bytes = hex_round_up((size_t) d_conv * d_inner_per_thread * sizeof(float), 128);
L->src1_bytes_per_thread = src1_raw_bytes + src1_T_bytes;
if (n_t == 1) {
const size_t src0_tile_raw_bytes = hex_round_up((size_t) d_inner_tile * d_conv * sizeof(float), 128);
const size_t src0_T_bytes = hex_round_up((size_t) d_conv * d_inner_tile * sizeof(float), 128);
L->src0_bytes_per_thread = 2 * src0_tile_raw_bytes + src0_T_bytes;
L->dst_bytes_per_thread = 2 * hex_round_up((size_t) d_inner_tile * sizeof(float), 128);
} else {
const uint32_t ncs = d_conv - 1 + n_t;
const size_t src0_block_T = hex_round_up((size_t) ncs * 32 * sizeof(float), 128);
const size_t src0_tile_raw = hex_round_up((size_t) d_inner_tile * ncs * sizeof(float), 128);
L->src0_bytes_per_thread = 2 * src0_tile_raw + src0_block_T;
L->dst_bytes_per_thread = 2 * hex_round_up((size_t) d_inner_tile * n_t * sizeof(float), 128);
}
L->src0_bytes = L->src0_bytes_per_thread * n_threads;
L->src1_bytes = L->src1_bytes_per_thread * n_threads;
L->dst_bytes = L->dst_bytes_per_thread * n_threads;
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes);
VTCM_LAYOUT_ALLOC(off, off_src1, L->src1_bytes);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes);
L->total_bytes = off;
}
#if defined(__cplusplus)
static_assert(sizeof(struct htp_ssm_conv_kernel_params) <= 128, "htp_ssm_conv_kernel_params is too large for kernel_params blob");
#else
+30 -22
View File
@@ -18,6 +18,7 @@
#include "htp-ctx.h"
#include "htp-ops.h"
#include "htp-tensor.h"
#include "sum-rows-ops.h"
#define sum_rows_preamble \
const struct htp_tensor *src0 = octx->src[0]; \
@@ -52,7 +53,6 @@ struct sum_rows_context {
size_t dst_stride;
uint32_t rows_per_thread;
uint32_t total_rows;
bool opt_path;
};
static void sum_rows_thread_f32(unsigned int nth, unsigned int ith, void *data) {
@@ -71,7 +71,6 @@ static void sum_rows_thread_f32(unsigned int nth, unsigned int ith, void *data)
const size_t src_stride = smctx->src_stride;
const size_t dst_stride = smctx->dst_stride;
const uint32_t ne00 = smctx->ne00;
const bool opt_path = smctx->opt_path;
const float * restrict src_th = (const float *) (smctx->src_data + (start_row * src_stride));
float * restrict dst_th = (float *) (smctx->dst_data + (start_row * dst_stride));
@@ -90,11 +89,7 @@ static void sum_rows_thread_f32(unsigned int nth, unsigned int ith, void *data)
hex_l2fetch((const uint8_t *) src_local + src_stride, src_stride, src_stride, 1);
}
if (opt_path) {
*dst_local = hvx_reduce_sum_f32_a((const uint8_t *) src_local, ne00);
} else {
*dst_local = hvx_reduce_sum_f32((const uint8_t *) src_local, ne00);
}
*dst_local = hvx_reduce_sum_f32((const uint8_t *) src_local, ne00);
}
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, (uint16_t) start_row);
@@ -111,6 +106,13 @@ int op_sum_rows(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_sum_rows_kernel_params * kparams =
(const struct htp_sum_rows_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t src0_nrows = ne01 * ne02 * ne03;
const size_t dst_data_row_size = dst->ne[0] * sizeof(float);
@@ -129,14 +131,9 @@ int op_sum_rows(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
const uint32_t n_threads = octx->n_threads;
const uint32_t n_threads = octx->n_threads;
const uint32_t rows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
bool opt_path = false;
if ((0 == hex_is_aligned((void *) src0->data, VLEN)) && !(nb01 & (VLEN - 1))) {
opt_path = true;
}
struct sum_rows_context smctx = {
.octx = octx,
.src_data = (const uint8_t *) src0->data + row_start * nb01,
@@ -146,7 +143,6 @@ int op_sum_rows(struct htp_ops_context * octx) {
.dst_stride = nb1,
.rows_per_thread = rows_per_thread,
.total_rows = nrows,
.opt_path = opt_path,
};
work_queue_run(octx->ctx->work_queue, sum_rows_thread_f32, &smctx, n_threads);
@@ -197,6 +193,13 @@ int op_sum(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_sum_rows_kernel_params * kparams =
(const struct htp_sum_rows_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
if (octx->ctx->mdev.count > 1 && octx->ctx->mdev.idx > 0) {
return HTP_STATUS_OK;
}
@@ -207,9 +210,8 @@ int op_sum(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
const uint32_t n_threads = (total_elems >= 1024) ? MIN(octx->n_threads, HTP_MAX_NTHREADS) : 1;
const uint32_t raw_chunk = (total_elems + n_threads - 1) / n_threads;
const uint32_t elems_per_thread = hex_round_up(raw_chunk, 32);
const uint32_t n_threads = octx->n_threads;
const uint32_t elems_per_thread = kparams->elems_per_thread;
struct sum_context sctx = {
.octx = octx,
@@ -324,6 +326,13 @@ int op_argmax(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
const struct htp_sum_rows_kernel_params * kparams =
(const struct htp_sum_rows_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
return HTP_STATUS_INVAL_PARAMS;
}
const uint32_t ne00 = src0->ne[0];
const uint32_t src0_nrows = src0->ne[1] * src0->ne[2] * src0->ne[3];
@@ -341,9 +350,8 @@ int op_argmax(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
const uint32_t n_threads = (ne00 >= 1024) ? MIN(octx->n_threads, HTP_MAX_NTHREADS) : 1;
const uint32_t raw_chunk = (ne00 + n_threads - 1) / n_threads;
const uint32_t elems_per_thread = hex_round_up(raw_chunk, 32);
const uint32_t n_threads = octx->n_threads;
const uint32_t elems_per_thread = kparams->elems_per_thread;
struct argmax_context actx = {
.octx = octx,
@@ -389,8 +397,8 @@ int op_argmax(struct htp_ops_context * octx) {
return HTP_STATUS_OK;
}
const uint32_t n_threads = MIN(octx->n_threads, nrows);
const uint32_t rows_per_thread = (nrows + n_threads - 1) / n_threads;
const uint32_t n_threads = octx->n_threads;
const uint32_t rows_per_thread = fastdiv(nrows + n_threads - 1, &octx->n_threads_div);
struct argmax_context actx = {
.octx = octx,
+17
View File
@@ -0,0 +1,17 @@
#ifndef HTP_SUM_ROWS_OPS_H
#define HTP_SUM_ROWS_OPS_H
#include <stdint.h>
struct htp_sum_rows_kernel_params {
uint32_t n_threads;
uint32_t elems_per_thread;
};
#if defined(__cplusplus)
static_assert(sizeof(struct htp_sum_rows_kernel_params) <= 128, "htp_sum_rows_kernel_params is too large for kernel_params blob");
#else
_Static_assert(sizeof(struct htp_sum_rows_kernel_params) <= 128, "htp_sum_rows_kernel_params is too large for kernel_params blob");
#endif
#endif // HTP_SUM_ROWS_OPS_H
+105 -185
View File
@@ -109,18 +109,17 @@ static inline size_t unary_row_offset(uint32_t ir,
return i1 * nb1 + i2 * nb2 + i3 * nb3;
}
// Safe DMA block size from row `ir`: clamp to the tighter dim-1 slice
// boundary of src and dst so the nb1 stride stays valid for all rows.
// Safe DMA block size from row `ir`: clamp to the dim-1 slice boundary
// when non-contiguous so the nb1 stride stays valid for all rows.
static inline uint32_t unary_block_size(uint32_t ir,
uint32_t end_row,
uint32_t block,
bool src_contig,
bool dst_contig,
bool contig,
uint32_t ne1,
const struct fastdiv_values * div_ne1) {
uint32_t limit = MIN(block, end_row - ir);
if (!src_contig || !dst_contig) {
if (!contig) {
const uint32_t slice_end = (fastdiv(ir, div_ne1) + 1) * ne1;
limit = MIN(limit, slice_end - ir);
}
@@ -213,13 +212,15 @@ static void rms_norm_f32(const void * restrict src,
const struct htp_unary_context * uctx) {
htp_unary_op_preamble;
float epsilon = 0.f;
memcpy(&epsilon, op_params, sizeof(float));
float scale = 0.f;
memcpy(&epsilon, &op_params[0], sizeof(float));
memcpy(&scale, &op_params[1], sizeof(float));
for (uint32_t ir = 0; ir < num_rows; ir++) {
const uint8_t * restrict src_local = (const uint8_t *)src + (ir * src0_row_size_aligned);
uint8_t * restrict dst_local = (uint8_t *)dst + (ir * dst_row_size_aligned);
hvx_fast_rms_norm_f32((const uint8_t *) src_local, (uint8_t *) dst_local, ne0, epsilon);
hvx_fast_rms_norm_f32((const uint8_t *) src_local, (uint8_t *) dst_local, ne0, epsilon, scale);
}
}
@@ -230,14 +231,16 @@ static void rms_norm_mul_f32(const void * restrict src,
const struct htp_unary_context * uctx) {
htp_unary_op_preamble;
float epsilon = 0.f;
memcpy(&epsilon, op_params, sizeof(float));
float scale = 0.f;
memcpy(&epsilon, &op_params[0], sizeof(float));
memcpy(&scale, &op_params[1], sizeof(float));
for (uint32_t ir = 0; ir < num_rows; ir++) {
const uint8_t * restrict src_local = (const uint8_t *)src + (ir * src0_row_size_aligned);
const uint8_t * restrict w_local = (const uint8_t *)weight + (uctx->broadcast_weight ? 0 : ir * uctx->src1_row_size_aligned);
uint8_t * restrict dst_local = (uint8_t *)dst + (ir * dst_row_size_aligned);
hvx_fast_rms_norm_mul_f32(src_local, w_local, dst_local, ne0, epsilon);
hvx_fast_rms_norm_mul_f32(src_local, w_local, dst_local, ne0, epsilon, scale);
}
}
@@ -617,10 +620,11 @@ static void tri_f32(const void * restrict src,
const uint32_t nloe = ne0 % VLEN_FP32;
const uint32_t ne01 = uctx->octx->src[0]->ne[1];
const struct fastdiv_values * div_ne01 = &uctx->kparams->div_ne01;
for (uint32_t b = 0; b < num_rows; b++) {
const uint32_t abs_row = ir + b;
const uint32_t i01 = abs_row % ne01;
const uint32_t i01 = fastmodulo(abs_row, ne01, div_ne01);
const HVX_Vector * restrict v_src = (const HVX_Vector *) ((const uint8_t *) src + b * src0_row_size_aligned);
HVX_Vector * restrict v_dst = (HVX_Vector *) ((uint8_t *) dst + b * dst_row_size_aligned);
@@ -1163,35 +1167,23 @@ static void unary_thread_row_block(unsigned int nth, unsigned int ith, void * da
const size_t src0_vtcm_half_size = uctx->src0_vtcm_half_size;
const size_t dst_vtcm_half_size = uctx->dst_vtcm_half_size;
const bool src0_contig = (nb02 == (size_t)ne01 * nb01) &&
(nb03 == (size_t)ne02 * nb02);
const bool dst_contig = (nb2 == (size_t)ne1 * nb1) &&
(nb3 == (size_t)ne2 * nb2);
const bool src0_contig = uctx->kparams->src0_contig;
const uint32_t BLOCK = uctx->block;
const struct fastdiv_values * div_ne01 = &uctx->kparams->div_ne01;
const struct fastdiv_values * div_ne02 = &uctx->kparams->div_ne02;
const struct fastdiv_values * div_ne012 = &uctx->kparams->div_ne012;
const uint32_t src0_max_block = src0_contig ? uctx->block : MIN((uint32_t)uctx->block, ne01);
const uint32_t dst_max_block = dst_contig ? uctx->block : MIN((uint32_t)uctx->block, ne1);
const uint32_t BLOCK = MIN(src0_max_block, dst_max_block);
if (BLOCK == 0) {
FARF(ERROR, "unary-row-block : current VTCM reservation %zu is too small, needed at least %zu\n",
uctx->vtcm_src0_size_per_thread, src0_row_size_aligned);
return;
}
dma_queue * dma_q = octx->ctx->dma[ith];
for (uint32_t ir = src0_start_row, vtcm_idx = 0; ir < src0_end_row && vtcm_idx < 2; vtcm_idx++) {
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, src0_contig, dst_contig,
ne01, div_ne01);
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, src0_contig, ne01, div_ne01);
dma_queue_push(dma_q,
dma_make_data(data_dst, dst_vtcm_data + (vtcm_idx * dst_vtcm_half_size)),
nb1, dst_row_size_aligned, dst_data_row_size, 0);
const size_t src0_off = src0_contig ? (ir * nb01) :
const size_t src0_off = src0_contig ? ((size_t) ir * nb01) :
unary_row_offset(ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03);
dma_queue_push(dma_q,
dma_make_data(src0_vtcm_data + (vtcm_idx * src0_vtcm_half_size), data_src + src0_off),
@@ -1203,8 +1195,7 @@ static void unary_thread_row_block(unsigned int nth, unsigned int ith, void * da
unary_compute_fn_t compute = (unary_compute_fn_t) uctx->compute;
for (uint32_t ir = src0_start_row; ir < src0_end_row; ) {
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, src0_contig, dst_contig,
ne01, div_ne01);
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, src0_contig, ne01, div_ne01);
void * dst_vtcm = (void *) (uintptr_t) dma_queue_pop(dma_q).src;
void * src0_vtcm = (void *) (uintptr_t) dma_queue_pop(dma_q).dst;
@@ -1213,8 +1204,7 @@ static void unary_thread_row_block(unsigned int nth, unsigned int ith, void * da
compute(src0_vtcm, dst_vtcm, block_size, uctx);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, ir);
const size_t dst_off = dst_contig ? (ir * nb1) :
unary_row_offset(ir, ne1, ne2, div_ne01, div_ne02, div_ne012, nb1, nb2, nb3);
const size_t dst_off = (size_t) ir * nb1;
dma_queue_push(dma_q,
dma_make_data(data_dst + dst_off, dst_vtcm),
nb1, dst_row_size_aligned, dst_data_row_size, block_size);
@@ -1222,12 +1212,12 @@ static void unary_thread_row_block(unsigned int nth, unsigned int ith, void * da
const uint32_t next_ir = ir + block_size;
if (next_ir < src0_end_row) {
const uint32_t next_block_size = unary_block_size(next_ir, src0_end_row, BLOCK, src0_contig,
dst_contig, ne01, div_ne01);
ne01, div_ne01);
const uint32_t pref_ir = next_ir + next_block_size;
if (pref_ir < src0_end_row) {
const uint32_t pref_block_size = unary_block_size(pref_ir, src0_end_row, BLOCK, src0_contig,
dst_contig, ne01, div_ne01);
const size_t src0_pref_off = src0_contig ? (pref_ir * nb01) :
ne01, div_ne01);
const size_t src0_pref_off = src0_contig ? ((size_t) pref_ir * nb01) :
unary_row_offset(pref_ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03);
dma_queue_push(dma_q,
dma_make_data(src0_vtcm, data_src + src0_pref_off),
@@ -1273,10 +1263,6 @@ static void unary_thread_rms_norm_mul_f32(unsigned int nth, unsigned int ith, vo
const uint32_t nb11 = src1->nb[1];
const uint32_t nb12 = src1->nb[2];
const uint32_t nb13 = src1->nb[3];
const uint32_t nb11_bc = (src1->ne[1] > 1) ? nb11 : 0;
const uint32_t nb12_bc = (src1->ne[2] > 1) ? nb12 : 0;
const uint32_t nb13_bc = (src1->ne[3] > 1) ? nb13 : 0;
const bool src1_contig = ((nb12 == (size_t)ne01 * nb11) && (nb13 == (size_t)ne02 * nb12));
uint8_t * src0_vtcm_data = uctx->vtcm_src0 + (ith * uctx->vtcm_src0_size_per_thread);
uint8_t * src1_vtcm_data = uctx->vtcm_src1 ? (uctx->vtcm_src1 + (ith * uctx->vtcm_src1_size_per_thread)) : NULL;
@@ -1286,28 +1272,15 @@ static void unary_thread_rms_norm_mul_f32(unsigned int nth, unsigned int ith, vo
const size_t src1_vtcm_half_size = uctx->src1_vtcm_half_size;
const size_t dst_vtcm_half_size = uctx->dst_vtcm_half_size;
const bool src0_contig = (nb02 == (size_t)ne01 * nb01) &&
(nb03 == (size_t)ne02 * nb02);
const bool dst_contig = (nb2 == (size_t)ne1 * nb1) &&
(nb3 == (size_t)ne2 * nb2);
const bool src0_contig = uctx->kparams->src0_contig;
const bool src1_contig = uctx->kparams->src1_contig;
const bool block_contig = src0_contig && src1_contig;
const uint32_t BLOCK = uctx->block;
const struct fastdiv_values * div_ne01 = &uctx->kparams->div_ne01;
const struct fastdiv_values * div_ne02 = &uctx->kparams->div_ne02;
const struct fastdiv_values * div_ne012 = &uctx->kparams->div_ne012;
const bool src1_needs_row_clip = !uctx->broadcast_weight && !src1_contig;
const bool block_src0_contig = src0_contig && !src1_needs_row_clip;
const bool block_dst_contig = dst_contig && !src1_needs_row_clip;
const uint32_t src0_max_block = block_src0_contig ? uctx->block : MIN((uint32_t)uctx->block, ne01);
const uint32_t dst_max_block = block_dst_contig ? uctx->block : MIN((uint32_t)uctx->block, ne1);
const uint32_t BLOCK = MIN(src0_max_block, dst_max_block);
if (BLOCK == 0) {
FARF(ERROR, "unary-rms-norm-mul : current VTCM reservation %zu is too small, needed at least %zu\n",
uctx->vtcm_src0_size_per_thread, src0_row_size_aligned);
return;
}
dma_queue * dma_q = octx->ctx->dma[ith];
if (uctx->broadcast_weight) {
@@ -1317,22 +1290,21 @@ static void unary_thread_rms_norm_mul_f32(unsigned int nth, unsigned int ith, vo
}
for (uint32_t ir = src0_start_row, vtcm_idx = 0; ir < src0_end_row && vtcm_idx < 2; vtcm_idx++) {
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, block_src0_contig, block_dst_contig,
ne01, div_ne01);
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, block_contig, ne01, div_ne01);
dma_queue_push(dma_q,
dma_make_data(data_dst, dst_vtcm_data + (vtcm_idx * dst_vtcm_half_size)),
nb1, dst_row_size_aligned, dst_data_row_size, 0);
const size_t src0_off = src0_contig ? (ir * nb01) :
const size_t src0_off = src0_contig ? ((size_t) ir * nb01) :
unary_row_offset(ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03);
dma_queue_push(dma_q,
dma_make_data(src0_vtcm_data + (vtcm_idx * src0_vtcm_half_size), data_src + src0_off),
src0_row_size_aligned, nb01, src0_data_row_size, block_size);
if (!uctx->broadcast_weight) {
const size_t src1_off = src1_contig ? (ir * nb11) :
unary_row_offset(ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb11_bc, nb12_bc, nb13_bc);
const size_t src1_off = src1_contig ? ((size_t) ir * nb11) :
unary_row_offset(ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb11, nb12, nb13);
dma_queue_push(dma_q,
dma_make_data(src1_vtcm_data + (vtcm_idx * src1_vtcm_half_size), data_src1 + src1_off),
uctx->src1_row_size_aligned, nb11, uctx->src1_data_row_size, block_size);
@@ -1344,8 +1316,7 @@ static void unary_thread_rms_norm_mul_f32(unsigned int nth, unsigned int ith, vo
unary_rms_norm_mul_compute_fn_t compute = (unary_rms_norm_mul_compute_fn_t) uctx->compute;
for (uint32_t ir = src0_start_row; ir < src0_end_row; ) {
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, block_src0_contig, block_dst_contig,
ne01, div_ne01);
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, block_contig, ne01, div_ne01);
void * dst_vtcm = (void *) (uintptr_t) dma_queue_pop(dma_q).src;
void * src0_vtcm = (void *) (uintptr_t) dma_queue_pop(dma_q).dst;
@@ -1359,30 +1330,28 @@ static void unary_thread_rms_norm_mul_f32(unsigned int nth, unsigned int ith, vo
compute(src0_vtcm, w, dst_vtcm, block_size, uctx);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, ir);
const size_t dst_off = dst_contig ? (ir * nb1) :
unary_row_offset(ir, ne1, ne2, div_ne01, div_ne02, div_ne012, nb1, nb2, nb3);
const size_t dst_off = (size_t) ir * nb1;
dma_queue_push(dma_q,
dma_make_data(data_dst + dst_off, dst_vtcm),
nb1, dst_row_size_aligned, dst_data_row_size, block_size);
const uint32_t next_ir = ir + block_size;
if (next_ir < src0_end_row) {
const uint32_t next_block_size = unary_block_size(next_ir, src0_end_row, BLOCK, block_src0_contig,
block_dst_contig, ne01, div_ne01);
const uint32_t next_block_size = unary_block_size(next_ir, src0_end_row, BLOCK, block_contig,
ne01, div_ne01);
const uint32_t pref_ir = next_ir + next_block_size;
if (pref_ir < src0_end_row) {
const uint32_t pref_block_size = unary_block_size(pref_ir, src0_end_row, BLOCK, block_src0_contig,
block_dst_contig, ne01, div_ne01);
const size_t src0_pref_off = src0_contig ? (pref_ir * nb01) :
const uint32_t pref_block_size = unary_block_size(pref_ir, src0_end_row, BLOCK, block_contig,
ne01, div_ne01);
const size_t src0_pref_off = src0_contig ? ((size_t) pref_ir * nb01) :
unary_row_offset(pref_ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03);
dma_queue_push(dma_q,
dma_make_data(src0_vtcm, data_src + src0_pref_off),
src0_row_size_aligned, nb01, src0_data_row_size, pref_block_size);
if (!uctx->broadcast_weight) {
const size_t src1_pref_off = src1_contig ? (pref_ir * nb11) :
unary_row_offset(pref_ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb11_bc, nb12_bc,
nb13_bc);
const size_t src1_pref_off = src1_contig ? ((size_t) pref_ir * nb11) :
unary_row_offset(pref_ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb11, nb12, nb13);
dma_queue_push(dma_q,
dma_make_data(src1_vtcm, data_src1 + src1_pref_off),
uctx->src1_row_size_aligned, nb11, uctx->src1_data_row_size, pref_block_size);
@@ -1428,37 +1397,18 @@ static void unary_thread_tri_f32(unsigned int nth, unsigned int ith, void * data
const size_t src0_vtcm_half_size = uctx->src0_vtcm_half_size;
const size_t dst_vtcm_half_size = uctx->dst_vtcm_half_size;
const bool src0_contig = (nb02 == (size_t)ne01 * nb01) &&
(nb03 == (size_t)ne02 * nb02);
const bool dst_contig = (nb2 == (size_t)ne1 * nb1) &&
(nb3 == (size_t)ne2 * nb2);
const struct fastdiv_values * div_ne01 = &uctx->kparams->div_ne01;
const struct fastdiv_values * div_ne02 = &uctx->kparams->div_ne02;
const struct fastdiv_values * div_ne012 = &uctx->kparams->div_ne012;
const uint32_t src0_max_block = src0_contig ? uctx->block : MIN((uint32_t)uctx->block, ne01);
const uint32_t dst_max_block = dst_contig ? uctx->block : MIN((uint32_t)uctx->block, ne1);
const uint32_t BLOCK = MIN(src0_max_block, dst_max_block);
if (BLOCK == 0) {
FARF(ERROR, "unary-tri : current VTCM reservation %zu is too small, needed at least %zu\n",
uctx->vtcm_src0_size_per_thread, src0_row_size_aligned);
return;
}
const uint32_t BLOCK = uctx->block;
dma_queue * dma_q = octx->ctx->dma[ith];
for (uint32_t ir = src0_start_row, vtcm_idx = 0; ir < src0_end_row && vtcm_idx < 2; vtcm_idx++) {
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, src0_contig, dst_contig,
ne01, div_ne01);
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir);
dma_queue_push(dma_q,
dma_make_data(data_dst, dst_vtcm_data + (vtcm_idx * dst_vtcm_half_size)),
nb1, dst_row_size_aligned, dst_data_row_size, 0);
const size_t src0_off = src0_contig ? (ir * nb01) :
unary_row_offset(ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03);
const size_t src0_off = (size_t) ir * nb01;
dma_queue_push(dma_q,
dma_make_data(src0_vtcm_data + (vtcm_idx * src0_vtcm_half_size), data_src + src0_off),
src0_row_size_aligned, nb01, src0_data_row_size, block_size);
@@ -1469,8 +1419,7 @@ static void unary_thread_tri_f32(unsigned int nth, unsigned int ith, void * data
unary_tri_compute_fn_t compute = (unary_tri_compute_fn_t) uctx->compute;
for (uint32_t ir = src0_start_row; ir < src0_end_row; ) {
const uint32_t block_size = unary_block_size(ir, src0_end_row, BLOCK, src0_contig, dst_contig,
ne01, div_ne01);
const uint32_t block_size = MIN(BLOCK, src0_end_row - ir);
void * dst_vtcm = (void *) (uintptr_t) dma_queue_pop(dma_q).src;
void * src0_vtcm = (void *) (uintptr_t) dma_queue_pop(dma_q).dst;
@@ -1479,22 +1428,18 @@ static void unary_thread_tri_f32(unsigned int nth, unsigned int ith, void * data
compute(src0_vtcm, dst_vtcm, block_size, ir, uctx);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, ir);
const size_t dst_off = dst_contig ? (ir * nb1) :
unary_row_offset(ir, ne1, ne2, div_ne01, div_ne02, div_ne012, nb1, nb2, nb3);
const size_t dst_off = (size_t) ir * nb1;
dma_queue_push(dma_q,
dma_make_data(data_dst + dst_off, dst_vtcm),
nb1, dst_row_size_aligned, dst_data_row_size, block_size);
const uint32_t next_ir = ir + block_size;
if (next_ir < src0_end_row) {
const uint32_t next_block_size = unary_block_size(next_ir, src0_end_row, BLOCK, src0_contig,
dst_contig, ne01, div_ne01);
const uint32_t next_block_size = MIN(BLOCK, src0_end_row - next_ir);
const uint32_t pref_ir = next_ir + next_block_size;
if (pref_ir < src0_end_row) {
const uint32_t pref_block_size = unary_block_size(pref_ir, src0_end_row, BLOCK, src0_contig,
dst_contig, ne01, div_ne01);
const size_t src0_pref_off = src0_contig ? (pref_ir * nb01) :
unary_row_offset(pref_ir, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03);
const uint32_t pref_block_size = MIN(BLOCK, src0_end_row - pref_ir);
const size_t src0_pref_off = (size_t) pref_ir * nb01;
dma_queue_push(dma_q,
dma_make_data(src0_vtcm, data_src + src0_pref_off),
src0_row_size_aligned, nb01, src0_data_row_size, pref_block_size);
@@ -1544,21 +1489,17 @@ static void unary_thread_tiled(unsigned int nth, unsigned int ith, void * data)
const struct fastdiv_values * div_ne012 = &uctx->kparams->div_ne012;
const struct fastdiv_values * div_tpr = &uctx->kparams->div_tpr;
const uint32_t tiles_per_row = (ne0 + col_tile - 1) / col_tile;
const bool src0_contig = (nb02 == (size_t)ne01 * nb01) &&
(nb03 == (size_t)ne02 * nb02);
const bool dst_contig = (nb2 == (size_t)ne1 * nb1) &&
(nb3 == (size_t)ne2 * nb2);
const uint32_t tiles_per_row = uctx->kparams->tiles_per_row;
const bool src0_contig = uctx->kparams->src0_contig;
const uint32_t total_tiles = (src0_end_row - src0_start_row) * tiles_per_row;
for (uint32_t t = 0, vtcm_idx = 0; t < total_tiles && vtcm_idx < 2; t++, vtcm_idx++) {
const uint32_t row = src0_start_row + t / tiles_per_row;
const uint32_t col = (t % tiles_per_row) * col_tile;
const uint32_t row = src0_start_row + fastdiv(t, div_tpr);
const uint32_t col = fastmodulo(t, tiles_per_row, div_tpr) * col_tile;
const uint32_t tw = MIN(col_tile, ne0 - col);
const size_t tb = (size_t) tw * sizeof(float);
const size_t soff = (src0_contig ? (row * nb01) :
const size_t soff = (src0_contig ? ((size_t) row * nb01) :
unary_row_offset(row, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03)) +
(size_t) col * sizeof(float);
@@ -1586,9 +1527,7 @@ static void unary_thread_tiled(unsigned int nth, unsigned int ith, void * data)
compute(dst_vtcm, src_vtcm, tw, uctx);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, t);
const size_t doff = (dst_contig ? (row * nb1) :
unary_row_offset(row, ne1, ne2, div_ne01, div_ne02, div_ne012, nb1, nb2, nb3)) +
(size_t) col * sizeof(float);
const size_t doff = (size_t) row * nb1 + (size_t) col * sizeof(float);
const size_t tb = (size_t) tw * sizeof(float);
dma_queue_push(dma_q, dma_make_data(data_dst + doff, dst_vtcm), tb, tb, tb, 1);
@@ -1596,7 +1535,7 @@ static void unary_thread_tiled(unsigned int nth, unsigned int ith, void * data)
if (pt < total_tiles) {
const uint32_t ptw = MIN(col_tile, ne0 - pcol);
const size_t ptb = (size_t) ptw * sizeof(float);
const size_t psoff = (src0_contig ? (prow * nb01) :
const size_t psoff = (src0_contig ? ((size_t) prow * nb01) :
unary_row_offset(prow, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02,
nb03)) +
(size_t) pcol * sizeof(float);
@@ -1657,29 +1596,20 @@ static void unary_thread_tiled_tri_f32(unsigned int nth, unsigned int ith, void
dma_queue * dma_q = octx->ctx->dma[ith];
const struct fastdiv_values * div_ne01 = &uctx->kparams->div_ne01;
const struct fastdiv_values * div_ne02 = &uctx->kparams->div_ne02;
const struct fastdiv_values * div_ne012 = &uctx->kparams->div_ne012;
const struct fastdiv_values * div_tpr = &uctx->kparams->div_tpr;
const struct fastdiv_values * div_ne01 = &uctx->kparams->div_ne01;
const struct fastdiv_values * div_tpr = &uctx->kparams->div_tpr;
const uint32_t tiles_per_row = (ne0 + col_tile - 1) / col_tile;
const uint32_t tiles_per_row = uctx->kparams->tiles_per_row;
const int32_t tri_ttype = op_params[0];
const bool src0_contig = (nb02 == (size_t)ne01 * nb01) &&
(nb03 == (size_t)ne02 * nb02);
const bool dst_contig = (nb2 == (size_t)ne1 * nb1) &&
(nb3 == (size_t)ne2 * nb2);
const uint32_t total_tiles = (src0_end_row - src0_start_row) * tiles_per_row;
for (uint32_t t = 0, vtcm_idx = 0; t < total_tiles && vtcm_idx < 2; t++, vtcm_idx++) {
const uint32_t row = src0_start_row + t / tiles_per_row;
const uint32_t col = (t % tiles_per_row) * col_tile;
const uint32_t row = src0_start_row + fastdiv(t, div_tpr);
const uint32_t col = fastmodulo(t, tiles_per_row, div_tpr) * col_tile;
const uint32_t tw = MIN(col_tile, ne0 - col);
const size_t tb = (size_t) tw * sizeof(float);
const size_t soff = (src0_contig ? (row * nb01) :
unary_row_offset(row, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02, nb03)) +
(size_t) col * sizeof(float);
const size_t soff = (size_t) row * nb01 + (size_t) col * sizeof(float);
dma_queue_push(dma_q, dma_make_data(data_dst, dst_vtcm_data + (vtcm_idx * dst_half)), 0, 0, 0, 0);
dma_queue_push(dma_q, dma_make_data(src0_vtcm_data + (vtcm_idx * src0_half), data_src + soff), tb, tb, tb, 1);
@@ -1706,20 +1636,15 @@ static void unary_thread_tiled_tri_f32(unsigned int nth, unsigned int ith, void
compute(src_vtcm, dst_vtcm, tw, col, i01, ne0, tri_ttype);
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_COMP, t);
const size_t doff = (dst_contig ? (row * nb1) :
unary_row_offset(row, ne1, ne2, div_ne01, div_ne02, div_ne012, nb1, nb2, nb3)) +
(size_t) col * sizeof(float);
const size_t doff = (size_t) row * nb1 + (size_t) col * sizeof(float);
const size_t tb = (size_t) tw * sizeof(float);
dma_queue_push(dma_q, dma_make_data(data_dst + doff, dst_vtcm), tb, tb, tb, 1);
const uint32_t pt = t + 2;
if (pt < total_tiles) {
const uint32_t ptw = MIN(col_tile, ne0 - pcol);
const size_t ptb = (size_t) ptw * sizeof(float);
const size_t psoff = (src0_contig ? (prow * nb01) :
unary_row_offset(prow, ne01, ne02, div_ne01, div_ne02, div_ne012, nb01, nb02,
nb03)) +
(size_t) pcol * sizeof(float);
const uint32_t ptw = MIN(col_tile, ne0 - pcol);
const size_t ptb = (size_t) ptw * sizeof(float);
const size_t psoff = (size_t) prow * nb01 + (size_t) pcol * sizeof(float);
dma_queue_push(dma_q, dma_make_data(src_vtcm, data_src + psoff), ptb, ptb, ptb, 1);
}
@@ -1787,28 +1712,6 @@ static int execute_op_unary(struct htp_ops_context * octx) {
return HTP_STATUS_NO_SUPPORT;
}
// F16 only has row-block kernels for this subset of ops (see the dispatch switch
// below) - reject everything else up front, before touching kparams/VTCM.
if (is_f16) {
switch (octx->op) {
case HTP_OP_NORM:
case HTP_OP_RMS_NORM:
case HTP_OP_SCALE:
case HTP_OP_CLAMP:
case HTP_OP_SQR:
case HTP_OP_SQRT:
case HTP_OP_L2_NORM:
case HTP_OP_UNARY_ABS:
case HTP_OP_UNARY_LOG:
case HTP_OP_UNARY_STEP:
case HTP_OP_HADAMARD:
break;
default:
FARF(ERROR, "unary-%s: not supported for F16\n", op_type);
return HTP_STATUS_NO_SUPPORT;
}
}
const struct htp_unary_kernel_params * kparams = (const struct htp_unary_kernel_params *) octx->kernel_params;
if (!htp_ops_context_set_n_threads(octx, kparams->n_threads)) {
@@ -1838,15 +1741,11 @@ static int execute_op_unary(struct htp_ops_context * octx) {
const uint32_t n_threads = octx->n_threads;
const size_t src0_row_size_aligned = kparams->src0_row_size_aligned;
const size_t dst_row_size_aligned = kparams->dst_row_size_aligned;
// Always 0 for F16 - htp_unary_vtcm_layout_build() keeps F16 on the row-block path,
// Always 0 for F16 - htp_unary_solve_layout() keeps F16 on the row-block path,
// since only F32 has unary_task_f32_tiled_* kernels.
const uint32_t col_tile = kparams->col_tile;
size_t src1_data_row_size = 0;
size_t src1_row_size_aligned = kparams->src1_row_size_aligned;
bool broadcast_weight = kparams->broadcast_weight;
const struct htp_tensor * src1 = NULL;
@@ -1857,8 +1756,8 @@ static int execute_op_unary(struct htp_ops_context * octx) {
src1_data_row_size = src1->ne[0] * sizeof(float);
}
if (octx->ctx->vtcm_size < (size_t)kparams->vtcm_size) {
FARF(ERROR, "unary-%s : current VTCM reservation %zu is too small, needed %zu\n", op_type, octx->ctx->vtcm_size, (size_t)kparams->vtcm_size);
if ((!col_tile && kparams->block == 0) || octx->ctx->vtcm_size < (size_t) kparams->vtcm_size) {
FARF(ERROR, "unary-%s : current VTCM reservation %zu is too small, needed %zu\n", op_type, octx->ctx->vtcm_size, (size_t) kparams->vtcm_size);
return HTP_STATUS_VTCM_TOO_SMALL;
}
@@ -1866,9 +1765,13 @@ static int execute_op_unary(struct htp_ops_context * octx) {
octx->src1_spad.src = NULL;
octx->dst_spad.src = NULL;
FARF(HIGH, "%s: (%ux%ux%ux%u) -> (%ux%ux%ux%u) : src0-vtcm-size %u src1-vtcm-size %u dst-vtcm-size %u\n", op_type,
struct htp_unary_vtcm_layout L;
htp_unary_vtcm_layout_build(&L, octx->op, src0_data_row_size, dst_data_row_size, src1_data_row_size,
src0_elem_size, col_tile, kparams->block, broadcast_weight, kparams->n_threads);
FARF(HIGH, "%s: (%ux%ux%ux%u) -> (%ux%ux%ux%u) : src0-vtcm-size %zu src1-vtcm-size %zu dst-vtcm-size %zu\n", op_type,
src0->ne[0], src0->ne[1], src0->ne[2], src0->ne[3], dst->ne[0], dst->ne[1], dst->ne[2], dst->ne[3],
kparams->vtcm_src0_size, kparams->vtcm_src1_size, kparams->vtcm_dst_size);
L.src0_bytes * n_threads, L.src1_bytes * n_threads, L.dst_bytes * n_threads);
uint8_t * const base = (uint8_t *) octx->ctx->vtcm_base;
struct htp_unary_context uctx = {
@@ -1886,26 +1789,26 @@ static int execute_op_unary(struct htp_ops_context * octx) {
.src1_data_row_size = src1_data_row_size,
.dst_data_row_size = dst_data_row_size,
.src0_row_size_aligned = src0_row_size_aligned,
.src1_row_size_aligned = src1_row_size_aligned,
.dst_row_size_aligned = dst_row_size_aligned,
.src0_row_size_aligned = L.src0_row_size_aligned,
.src1_row_size_aligned = L.src1_row_size_aligned,
.dst_row_size_aligned = L.dst_row_size_aligned,
.src0_vtcm_half_size = kparams->vtcm_src0_size_per_thread / 2,
.src1_vtcm_half_size = (octx->op == HTP_OP_RMS_NORM_MUL) ? (kparams->vtcm_src1_size_per_thread / (broadcast_weight ? 1 : 2)) : 0,
.dst_vtcm_half_size = kparams->vtcm_dst_size_per_thread / 2,
.src0_vtcm_half_size = L.src0_bytes >> 1,
.src1_vtcm_half_size = (octx->op == HTP_OP_RMS_NORM_MUL) ? (L.src1_bytes >> (broadcast_weight ? 0 : 1)) : 0,
.dst_vtcm_half_size = L.dst_bytes >> 1,
.block = kparams->block,
.nc = src0->ne[0],
.col_tile = col_tile,
.broadcast_weight = broadcast_weight,
.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, 0),
.vtcm_src1 = VTCM_LAYOUT_PTR_OPTIONAL(uint8_t, base, kparams->vtcm_src0_size, kparams->vtcm_src1_size > 0),
.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, kparams->vtcm_src0_size + kparams->vtcm_src1_size),
.vtcm_src0 = VTCM_LAYOUT_PTR(uint8_t, base, L.off_src0),
.vtcm_src1 = VTCM_LAYOUT_PTR_OPTIONAL(uint8_t, base, L.off_src1, L.src1_bytes > 0),
.vtcm_dst = VTCM_LAYOUT_PTR(uint8_t, base, L.off_dst),
.vtcm_src0_size_per_thread = kparams->vtcm_src0_size_per_thread,
.vtcm_src1_size_per_thread = kparams->vtcm_src1_size_per_thread,
.vtcm_dst_size_per_thread = kparams->vtcm_dst_size_per_thread,
.vtcm_src0_size_per_thread = L.src0_bytes,
.vtcm_src1_size_per_thread = L.src1_bytes,
.vtcm_dst_size_per_thread = L.dst_bytes,
};
FARF(HIGH, "%s: %s mode (col_tile %u)\n", op_type, col_tile ? "tiled" : "row-block", col_tile);
@@ -2007,8 +1910,25 @@ static int execute_op_unary(struct htp_ops_context * octx) {
int op_unary(struct htp_ops_context * octx) {
switch (octx->src[0]->type) {
case HTP_TYPE_F32:
case HTP_TYPE_F16:
return execute_op_unary(octx);
case HTP_TYPE_F16: {
if (!htp_unary_is_elementwise(octx->op)) {
return execute_op_unary(octx);
}
struct htp_tensor src0_c = *octx->src[0];
struct htp_tensor dst_c = *octx->dst;
const size_t elem_size = (src0_c.type == HTP_TYPE_F16) ? sizeof(_Float16) : sizeof(float);
HTP_UNARY_COLLAPSE_DIMS(src0_c.ne, src0_c.nb, dst_c.ne, dst_c.nb, elem_size);
const struct htp_tensor * orig_src0 = octx->src[0];
const struct htp_tensor * orig_dst = octx->dst;
octx->src[0] = &src0_c;
octx->dst = &dst_c;
const int status = execute_op_unary(octx);
octx->src[0] = orig_src0;
octx->dst = orig_dst;
return status;
}
default:
return HTP_STATUS_NO_SUPPORT;
+97 -46
View File
@@ -2,29 +2,22 @@
#define HTP_UNARY_OPS_H
#include "hex-common.h"
#include "hex-fastdiv.h"
#include "htp-ops.h"
#include "htp-vtcm.h"
// Op-specific struct for precomputed unary params
struct htp_unary_kernel_params {
uint32_t n_threads;
uint32_t col_tile;
uint32_t vtcm_row_per_thread;
uint32_t block;
uint32_t broadcast_weight;
uint32_t vtcm_src0_size_per_thread;
uint32_t vtcm_src1_size_per_thread;
uint32_t vtcm_dst_size_per_thread;
uint32_t vtcm_src0_size;
uint32_t vtcm_src1_size;
uint32_t vtcm_dst_size;
uint32_t src0_row_size_aligned;
uint32_t src1_row_size_aligned;
uint32_t dst_row_size_aligned;
uint32_t src0_contig;
uint32_t src1_contig;
uint32_t vtcm_size;
uint32_t tiles_per_row;
// Fastdiv helpers
struct fastdiv_values div_ne01;
@@ -71,23 +64,105 @@ static inline bool htp_op_is_unary(uint32_t opcode) {
}
}
static inline bool htp_unary_is_elementwise(uint32_t opcode) {
switch (opcode) {
case HTP_OP_NORM:
case HTP_OP_RMS_NORM:
case HTP_OP_RMS_NORM_MUL:
case HTP_OP_L2_NORM:
case HTP_OP_HADAMARD:
case HTP_OP_TRI:
return false;
default:
return true;
}
}
#define HTP_UNARY_COLLAPSE_DIMS(src_ne, src_nb, dst_ne, dst_nb, elem_size) \
do { \
while (((src_ne)[1] > 1 || (src_ne)[2] > 1 || (src_ne)[3] > 1) && \
(size_t) (src_nb)[0] == (elem_size) && \
(size_t) (dst_nb)[0] == (elem_size) && \
(((src_ne)[1] == 1 && (dst_ne)[1] == 1) || \
((size_t) (src_nb)[1] == (size_t) (src_ne)[0] * (size_t) (src_nb)[0] && \
(size_t) (dst_nb)[1] == (size_t) (dst_ne)[0] * (size_t) (dst_nb)[0] && \
((src_ne)[0] == 1 || \
(uint64_t) (src_ne)[0] * (uint64_t) (src_ne)[1] * (elem_size) <= 128)))) { \
(src_ne)[0] *= (src_ne)[1]; \
(src_ne)[1] = (src_ne)[2]; \
(src_ne)[2] = (src_ne)[3]; \
(src_ne)[3] = 1; \
(dst_ne)[0] *= (dst_ne)[1]; \
(dst_ne)[1] = (dst_ne)[2]; \
(dst_ne)[2] = (dst_ne)[3]; \
(dst_ne)[3] = 1; \
(src_nb)[1] = (src_nb)[2]; \
(src_nb)[2] = (src_nb)[3]; \
(dst_nb)[1] = (dst_nb)[2]; \
(dst_nb)[2] = (dst_nb)[3]; \
} \
} while (0)
struct htp_unary_vtcm_layout {
size_t total_bytes;
size_t off_src0;
size_t off_src1;
size_t off_dst;
size_t src0_row_size_aligned;
size_t src1_row_size_aligned;
size_t dst_row_size_aligned;
size_t src0_bytes;
size_t src1_bytes;
size_t dst_bytes;
};
static inline void htp_unary_vtcm_layout_build(
struct htp_unary_vtcm_layout * L,
uint32_t op,
size_t src0_data_row_size,
size_t dst_data_row_size,
size_t src1_data_row_size,
size_t elem_size,
uint32_t col_tile,
uint32_t block,
bool broadcast_weight,
uint32_t n_threads
) {
L->src0_row_size_aligned = hex_round_up(src0_data_row_size, 128);
L->dst_row_size_aligned = hex_round_up(dst_data_row_size, 128);
L->src1_row_size_aligned = (op == HTP_OP_RMS_NORM_MUL) ? hex_round_up(src1_data_row_size, 128) : 0;
if (col_tile > 0) {
const size_t col_tile_bytes = col_tile * elem_size;
L->src0_bytes = col_tile_bytes * 2;
L->dst_bytes = col_tile_bytes * 2;
L->src1_bytes = 0;
} else {
L->src0_bytes = L->src0_row_size_aligned * block * 2;
L->dst_bytes = L->dst_row_size_aligned * block * 2;
if (op == HTP_OP_RMS_NORM_MUL) {
L->src1_bytes = broadcast_weight ? L->src1_row_size_aligned : (L->src1_row_size_aligned * block * 2);
} else {
L->src1_bytes = 0;
}
}
size_t off = 0;
VTCM_LAYOUT_ALLOC(off, off_src0, L->src0_bytes * n_threads);
VTCM_LAYOUT_ALLOC_OPTIONAL(off, off_src1, L->src1_bytes * n_threads, L->src1_bytes > 0);
VTCM_LAYOUT_ALLOC(off, off_dst, L->dst_bytes * n_threads);
L->total_bytes = off;
}
static inline void htp_unary_solve_layout(
struct htp_unary_vtcm_layout * L,
uint32_t op,
uint32_t ne00,
uint32_t ne10,
uint32_t ne11,
uint32_t max_block,
bool broadcast_weight,
uint32_t n_threads,
size_t vtcm_size,
@@ -98,16 +173,11 @@ static inline void htp_unary_vtcm_layout_build(
const size_t dst_elem_size = (op == HTP_OP_HADAMARD) ? sizeof(float) : elem_size;
const size_t src0_data_row_size = ne00 * elem_size;
const size_t dst_data_row_size = ne10 * dst_elem_size;
const size_t src1_data_row_size = (op == HTP_OP_RMS_NORM_MUL) ? (ne11 * sizeof(float)) : 0;
const size_t src0_row_size_aligned = hex_round_up(src0_data_row_size, 128);
const size_t dst_row_size_aligned = hex_round_up(dst_data_row_size, 128);
size_t src1_row_size_aligned = 0;
if (op == HTP_OP_RMS_NORM_MUL) {
// RMS_NORM_MUL fusion is F32-only; its weight tensor is always F32.
const size_t src1_data_row_size = ne11 * sizeof(float);
src1_row_size_aligned = hex_round_up(src1_data_row_size, 128);
}
const size_t src1_row_size_aligned = (op == HTP_OP_RMS_NORM_MUL) ? hex_round_up(src1_data_row_size, 128) : 0;
size_t vtcm_size_per_row = 0;
size_t vtcm_row_per_thread = 0;
@@ -132,6 +202,10 @@ static inline void htp_unary_vtcm_layout_build(
vtcm_row_per_thread = vtcm_size / (n_threads * vtcm_size_per_row);
}
if (max_block > 0 && vtcm_row_per_thread > max_block) {
vtcm_row_per_thread = max_block;
}
const bool is_reduction = (op == HTP_OP_NORM || op == HTP_OP_RMS_NORM ||
op == HTP_OP_RMS_NORM_MUL || op == HTP_OP_L2_NORM ||
op == HTP_OP_HADAMARD);
@@ -148,37 +222,14 @@ static inline void htp_unary_vtcm_layout_build(
const size_t per_thread_budget = vtcm_size / n_threads;
const size_t col_tile_bytes = hex_align_down(per_thread_budget / 4, 128);
col_tile = (uint32_t) (col_tile_bytes / elem_size);
L->src0_bytes = col_tile_bytes * 2;
L->dst_bytes = col_tile_bytes * 2;
L->src1_bytes = 0;
} else {
L->src0_bytes = src0_row_size_aligned * vtcm_row_per_thread * 2;
L->dst_bytes = dst_row_size_aligned * vtcm_row_per_thread * 2;
if (op == HTP_OP_RMS_NORM_MUL) {
if (broadcast_weight) {
L->src1_bytes = src1_row_size_aligned;
} else {
L->src1_bytes = src1_row_size_aligned * vtcm_row_per_thread * 2;
}
} else {
L->src1_bytes = 0;
}
}
L->off_src0 = 0;
if (op == HTP_OP_RMS_NORM_MUL) {
L->off_src1 = L->off_src0 + L->src0_bytes * n_threads;
L->off_dst = L->off_src1 + L->src1_bytes * n_threads;
} else {
L->off_src1 = 0;
L->off_dst = L->off_src0 + L->src0_bytes * n_threads;
}
L->total_bytes = L->off_dst + L->dst_bytes * n_threads;
const uint32_t block = col_tile ? 0 : (uint32_t) vtcm_row_per_thread;
htp_unary_vtcm_layout_build(L, op, src0_data_row_size, dst_data_row_size, src1_data_row_size,
elem_size, col_tile, block, broadcast_weight, n_threads);
*out_col_tile = col_tile;
*out_vtcm_row_per_thread = vtcm_row_per_thread;
*out_vtcm_row_per_thread = (uint32_t) vtcm_row_per_thread;
}
#endif /* HTP_UNARY_OPS_H */
+4 -3
View File
@@ -6868,7 +6868,7 @@ static bool ggml_sycl_graph_update_required(ggml_sycl_graph * graph, ggml_cgraph
// Reports if ggml_sycl_mul_mat() gives this node to oneDNN. oneDNN chains the submission on events
// made before recording started, which SYCL graphs do not allow.
static bool mul_mat_uses_onednn(ggml_tensor * dst) {
static bool mul_mat_uses_onednn(int device, ggml_tensor * dst) {
#if GGML_SYCL_DNNL
if (!g_ggml_sycl_enable_dnn) {
return false;
@@ -6894,7 +6894,7 @@ static bool mul_mat_uses_onednn(ggml_tensor * dst) {
// ggml_sycl_op_mul_mat_sycl() is the last resort of the dispatch and the only user of oneDNN.
// The reorder decision that ggml_sycl_mul_mat() makes between DMMV and MMVQ is left out here:
// neither uses a library.
if (can_use_dequantize_mul_mat_vec(src0, src1, dst) || can_use_mul_mat_vec_q(src0, src1, dst) ||
if (can_use_dequantize_mul_mat_vec(src0, src1, dst) || can_use_mul_mat_vec_q(device, src0, src1, dst) ||
can_use_mul_mat_q(src0, src1, dst)) {
return false;
}
@@ -6916,6 +6916,7 @@ static bool mul_mat_uses_onednn(ggml_tensor * dst) {
const int64_t gemm_flops = src0->ne[1] * src1->ne[1] * src0->ne[0];
return gemm_flops >= SYCL_F32_DNNL_MIN_GEMM_FLOPS;
#else
GGML_UNUSED(device);
GGML_UNUSED(dst);
return false;
#endif
@@ -6978,7 +6979,7 @@ static bool check_graph_compatibility(ggml_backend_sycl_context * ctx, ggml_cgra
return false;
}
#ifndef GGML_SYCL_GRAPH_DNNL_SUPPORTED
if (mul_mat_uses_onednn(node)) {
if (mul_mat_uses_onednn(ctx->device, node)) {
GGML_LOG_DEBUG("%s: disabling SYCL graphs due to %s using oneDNN\n", __func__,
ggml_op_name(node_op));
return false;
+19 -2
View File
@@ -422,6 +422,7 @@ struct llm_tokenizer_bpe : llm_tokenizer {
};
break;
case LLAMA_VOCAB_PRE_TYPE_TEKKEN:
case LLAMA_VOCAB_PRE_TYPE_NEMOTRON_3_5_EMBD:
// original regex from tokenizer.json
// "[^\\r\\n\\p{L}\\p{N}]?[\\p{Lu}\\p{Lt}\\p{Lm}\\p{Lo}\\p{M}]*[\\p{Ll}\\p{Lm}\\p{Lo}\\p{M}]+|[^\\r\\n\\p{L}\\p{N}]?[\\p{Lu}\\p{Lt}\\p{Lm}\\p{Lo}\\p{M}]+[\\p{Ll}\\p{Lm}\\p{Lo}\\p{M}]*|\\p{N}| ?[^\\s\\p{L}\\p{N}]+[\\r\\n/]*|\\s*[\\r\\n]+|\\s+(?!\\S)|\\s+"
regex_exprs = {
@@ -637,11 +638,22 @@ struct llm_tokenizer_bpe_session {
}
virtual void tokenize(const std::string & text, std::vector<llama_token> & output) {
auto tok_pre = vocab.get_pre_type();
std::vector<std::string> word_collection;
if (tok_pre == LLAMA_VOCAB_PRE_TYPE_NEMOTRON_3_5_EMBD) {
static const std::string zwnj = "\xe2\x80\x8c";
std::string normalized_text = text;
replace_all(normalized_text, "[" + zwnj, "[");
replace_all(normalized_text, "<" + zwnj, "<");
word_collection = unicode_regex_split(normalized_text, tokenizer.regex_exprs, tokenizer.byte_encode);
} else {
word_collection = unicode_regex_split(text, tokenizer.regex_exprs, tokenizer.byte_encode);
}
int final_prev_index = -1;
auto word_collection = unicode_regex_split(text, tokenizer.regex_exprs, tokenizer.byte_encode);
symbols_final.clear();
auto tok_pre = vocab.get_pre_type();
if (tok_pre == LLAMA_VOCAB_PRE_TYPE_MMBERT) {
// Metaspace pre-tokenizer: a text starts with an escaped space, and each escaped space starts a new word
@@ -2713,6 +2725,11 @@ void llama_vocab::impl::load(llama_model_loader & ml, const LLM_KV & kv) {
tokenizer_pre == "k2-horizon") {
pre_type = LLAMA_VOCAB_PRE_TYPE_K2_HORIZON;
clean_spaces = false;
} else if (
tokenizer_pre == "nemotron-3.5-embed") {
pre_type = LLAMA_VOCAB_PRE_TYPE_NEMOTRON_3_5_EMBD;
ignore_merges = true;
add_bos = true;
} else {
throw std::runtime_error(format("unknown pre-tokenizer type: '%s'", tokenizer_pre.c_str()));
}
+1
View File
@@ -72,6 +72,7 @@ enum llama_vocab_pre_type {
LLAMA_VOCAB_PRE_TYPE_K2_HORIZON = 61,
LLAMA_VOCAB_PRE_TYPE_FLINT = 62,
LLAMA_VOCAB_PRE_TYPE_DOMYN_SMALL = 63,
LLAMA_VOCAB_PRE_TYPE_NEMOTRON_3_5_EMBD = 64,
};
// HF Metaspace pre-tokenizer prepend_scheme
+1 -1
View File
@@ -9971,7 +9971,7 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_eval() {
}
// fused unary + mul (gated activations that are not expressed as GGML_OP_GLU)
for (ggml_unary_op op : { GGML_UNARY_OP_GELU, GGML_UNARY_OP_SILU, GGML_UNARY_OP_SIGMOID, GGML_UNARY_OP_SOFTPLUS }) {
for (ggml_unary_op op : { GGML_UNARY_OP_GELU, GGML_UNARY_OP_SILU, GGML_UNARY_OP_RELU, GGML_UNARY_OP_SIGMOID, GGML_UNARY_OP_SOFTPLUS }) {
for (ggml_type type : { GGML_TYPE_F16, GGML_TYPE_F32, GGML_TYPE_BF16 }) {
for (bool swap : { false, true }) {
test_cases.emplace_back(new test_unary_mul(op, type, { 128, 2, 2, 2 }, swap));