mirror of
https://github.com/ggml-org/llama.cpp.git
synced 2026-07-22 21:58:15 +02:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1a064ab092 | |||
| 0278d8362d | |||
| e0833bf686 | |||
| 61328e6a91 | |||
| e8e6c7af24 | |||
| 6d5a910c50 | |||
| f534da26e4 | |||
| 3ce7da2c85 | |||
| b4d6c7d8ff | |||
| 7347430f44 | |||
| c5a4a0bb83 | |||
| 67b9b0e7f6 | |||
| 1f66c3ce1c | |||
| 66e4bf7e59 | |||
| b4aa7dd477 | |||
| 71102a73f2 | |||
| 846e991ec3 | |||
| fb0e6b6219 | |||
| 60f6a17704 | |||
| fd41bf65a2 | |||
| 40b740ad05 | |||
| f048010180 | |||
| 5735e10c49 | |||
| 305ba519ab | |||
| 76f46ad29d | |||
| 2beefef688 | |||
| 91d2fc3875 | |||
| 4ee6a9af71 | |||
| 43b5e63589 | |||
| 1521a9ac31 | |||
| 178a6c4493 | |||
| 571d0d540d | |||
| 4937ca83f4 | |||
| 86a9c79f86 | |||
| 6bdd77f13c | |||
| 86d86ed439 | |||
| 7d56da7e54 | |||
| 3727404068 | |||
| 5d5306bf3e | |||
| 635cdd5fcc | |||
| 11fd0a6fb7 | |||
| 788e07dc91 | |||
| 0bd0ec6099 | |||
| b85833e934 | |||
| e8f19cc0ad | |||
| ac2557cb24 | |||
| 0dc74e332e | |||
| b2dd28a3b6 | |||
| f15bd60901 | |||
| b15ca938ad | |||
| 3278e921b1 | |||
| 2e1fd76490 |
@@ -1109,6 +1109,8 @@ jobs:
|
||||
-DGGML_SYCL=ON \
|
||||
-DCMAKE_C_COMPILER=icx \
|
||||
-DCMAKE_CXX_COMPILER=icpx \
|
||||
-DCMAKE_INSTALL_RPATH='$ORIGIN' \
|
||||
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
|
||||
-DLLAMA_OPENSSL=OFF \
|
||||
-DGGML_NATIVE=OFF \
|
||||
-DGGML_SYCL_F16=${{ matrix.fp16 }}
|
||||
|
||||
+106
-2
@@ -351,6 +351,10 @@ static std::string get_default_local_path(const std::string & url) {
|
||||
return fs_get_cache_file(string_split<std::string>(f, '/').back());
|
||||
}
|
||||
|
||||
static bool spec_types_is_default(const common_params & params) {
|
||||
return params.speculative.types == std::vector<enum common_speculative_type>{COMMON_SPECULATIVE_TYPE_NONE};
|
||||
}
|
||||
|
||||
common_models_handler common_models_handler_init(const common_params & params, llama_example curr_ex) {
|
||||
common_download_hf_plan plan;
|
||||
common_download_hf_plan plan_spec;
|
||||
@@ -361,6 +365,14 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
||||
params.speculative.types.end(),
|
||||
COMMON_SPECULATIVE_TYPE_DRAFT_MTP) != params.speculative.types.end();
|
||||
|
||||
const bool spec_type_draft_dflash = std::find(params.speculative.types.begin(),
|
||||
params.speculative.types.end(),
|
||||
COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH) != params.speculative.types.end();
|
||||
|
||||
const bool spec_type_draft_eagle3 = std::find(params.speculative.types.begin(),
|
||||
params.speculative.types.end(),
|
||||
COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3) != params.speculative.types.end();
|
||||
|
||||
// only download mmproj if the current example is using it
|
||||
bool use_mmproj = false;
|
||||
for (const auto & ex : mmproj_examples) {
|
||||
@@ -373,6 +385,8 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
||||
opts.bearer_token = params.hf_token;
|
||||
opts.offline = params.offline;
|
||||
opts.download_mtp = spec_type_draft_mtp;
|
||||
opts.download_eagle3 = spec_type_draft_eagle3;
|
||||
opts.download_dflash = spec_type_draft_dflash;
|
||||
opts.download_mmproj = use_mmproj && !params.no_mmproj
|
||||
&& params.mmproj.path.empty() && params.mmproj.url.empty();
|
||||
|
||||
@@ -381,7 +395,14 @@ common_models_handler common_models_handler_init(const common_params & params, l
|
||||
}
|
||||
|
||||
if (!params.speculative.draft.mparams.hf_repo.empty()) {
|
||||
plan_spec = common_download_get_hf_plan(params.speculative.draft.mparams, opts);
|
||||
// without a requested type, discover every sidecar the draft repo ships to infer the type later
|
||||
auto opts_spec = opts;
|
||||
if (spec_types_is_default(params)) {
|
||||
opts_spec.download_mtp = true;
|
||||
opts_spec.download_dflash = true;
|
||||
opts_spec.download_eagle3 = true;
|
||||
}
|
||||
plan_spec = common_download_get_hf_plan(params.speculative.draft.mparams, opts_spec);
|
||||
}
|
||||
|
||||
if (!params.vocoder.model.hf_repo.empty()) {
|
||||
@@ -517,8 +538,57 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
||||
}
|
||||
};
|
||||
|
||||
// infer the speculative type from the sidecar shipped by the draft repo when none is requested
|
||||
if (spec_types_is_default(params)) {
|
||||
if (!plan_spec.mtp.local_path.empty()) {
|
||||
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_MTP };
|
||||
plan_spec.dflash = {};
|
||||
plan_spec.eagle3 = {};
|
||||
} else if (!plan_spec.dflash.local_path.empty()) {
|
||||
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH };
|
||||
plan_spec.eagle3 = {};
|
||||
} else if (!plan_spec.eagle3.local_path.empty()) {
|
||||
params.speculative.types = { COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3 };
|
||||
}
|
||||
}
|
||||
|
||||
// when a sidecar type is requested, the draft repo resolves to its sidecar instead of a full model
|
||||
const bool spec_sidecar_found = !plan_spec.mtp.local_path.empty() ||
|
||||
!plan_spec.dflash.local_path.empty() ||
|
||||
!plan_spec.eagle3.local_path.empty();
|
||||
if (!plan_spec.mtp.local_path.empty() && !had_spec_url) {
|
||||
tasks.emplace_back(plan_spec.mtp, opts, [&]() {
|
||||
// only use the discovered MTP head when no draft path is set yet
|
||||
if (params.speculative.draft.mparams.path.empty()) {
|
||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan_spec.mtp);
|
||||
} else {
|
||||
hf_cache::finalize_file(plan_spec.mtp);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!plan_spec.dflash.local_path.empty() && !had_spec_url) {
|
||||
tasks.emplace_back(plan_spec.dflash, opts, [&]() {
|
||||
// only use the discovered DFlash sidecar when no draft path is set yet
|
||||
if (params.speculative.draft.mparams.path.empty()) {
|
||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan_spec.dflash);
|
||||
} else {
|
||||
hf_cache::finalize_file(plan_spec.dflash);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!plan_spec.eagle3.local_path.empty() && !had_spec_url) {
|
||||
tasks.emplace_back(plan_spec.eagle3, opts, [&]() {
|
||||
// only use the discovered Eagle3 sidecar when no draft path is set yet
|
||||
if (params.speculative.draft.mparams.path.empty()) {
|
||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan_spec.eagle3);
|
||||
} else {
|
||||
hf_cache::finalize_file(plan_spec.eagle3);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// handle plan_spec (e.g. --spec-draft-hf)
|
||||
if (!plan_spec.model_files.empty() && !had_spec_url) {
|
||||
if (!plan_spec.model_files.empty() && !had_spec_url && !spec_sidecar_found) {
|
||||
add_tasks(plan_spec.model_files, plan_spec.primary, params.speculative.draft.mparams);
|
||||
had_spec_url = true;
|
||||
}
|
||||
@@ -546,6 +616,26 @@ void common_models_handler_apply(common_models_handler & handler, common_params
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!plan.dflash.local_path.empty() && !had_spec_url) {
|
||||
tasks.emplace_back(plan.dflash, opts, [&]() {
|
||||
// only fall back to the discovered DFlash sidecar when no draft was explicitly provided
|
||||
if (params.speculative.draft.mparams.empty()) {
|
||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan.dflash);
|
||||
} else {
|
||||
hf_cache::finalize_file(plan.dflash);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!plan.eagle3.local_path.empty() && !had_spec_url) {
|
||||
tasks.emplace_back(plan.eagle3, opts, [&]() {
|
||||
// only fall back to the discovered Eagle3 sidecar when no draft was explicitly provided
|
||||
if (params.speculative.draft.mparams.empty()) {
|
||||
params.speculative.draft.mparams.path = hf_cache::finalize_file(plan.eagle3);
|
||||
} else {
|
||||
hf_cache::finalize_file(plan.eagle3);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (!plan.preset.local_path.empty()) {
|
||||
tasks.emplace_back(plan.preset, opts, [&]() {
|
||||
// if HF repo is a preset repo, we simply run server in router mode with the preset.ini file
|
||||
@@ -2815,6 +2905,20 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
||||
params.speculative.types.push_back(COMMON_SPECULATIVE_TYPE_DRAFT_MTP);
|
||||
}
|
||||
).set_examples({LLAMA_EXAMPLE_DOWNLOAD}));
|
||||
add_opt(common_arg(
|
||||
{"--dflash"},
|
||||
"also download the DFlash sidecar, if available (default: unused)",
|
||||
[](common_params & params) {
|
||||
params.speculative.types.push_back(COMMON_SPECULATIVE_TYPE_DRAFT_DFLASH);
|
||||
}
|
||||
).set_examples({LLAMA_EXAMPLE_DOWNLOAD}));
|
||||
add_opt(common_arg(
|
||||
{"--eagle3"},
|
||||
"also download the Eagle3 sidecar, if available (default: unused)",
|
||||
[](common_params & params) {
|
||||
params.speculative.types.push_back(COMMON_SPECULATIVE_TYPE_DRAFT_EAGLE3);
|
||||
}
|
||||
).set_examples({LLAMA_EXAMPLE_DOWNLOAD}));
|
||||
add_opt(common_arg(
|
||||
{"--context-file"}, "FNAME",
|
||||
"file to load context from (use comma-separated values to specify multiple files)",
|
||||
|
||||
@@ -47,6 +47,8 @@ common_chat_params peg_generator::generate_parser(const common_chat_template &
|
||||
data.generation_prompt = common_chat_template_generation_prompt(tmpl, inputs);
|
||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
||||
data.preserved_tokens = autoparser.preserved_tokens;
|
||||
data.additional_stops.insert(data.additional_stops.end(),
|
||||
autoparser.additional_stops.begin(), autoparser.additional_stops.end());
|
||||
|
||||
std::string parser_generation_prompt = data.generation_prompt;
|
||||
|
||||
@@ -286,7 +288,13 @@ common_peg_parser analyze_tools::build_func_parser(common_chat_peg_builder & p,
|
||||
// we only emit tool_close when we can actually see the closing marker. This prevents
|
||||
// premature closing during partial parsing when we've seen e.g. "</" which could be
|
||||
// either "</tool_call>" (end) or "<arg_key>" prefix that failed to match.
|
||||
func_parser = func_parser + p.tool_close(p.peek(p.literal(format.per_call_end)));
|
||||
// Laguna (v4): the model may emit whitespace between the last </arg_value> and
|
||||
// </tool_call> even though the template renders them tight. Tolerate optional
|
||||
// leading space in the close lookahead so the tool call still closes.
|
||||
auto close_peek = arguments.tolerate_intertag_whitespace
|
||||
? p.peek(p.space() + p.literal(format.per_call_end))
|
||||
: p.peek(p.literal(format.per_call_end));
|
||||
func_parser = func_parser + p.tool_close(close_peek);
|
||||
} else {
|
||||
func_parser = func_parser + p.tool_close(p.space()); // force this to process tool closing callbacks in mapper
|
||||
}
|
||||
|
||||
@@ -206,6 +206,7 @@ struct tool_arguments_analysis {
|
||||
std::string value_prefix; // e.g., "", "<arg_value>", ""
|
||||
std::string value_suffix; // e.g., "</param>", "</arg_value>", ""
|
||||
std::string separator; // e.g., "", "\n", ","
|
||||
bool tolerate_intertag_whitespace = false; // Laguna: accept optional whitespace between arg tags
|
||||
};
|
||||
|
||||
struct tool_id_analysis {
|
||||
@@ -388,6 +389,7 @@ struct autoparser {
|
||||
|
||||
// Preserved tokens for tokenizer (union of all non-empty markers)
|
||||
std::vector<std::string> preserved_tokens;
|
||||
std::vector<std::string> additional_stops; // literal stop strings (e.g. Laguna </assistant>) caught however tokenized
|
||||
|
||||
autoparser() = default;
|
||||
|
||||
|
||||
@@ -173,6 +173,26 @@ static std::vector<std::function<void(const common_chat_template & tmpl, autopar
|
||||
LOG_DBG(ANSI_ORANGE "[Patch: JSON name/parameters tool instruction]\n" ANSI_RESET);
|
||||
}
|
||||
},
|
||||
// Laguna (poolside) - the v4 chat template renders reasoning and tool-arg
|
||||
// delimiters with formatting whitespace ("<think>\n", "</arg_value>\n") that
|
||||
// the model does not emit, so the inferred delimiters carry a spurious
|
||||
// newline and never match the model output. Trim to the bare tag. (v8
|
||||
// renders without the whitespace, so this is a no-op there.)
|
||||
[](const common_chat_template & tmpl, autoparser & analysis) -> void {
|
||||
if (tmpl.src.find("laguna_glm_thinking") != std::string::npos) {
|
||||
analysis.reasoning.start = trim_whitespace(analysis.reasoning.start);
|
||||
analysis.reasoning.end = trim_whitespace(analysis.reasoning.end);
|
||||
analysis.tools.arguments.value_prefix = trim_whitespace(analysis.tools.arguments.value_prefix);
|
||||
analysis.tools.arguments.value_suffix = trim_whitespace(analysis.tools.arguments.value_suffix);
|
||||
analysis.tools.arguments.separator = trim_whitespace(analysis.tools.arguments.separator);
|
||||
analysis.tools.arguments.tolerate_intertag_whitespace = true;
|
||||
// The CONTROL/eot </assistant> token only halts generation when emitted as the
|
||||
// single token; after tool calls the model can spell it out as text tokens.
|
||||
// A literal stop string catches it either way.
|
||||
analysis.additional_stops.push_back("</assistant>");
|
||||
LOG_DBG(ANSI_ORANGE "[Patch: Laguna]\n" ANSI_RESET);
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
|
||||
+95
-10
@@ -15,11 +15,13 @@
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <exception>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
|
||||
#include <optional>
|
||||
#include <sstream>
|
||||
@@ -1855,12 +1857,89 @@ static common_chat_params common_chat_params_init_gigachat_v3(
|
||||
return data;
|
||||
}
|
||||
|
||||
// The DeepSeek V4 reference implementation renders consecutive tool results into a single
|
||||
// user block, ordered by the tool call order of the preceding assistant message (matched
|
||||
// by tool call id) rather than by the order they appear in the conversation.
|
||||
static json deepseek_v4_sort_tool_results(const json & messages) {
|
||||
json adjusted = messages;
|
||||
std::map<std::string, size_t> call_order;
|
||||
|
||||
for (size_t i = 0; i < adjusted.size();) {
|
||||
const auto & msg = adjusted[i];
|
||||
const auto role = msg.value("role", "");
|
||||
|
||||
if (role == "assistant" && msg.contains("tool_calls") &&
|
||||
msg.at("tool_calls").is_array() && !msg.at("tool_calls").empty()) {
|
||||
call_order.clear();
|
||||
const auto & tool_calls = msg.at("tool_calls");
|
||||
for (size_t idx = 0; idx < tool_calls.size(); idx++) {
|
||||
auto id = tool_calls[idx].value("id", "");
|
||||
if (!id.empty()) {
|
||||
call_order[id] = idx;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (role != "user" && role != "tool") {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// collect a maximal run of user/tool messages - they render into one user block
|
||||
std::vector<size_t> tool_positions;
|
||||
size_t run_end = i;
|
||||
for (; run_end < adjusted.size(); run_end++) {
|
||||
const auto r = adjusted[run_end].value("role", "");
|
||||
if (r == "tool") {
|
||||
tool_positions.push_back(run_end);
|
||||
} else if (r != "user") {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tool_positions.size() > 1 && !call_order.empty()) {
|
||||
std::vector<json> results;
|
||||
results.reserve(tool_positions.size());
|
||||
for (auto pos : tool_positions) {
|
||||
results.push_back(adjusted[pos]);
|
||||
}
|
||||
std::stable_sort(results.begin(), results.end(), [&](const json & a, const json & b) {
|
||||
const auto order = [&](const json & m) {
|
||||
auto it = call_order.find(m.value("tool_call_id", ""));
|
||||
return it == call_order.end() ? (size_t) 0 : it->second;
|
||||
};
|
||||
return order(a) < order(b);
|
||||
});
|
||||
for (size_t k = 0; k < tool_positions.size(); k++) {
|
||||
adjusted[tool_positions[k]] = std::move(results[k]);
|
||||
}
|
||||
}
|
||||
|
||||
i = run_end;
|
||||
}
|
||||
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
static common_chat_params common_chat_params_init_deepseek_v3_2(const common_chat_template & tmpl,
|
||||
const autoparser::generation_params & inputs) {
|
||||
common_chat_params data;
|
||||
|
||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs);
|
||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs);
|
||||
// V4 uses the same DSML markup as V3.2, but names the tool call block "tool_calls"
|
||||
// instead of "function_calls", renders tool results in tool call order and its
|
||||
// non-thinking generation prompt ends with a bare </think> instead of an empty
|
||||
// <think></think> pair.
|
||||
const bool is_v4 = tmpl.source().find("function_calls") == std::string::npos;
|
||||
|
||||
std::optional<json> adjusted_messages;
|
||||
if (is_v4) {
|
||||
adjusted_messages = deepseek_v4_sort_tool_results(inputs.messages);
|
||||
}
|
||||
|
||||
data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs, adjusted_messages);
|
||||
data.generation_prompt = common_chat_template_generation_prompt_impl(tmpl, inputs, adjusted_messages);
|
||||
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
|
||||
data.supports_thinking = true;
|
||||
data.thinking_start_tag = "<think>";
|
||||
@@ -1879,8 +1958,9 @@ static common_chat_params common_chat_params_init_deepseek_v3_2(const common_cha
|
||||
const std::string DSML = "|DSML|";
|
||||
const std::string THINK_START = "<think>";
|
||||
const std::string THINK_END = "</think>";
|
||||
const std::string FC_START = "<" + DSML + "function_calls>";
|
||||
const std::string FC_END = "</" + DSML + "function_calls>";
|
||||
const std::string TC_BLOCK = is_v4 ? "tool_calls" : "function_calls";
|
||||
const std::string FC_START = "<" + DSML + TC_BLOCK + ">";
|
||||
const std::string FC_END = "</" + DSML + TC_BLOCK + ">";
|
||||
const std::string INVOKE_START = "<" + DSML + "invoke";
|
||||
const std::string INVOKE_END = "</" + DSML + "invoke>";
|
||||
const std::string PARAM_START = "<" + DSML + "parameter";
|
||||
@@ -1907,8 +1987,11 @@ static common_chat_params common_chat_params_init_deepseek_v3_2(const common_cha
|
||||
reasoning = p.optional(THINK_START + p.reasoning(p.until(THINK_END)) + THINK_END);
|
||||
} else if (extract_reasoning) {
|
||||
// Thinking disabled but reasoning extraction requested: the generation prompt
|
||||
// contains an empty <think></think> pair that must still be consumed.
|
||||
reasoning = p.optional(p.literal(THINK_START) + p.until(THINK_END) + p.literal(THINK_END));
|
||||
// contains an empty <think></think> pair (V3.2) or a bare </think> (V4) that
|
||||
// must still be consumed.
|
||||
reasoning = is_v4
|
||||
? p.optional(p.literal(THINK_END))
|
||||
: p.optional(p.literal(THINK_START) + p.until(THINK_END) + p.literal(THINK_END));
|
||||
}
|
||||
|
||||
if (has_response_format) {
|
||||
@@ -2612,12 +2695,14 @@ std::optional<common_chat_params> common_chat_try_specialized_template(
|
||||
return common_chat_params_init_gigachat_v3(tmpl, params);
|
||||
}
|
||||
|
||||
// DeepSeek V3.2 format detection: template defines dsml_token and uses it for tool calls.
|
||||
// DeepSeek V3.2/V4 format detection: template defines dsml_token and uses it for tool calls.
|
||||
// The template source contains the token as a variable assignment, not as a literal in markup.
|
||||
// V3.2 names the tool call block "function_calls", V4 names it "tool_calls".
|
||||
if (src.find("dsml_token") != std::string::npos &&
|
||||
src.find("function_calls") != std::string::npos &&
|
||||
src.find("DSML") != std::string::npos) {
|
||||
LOG_DBG("Using specialized template: DeepSeek V3.2\n");
|
||||
src.find("DSML") != std::string::npos &&
|
||||
(src.find("function_calls") != std::string::npos ||
|
||||
src.find("tool_calls") != std::string::npos)) {
|
||||
LOG_DBG("Using specialized template: DeepSeek V3.2/V4\n");
|
||||
return common_chat_params_init_deepseek_v3_2(tmpl, params);
|
||||
}
|
||||
|
||||
|
||||
+23
-3
@@ -620,6 +620,16 @@ static hf_cache::hf_file find_best_mtp(const hf_cache::hf_files & files,
|
||||
return find_best_sibling(files, model, "mtp-");
|
||||
}
|
||||
|
||||
static hf_cache::hf_file find_best_eagle3(const hf_cache::hf_files & files,
|
||||
const std::string & model) {
|
||||
return find_best_sibling(files, model, "eagle3-");
|
||||
}
|
||||
|
||||
static hf_cache::hf_file find_best_dflash(const hf_cache::hf_files & files,
|
||||
const std::string & model) {
|
||||
return find_best_sibling(files, model, "dflash-");
|
||||
}
|
||||
|
||||
static bool gguf_filename_is_model(const std::string & filepath) {
|
||||
if (!string_ends_with(filepath, ".gguf")) {
|
||||
return false;
|
||||
@@ -632,7 +642,9 @@ static bool gguf_filename_is_model(const std::string & filepath) {
|
||||
|
||||
return filename.find("mmproj") == std::string::npos &&
|
||||
filename.find("imatrix") == std::string::npos &&
|
||||
filename.find("mtp-") == std::string::npos;
|
||||
filename.find("mtp-") == std::string::npos &&
|
||||
filename.find("eagle3-") == std::string::npos &&
|
||||
filename.find("dflash-") == std::string::npos;
|
||||
}
|
||||
|
||||
static hf_cache::hf_file find_best_model(const hf_cache::hf_files & files,
|
||||
@@ -740,6 +752,12 @@ common_download_hf_plan common_download_get_hf_plan(const common_params_model &
|
||||
if (opts.download_mtp) {
|
||||
plan.mtp = find_best_mtp(all, primary.path);
|
||||
}
|
||||
if (opts.download_dflash) {
|
||||
plan.dflash = find_best_dflash(all, primary.path);
|
||||
}
|
||||
if (opts.download_eagle3) {
|
||||
plan.eagle3 = find_best_eagle3(all, primary.path);
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
@@ -911,8 +929,10 @@ std::vector<common_cached_model_info> common_list_cached_models() {
|
||||
for (const auto & f : files) {
|
||||
auto split = get_gguf_split_info(f.path);
|
||||
if (split.index != 1 || split.tag.empty() ||
|
||||
split.prefix.find("mmproj") != std::string::npos ||
|
||||
split.prefix.find("mtp-") != std::string::npos) {
|
||||
split.prefix.find("mmproj") != std::string::npos ||
|
||||
split.prefix.find("mtp-") != std::string::npos ||
|
||||
split.prefix.find("eagle3-") != std::string::npos ||
|
||||
split.prefix.find("dflash-") != std::string::npos) {
|
||||
continue;
|
||||
}
|
||||
if (seen.insert(f.repo_id + ":" + split.tag).second) {
|
||||
|
||||
+6
-2
@@ -55,8 +55,10 @@ struct common_download_opts {
|
||||
std::string bearer_token;
|
||||
common_header_list headers;
|
||||
bool offline = false;
|
||||
bool download_mmproj = false;
|
||||
bool download_mtp = false;
|
||||
bool download_mmproj = false;
|
||||
bool download_mtp = false;
|
||||
bool download_eagle3 = false;
|
||||
bool download_dflash = false;
|
||||
common_download_callback * callback = nullptr;
|
||||
};
|
||||
|
||||
@@ -106,6 +108,8 @@ struct common_download_hf_plan {
|
||||
hf_cache::hf_files model_files;
|
||||
hf_cache::hf_file mmproj;
|
||||
hf_cache::hf_file mtp;
|
||||
hf_cache::hf_file eagle3;
|
||||
hf_cache::hf_file dflash;
|
||||
hf_cache::hf_file preset; // if set, only this file is downloaded
|
||||
};
|
||||
common_download_hf_plan common_download_get_hf_plan(const common_params_model & model, const common_download_opts & opts);
|
||||
|
||||
@@ -23,6 +23,7 @@ void caps_apply_preserve_reasoning(jinja::context & ctx, bool enabled) {
|
||||
ctx.set_val("preserve_thinking", mk_val<value_bool>(enabled));
|
||||
ctx.set_val("clear_thinking", mk_val<value_bool>(!enabled));
|
||||
ctx.set_val("truncate_history_thinking", mk_val<value_bool>(!enabled));
|
||||
ctx.set_val("drop_thinking", mk_val<value_bool>(!enabled));
|
||||
}
|
||||
|
||||
static void caps_try_execute(jinja::program & prog,
|
||||
|
||||
@@ -18,6 +18,7 @@ __all__ = [
|
||||
|
||||
TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"AfmoeForCausalLM": "afmoe",
|
||||
"LagunaForCausalLM": "laguna",
|
||||
"ApertusForCausalLM": "llama",
|
||||
"ArceeForCausalLM": "llama",
|
||||
"ArcticForCausalLM": "arctic",
|
||||
@@ -31,6 +32,7 @@ TEXT_MODEL_MAP: dict[str, str] = {
|
||||
"BertForSequenceClassification": "bert",
|
||||
"BertModel": "bert",
|
||||
"BitnetForCausalLM": "bitnet",
|
||||
"BitNetForCausalLM": "bitnet",
|
||||
"BloomForCausalLM": "bloom",
|
||||
"BloomModel": "bloom",
|
||||
"CamembertModel": "bert",
|
||||
|
||||
@@ -1682,6 +1682,9 @@ class TextModel(ModelBase):
|
||||
if chkhsh == "9dcf830ee9990cdbf78cc523a5f7bd9ad8f3f9890c2d3581d2785ad10f07049d":
|
||||
# ref: https://huggingface.co/JetBrains/Mellum2-12B-A2.5B-Base
|
||||
res = "mellum2"
|
||||
if chkhsh == "972da7b59cec44d1f0a490a86c96df53859e486e481563e5dddac155013d87ac":
|
||||
# ref: https://huggingface.co/poolside/Laguna-XS.2
|
||||
res = "laguna"
|
||||
|
||||
if res is None:
|
||||
logger.warning("\n")
|
||||
|
||||
@@ -8,7 +8,7 @@ if TYPE_CHECKING:
|
||||
from .base import ModelBase, TextModel, gguf
|
||||
|
||||
|
||||
@ModelBase.register("BitnetForCausalLM")
|
||||
@ModelBase.register("BitnetForCausalLM", "BitNetForCausalLM")
|
||||
class BitnetModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.BITNET
|
||||
|
||||
|
||||
@@ -338,6 +338,12 @@ class HunyuanVLTextModel(HunYuanModel):
|
||||
|
||||
def __init__(self, dir_model: Path, *args, **kwargs):
|
||||
super().__init__(dir_model, *args, **kwargs)
|
||||
# transformers 5.13.0 encodes HunyuanVL XD-RoPE as dynamic + mrope_section.
|
||||
# Normalize it to avoid the HunYuan dynamic-RoPE context assertion.
|
||||
if self.rope_parameters.get("rope_type") == "dynamic" and "mrope_section" in self.rope_parameters:
|
||||
self.rope_parameters["rope_type"] = "xdrope"
|
||||
self.rope_parameters["type"] = "xdrope"
|
||||
self.rope_parameters["xdrope_section"] = list(self.rope_parameters["mrope_section"])
|
||||
|
||||
def set_gguf_parameters(self):
|
||||
super().set_gguf_parameters()
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
from collections.abc import Iterable
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import torch
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from torch import Tensor
|
||||
|
||||
from .base import ModelBase, TextModel, gguf, logger
|
||||
|
||||
|
||||
@ModelBase.register("LagunaForCausalLM")
|
||||
class LagunaModel(TextModel):
|
||||
model_arch = gguf.MODEL_ARCH.LAGUNA
|
||||
_experts: list[dict] | None = None
|
||||
_gate_types: list[str] | None = None
|
||||
|
||||
# --- vocab ---------------------------------------------------------------
|
||||
|
||||
def set_vocab(self) -> None:
|
||||
self._set_vocab_gpt2()
|
||||
|
||||
# Some Laguna releases wrap the chat template in tokenizer_config.json as
|
||||
# "{% include 'chat_template.jinja' %}", which SpecialVocab embeds verbatim
|
||||
# and llama.cpp's jinja engine cannot process. Prefer the resolved template
|
||||
# from the chat_template.jinja file so the GGUF is self-contained.
|
||||
tmpl_file = self.dir_model / "chat_template.jinja"
|
||||
if tmpl_file.is_file():
|
||||
self.gguf_writer.add_chat_template(tmpl_file.read_text(encoding="utf-8"))
|
||||
logger.info("gguf: embedded resolved chat_template.jinja (overriding include directive)")
|
||||
|
||||
# eos_token_id is a list [2, 24]: token 2 (EOS, also BOS) and token 24
|
||||
# (</assistant>, the turn-end). _set_vocab_gpt2 only records the scalar
|
||||
# eos, so register the extra id as eot; llama.cpp folds eot into its EOG
|
||||
# set, so the model halts on </assistant> natively.
|
||||
eos_ids = self.hparams.get("eos_token_id")
|
||||
if isinstance(eos_ids, list):
|
||||
bos_id = self.hparams.get("bos_token_id")
|
||||
extra = [e for e in eos_ids if e != bos_id]
|
||||
if extra:
|
||||
self.gguf_writer.add_eot_token_id(extra[0])
|
||||
logger.info(f"gguf: registered eot_token_id={extra[0]} from eos list {eos_ids}")
|
||||
|
||||
def get_vocab_base(self) -> tuple[list[str], list[int], str]:
|
||||
# </assistant> is the assistant turn-end (registered as eot below). The
|
||||
# HF tokenizer flags it special=false, so the base classifies it as
|
||||
# USER_DEFINED and llama.cpp renders its text into generated content,
|
||||
# leaking "</assistant>" and breaking response parsing. It is a control
|
||||
# marker, so promote it to CONTROL: llama.cpp then treats it as
|
||||
# end-of-generation and suppresses its text.
|
||||
tokens, toktypes, tokpre = super().get_vocab_base()
|
||||
for i, tok in enumerate(tokens):
|
||||
if tok == "</assistant>":
|
||||
toktypes[i] = gguf.TokenType.CONTROL
|
||||
logger.info(f"gguf: marked </assistant> (id {i}) as CONTROL token")
|
||||
return tokens, toktypes, tokpre
|
||||
|
||||
# --- hparams -------------------------------------------------------------
|
||||
|
||||
def set_gguf_parameters(self) -> None:
|
||||
super().set_gguf_parameters()
|
||||
hparams = self.hparams
|
||||
|
||||
# super() does not emit vocab_size for the gpt2 vocab path; head_count is
|
||||
# overridden with a per-layer array (XS.2 varies heads per layer via
|
||||
# num_attention_heads_per_layer; M.1 is uniform and omits it).
|
||||
self.gguf_writer.add_vocab_size(hparams["vocab_size"])
|
||||
|
||||
per_layer_heads = hparams.get("num_attention_heads_per_layer")
|
||||
if not per_layer_heads:
|
||||
per_layer_heads = [hparams["num_attention_heads"]] * hparams["num_hidden_layers"]
|
||||
assert len(per_layer_heads) == hparams["num_hidden_layers"], (
|
||||
f"num_attention_heads_per_layer length {len(per_layer_heads)} != "
|
||||
f"num_hidden_layers {hparams['num_hidden_layers']}"
|
||||
)
|
||||
self.gguf_writer.add_head_count(per_layer_heads)
|
||||
|
||||
# Resolve + validate the attention gate type now so an inconsistent
|
||||
# `gating` field fails at conversion time. See _attn_gate_types.
|
||||
self._attn_gate_types()
|
||||
|
||||
# SWA window size (M.1 has none -> key omitted, swa_type stays NONE).
|
||||
sliding_window = hparams.get("sliding_window") or 0
|
||||
if sliding_window > 0:
|
||||
self.gguf_writer.add_sliding_window(sliding_window)
|
||||
|
||||
# MoE (expert_count / expert_used_count come from super().set_gguf_parameters())
|
||||
self.gguf_writer.add_expert_feed_forward_length(hparams["moe_intermediate_size"])
|
||||
self.gguf_writer.add_expert_shared_feed_forward_length(hparams["shared_expert_intermediate_size"])
|
||||
self.gguf_writer.add_expert_weights_norm(True) # HF reference always sum-normalises after top-k
|
||||
self.gguf_writer.add_expert_weights_scale(float(hparams["moe_routed_scaling_factor"]))
|
||||
self.gguf_writer.add_expert_gating_func(gguf.ExpertGatingFuncType.SIGMOID)
|
||||
|
||||
# Leading dense layers (XS.2 has 1, M.1 has 3) before the MoE layers.
|
||||
mlp_layer_types: list[str] = hparams["mlp_layer_types"]
|
||||
leading_dense = 0
|
||||
for t in mlp_layer_types:
|
||||
if t == "dense":
|
||||
leading_dense += 1
|
||||
else:
|
||||
break
|
||||
self.gguf_writer.add_leading_dense_block_count(leading_dense)
|
||||
|
||||
# Per-layer-type RoPE dimension count (partial rotary). base emits
|
||||
# rope_freq_base(_swa) and the YaRN params from self.rope_parameters.
|
||||
head_dim = hparams["head_dim"]
|
||||
full_rope = self.rope_parameters["full_attention"]
|
||||
self.gguf_writer.add_rope_dimension_count(
|
||||
int(head_dim * float(full_rope.get("partial_rotary_factor", 1.0))))
|
||||
swa_rope = self.rope_parameters.get("sliding_attention")
|
||||
if swa_rope is not None:
|
||||
self.gguf_writer.add_rope_dimension_count_swa(
|
||||
int(head_dim * float(swa_rope.get("partial_rotary_factor", 1.0))))
|
||||
|
||||
def _attn_gate_types(self) -> list[str]:
|
||||
"""Per-layer attention output gate type: "per_head" or "per_element".
|
||||
|
||||
`gating_types` (per layer) is authoritative when present; otherwise the
|
||||
scalar `gating` field is used (the "per-element"/"per-head" string, or
|
||||
the legacy boolean True == per-head, as in Laguna-XS.2).
|
||||
|
||||
Fails loudly when the model is per-element but the `gating` field does
|
||||
not declare that as a string: runtimes that key off `gating` (vLLM,
|
||||
transformers) ignore gating_types and read a bare boolean True as
|
||||
per-head, silently corrupting the model. Surfacing it here keeps a
|
||||
broken checkpoint from being packaged as if it were fine.
|
||||
"""
|
||||
if self._gate_types is not None:
|
||||
return self._gate_types
|
||||
hparams = self.hparams
|
||||
n_layer = hparams["num_hidden_layers"]
|
||||
gating = hparams.get("gating")
|
||||
gating_types = hparams.get("gating_types")
|
||||
|
||||
def _norm(t: object) -> str:
|
||||
sval = str(t).replace("-", "_")
|
||||
if sval in ("per_element", "per_head"):
|
||||
return sval
|
||||
raise ValueError(f"Laguna: unrecognised attention gate type {t!r}")
|
||||
|
||||
if gating_types:
|
||||
assert len(gating_types) == n_layer, (
|
||||
f"gating_types length {len(gating_types)} != num_hidden_layers {n_layer}")
|
||||
types = [_norm(t) for t in gating_types]
|
||||
elif isinstance(gating, str):
|
||||
types = [_norm(gating)] * n_layer
|
||||
elif gating is True:
|
||||
types = ["per_head"] * n_layer
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Laguna: cannot determine attention gate type "
|
||||
f"(gating={gating!r}, gating_types={gating_types!r})")
|
||||
|
||||
if any(t == "per_element" for t in types) and not (
|
||||
isinstance(gating, str) and _norm(gating) == "per_element"):
|
||||
raise ValueError(
|
||||
f"Laguna config declares a per-element attention gate but "
|
||||
f"`gating`={gating!r} is not the string \"per-element\". Runtimes that "
|
||||
f"read `gating` (vLLM, transformers) will mis-handle this checkpoint as "
|
||||
f"per-head. Set gating=\"per-element\" in the source config.")
|
||||
|
||||
self._gate_types = types
|
||||
return types
|
||||
|
||||
# --- tensor handling -----------------------------------------------------
|
||||
|
||||
def modify_tensors(self, data_torch: Tensor, name: str, bid: int | None) -> Iterable[tuple[str, Tensor]]:
|
||||
# Per-expert MoE weights: model.layers.{bid}.mlp.experts.{xid}.{w}.weight.
|
||||
# Only the NUMBERED per-expert weights are stacked; the router bias
|
||||
# (mlp.experts.e_score_correction_bias) takes the normal mapping path.
|
||||
if re.search(r"mlp\.experts\.\d+\.", name):
|
||||
n_experts = self.find_hparam(["num_local_experts", "num_experts"])
|
||||
assert bid is not None
|
||||
if self._experts is None:
|
||||
self._experts = [{} for _ in range(self.block_count)]
|
||||
self._experts[bid][name] = data_torch
|
||||
needed = [f"model.layers.{bid}.mlp.experts.{x}.{w}.weight"
|
||||
for x in range(n_experts) for w in ("gate_proj", "up_proj", "down_proj")]
|
||||
if all(e in self._experts[bid] for e in needed):
|
||||
for w_name in ["gate_proj", "up_proj", "down_proj"]:
|
||||
datas = [self._experts[bid][f"model.layers.{bid}.mlp.experts.{x}.{w_name}.weight"]
|
||||
for x in range(n_experts)]
|
||||
stacked = torch.stack(datas, dim=0)
|
||||
merged = f"model.layers.{bid}.mlp.experts.{w_name}.weight"
|
||||
yield from TextModel.modify_tensors(self, stacked, merged, bid)
|
||||
self._experts[bid].clear()
|
||||
return
|
||||
return
|
||||
# Cross-check the gate projection width against the declared gate type;
|
||||
# a mismatch means the weights and config disagree -> fail, do not guess.
|
||||
if bid is not None and name.endswith("self_attn.g_proj.weight"):
|
||||
heads = (self.hparams.get("num_attention_heads_per_layer")
|
||||
or [self.hparams["num_attention_heads"]] * self.hparams["num_hidden_layers"])
|
||||
n_head = heads[bid]
|
||||
head_dim = self.hparams["head_dim"]
|
||||
gate_type = self._attn_gate_types()[bid]
|
||||
expected = n_head * head_dim if gate_type == "per_element" else n_head
|
||||
out_features = int(data_torch.shape[0])
|
||||
if out_features != expected:
|
||||
raise ValueError(
|
||||
f"Laguna layer {bid}: g_proj output width {out_features} contradicts the "
|
||||
f"declared {gate_type} gate (expected {expected}); weights and config disagree.")
|
||||
|
||||
yield from TextModel.modify_tensors(self, data_torch, name, bid)
|
||||
@@ -162,6 +162,7 @@ models = [
|
||||
{"name": "granite-embed-multi-97m", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/ibm-granite/granite-embedding-97m-multilingual-r2", },
|
||||
{"name": "granite-embed-multi-311m", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/ibm-granite/granite-embedding-311m-multilingual-r2", },
|
||||
{"name": "mellum2", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/JetBrains/Mellum2-12B-A2.5B-Base"},
|
||||
{"name": "laguna", "tokt": TOKENIZER_TYPE.BPE, "repo": "https://huggingface.co/poolside/Laguna-XS.2", },
|
||||
]
|
||||
|
||||
# some models are known to be broken upstream, so we will skip them as exceptions
|
||||
|
||||
@@ -47,6 +47,7 @@ The llama.cpp OpenCL backend is designed to enable llama.cpp on **Qualcomm Adren
|
||||
| Adreno GPU | Status |
|
||||
|:-------------------------------------:|:-------:|
|
||||
| Adreno 750 (Snapdragon 8 Gen 3) | Support |
|
||||
| Adreno 810 (Snapdragon 7s Gen 3) | Support |
|
||||
| Adreno 830 (Snapdragon 8 Elite) | Support |
|
||||
| Adreno 840 (Snapdragon 8 Elite Gen 5) | Support |
|
||||
| Adreno X1-85 (Snapdragon X Elite) | Support |
|
||||
|
||||
+10
-6
@@ -25,10 +25,10 @@ Legend:
|
||||
| CEIL | ❌ | ❌ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CLAMP | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | 🟡 | ✅ | 🟡 | ✅ | ❌ | ❌ |
|
||||
| COL2IM_1D | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| CONCAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CONCAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| CONT | ❌ | 🟡 | ✅ | ✅ | 🟡 | ✅ | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| CONV_2D | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CONV_2D_DW | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| CONV_2D_DW | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| CONV_3D | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ |
|
||||
| CONV_TRANSPOSE_1D | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| CONV_TRANSPOSE_2D | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
@@ -41,6 +41,9 @@ Legend:
|
||||
| DIAG | ❌ | ❌ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DIAG_MASK_INF | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| DIV | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| DSV4_HC_COMB | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_POST | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DSV4_HC_PRE | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| DUP | ❌ | ✅ | ✅ | 🟡 | ❌ | 🟡 | 🟡 | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| ELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| EXP | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
@@ -63,16 +66,17 @@ Legend:
|
||||
| HARDSWISH | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| IM2COL | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| IM2COL_3D | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| L2_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| L2_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| LEAKY_RELU | ❌ | ✅ | ✅ | ✅ | ❌ | 🟡 | ❌ | ✅ | 🟡 | ❌ | ❌ | ❌ |
|
||||
| LIGHTNING_INDEXER | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| LOG | ❌ | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MEAN | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| MUL | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL_MAT | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 | 🟡 |
|
||||
| MUL_MAT_HADAMARD | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| MUL_MAT_HADAMARD | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| MUL_MAT_ID | ❌ | 🟡 | ✅ | ✅ | 🟡 | 🟡 | 🟡 | ✅ | ✅ | 🟡 | 🟡 | ❌ |
|
||||
| NEG | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ❌ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | 🟡 | ✅ | ❌ | ❌ |
|
||||
| NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | 🟡 | 🟡 | ❌ | ❌ |
|
||||
| OPT_STEP_ADAMW | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||
| OPT_STEP_SGD | ❌ | ❌ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ |
|
||||
| OUT_PROD | 🟡 | 🟡 | 🟡 | 🟡 | ❌ | ❌ | ❌ | 🟡 | ❌ | ❌ | ❌ | 🟡 |
|
||||
@@ -82,7 +86,7 @@ Legend:
|
||||
| POOL_2D | ❌ | 🟡 | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| REGLU | ❌ | ✅ | ✅ | ✅ | 🟡 | 🟡 | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| RELU | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| REPEAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| REPEAT | ❌ | ✅ | ✅ | 🟡 | 🟡 | ✅ | 🟡 | ✅ | ✅ | 🟡 | ❌ | ❌ |
|
||||
| REPEAT_BACK | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
| RMS_NORM | ❌ | ✅ | ✅ | ✅ | 🟡 | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
|
||||
| RMS_NORM_BACK | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ | ❌ | ❌ |
|
||||
|
||||
+2629
-952
File diff suppressed because it is too large
Load Diff
+1
-1
@@ -4,7 +4,7 @@ project("ggml" C CXX ASM)
|
||||
|
||||
### GGML Version
|
||||
set(GGML_VERSION_MAJOR 0)
|
||||
set(GGML_VERSION_MINOR 16)
|
||||
set(GGML_VERSION_MINOR 17)
|
||||
set(GGML_VERSION_PATCH 0)
|
||||
set(GGML_VERSION_BASE "${GGML_VERSION_MAJOR}.${GGML_VERSION_MINOR}.${GGML_VERSION_PATCH}")
|
||||
|
||||
|
||||
@@ -100,6 +100,7 @@ extern "C" {
|
||||
GGML_BACKEND_API int ggml_cpu_has_sve (void);
|
||||
GGML_BACKEND_API int ggml_cpu_get_sve_cnt (void); // sve vector length in bytes
|
||||
GGML_BACKEND_API int ggml_cpu_has_sme (void);
|
||||
GGML_BACKEND_API int ggml_cpu_has_sme2 (void);
|
||||
// other
|
||||
GGML_BACKEND_API int ggml_cpu_has_riscv_v (void);
|
||||
GGML_BACKEND_API int ggml_cpu_get_rvv_vlen (void); // risc-v vector length in bytes
|
||||
|
||||
@@ -8,10 +8,10 @@ extern "C" {
|
||||
|
||||
#define RPC_PROTO_MAJOR_VERSION 4
|
||||
#define RPC_PROTO_MINOR_VERSION 0
|
||||
#define RPC_PROTO_PATCH_VERSION 2
|
||||
#define RPC_PROTO_PATCH_VERSION 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
static_assert(GGML_OP_COUNT == 98, "GGML_OP_COUNT has changed - update RPC_PROTO_PATCH_VERSION");
|
||||
static_assert(GGML_OP_COUNT == 101, "GGML_OP_COUNT has changed - update RPC_PROTO_PATCH_VERSION");
|
||||
#endif
|
||||
|
||||
#define GGML_RPC_MAX_SERVERS 16
|
||||
|
||||
@@ -571,6 +571,9 @@ extern "C" {
|
||||
GGML_OP_SOLVE_TRI,
|
||||
GGML_OP_GATED_DELTA_NET,
|
||||
GGML_OP_LIGHTNING_INDEXER,
|
||||
GGML_OP_DSV4_HC_COMB,
|
||||
GGML_OP_DSV4_HC_PRE,
|
||||
GGML_OP_DSV4_HC_POST,
|
||||
|
||||
GGML_OP_UNARY,
|
||||
|
||||
@@ -2598,6 +2601,45 @@ extern "C" {
|
||||
struct ggml_tensor * weights,
|
||||
struct ggml_tensor * mask);
|
||||
|
||||
// DeepSeek V4 hyper-connections (ref. https://arxiv.org/pdf/2512.24880)
|
||||
// In short these operations are replacements for the original residual connection (x = transformer(x) + x)
|
||||
// using a richer representation through streams.
|
||||
//
|
||||
// hc_comb: mixes [(2 + hc)*hc, n_tokens], scale [3], base [(2 + hc)*hc]
|
||||
// -> [dst_hc, src_hc, n_tokens]
|
||||
// logits[dst, src, t] = mixes[2*hc + dst + hc*src, t]*scale[2]
|
||||
// + base[2*hc + dst + hc*src]
|
||||
// Softmax over dst, add eps, normalize over src, then repeat normalization
|
||||
// over dst followed by src for iterations 1 through n_iter - 1.
|
||||
GGML_API struct ggml_tensor * ggml_dsv4_hc_comb(
|
||||
struct ggml_context * ctx,
|
||||
struct ggml_tensor * mixes,
|
||||
struct ggml_tensor * scale,
|
||||
struct ggml_tensor * base,
|
||||
float eps,
|
||||
int32_t n_iter);
|
||||
|
||||
// hc_pre: x [n_embd, hc, n_tokens], weights [hc, n_tokens] -> [n_embd, n_tokens]
|
||||
// result[i, t] = sum_h x[i, h, t]*weights[h, t]
|
||||
//
|
||||
GGML_API struct ggml_tensor * ggml_dsv4_hc_pre(
|
||||
struct ggml_context * ctx,
|
||||
struct ggml_tensor * x,
|
||||
struct ggml_tensor * weights);
|
||||
|
||||
// hc_post: x [n_embd, n_tokens], residual [n_embd, hc, n_tokens],
|
||||
// post [hc, n_tokens], comb [dst_hc, src_hc, n_tokens]
|
||||
// -> [n_embd, hc, n_tokens]
|
||||
// result[i, dst, t] = x[i, t]*post[dst, t]
|
||||
// + sum_src residual[i, src, t]*comb[dst, src, t]
|
||||
//
|
||||
GGML_API struct ggml_tensor * ggml_dsv4_hc_post(
|
||||
struct ggml_context * ctx,
|
||||
struct ggml_tensor * x,
|
||||
struct ggml_tensor * residual,
|
||||
struct ggml_tensor * post,
|
||||
struct ggml_tensor * comb);
|
||||
|
||||
// custom operators
|
||||
|
||||
typedef void (*ggml_custom1_op_t)(struct ggml_tensor * dst , const struct ggml_tensor * a, int ith, int nth, void * userdata);
|
||||
|
||||
@@ -430,7 +430,7 @@ if (GGML_CPU_ALL_VARIANTS)
|
||||
message(FATAL_ERROR "Unsupported ARM target OS: ${CMAKE_SYSTEM_NAME}")
|
||||
endif()
|
||||
elseif (GGML_SYSTEM_ARCH STREQUAL "PowerPC")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Linux|AIX")
|
||||
ggml_add_cpu_backend_variant(power0)
|
||||
ggml_add_cpu_backend_variant(power7_1 POWER7)
|
||||
ggml_add_cpu_backend_variant(power7_2 POWER7 VSX)
|
||||
|
||||
@@ -984,6 +984,11 @@ static struct ggml_backend_meta_split_state ggml_backend_meta_get_split_state(
|
||||
case GGML_OP_GATED_DELTA_NET: {
|
||||
split_state = handle_gated_delta_net(src_ss);
|
||||
} break;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
case GGML_OP_DSV4_HC_POST: {
|
||||
split_state = handle_generic(src_ss, /*scalar_only =*/ true);
|
||||
} break;
|
||||
case GGML_OP_UNARY: {
|
||||
split_state = handle_generic(src_ss, /*scalar_only =*/ false);
|
||||
} break;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "ggml.h"
|
||||
#include "ggml-impl.h"
|
||||
#include "ggml-blas.h"
|
||||
#include "ggml-backend-impl.h"
|
||||
@@ -415,6 +416,12 @@ static bool ggml_backend_blas_device_supports_op(ggml_backend_dev_t dev, const s
|
||||
// TODO: find the optimal value
|
||||
const int64_t min_batch = 32;
|
||||
|
||||
// default back to CPU fast path
|
||||
// see: https://github.com/ggml-org/llama.cpp/issues/25565
|
||||
if (ggml_get_op_params_i32(op, 1) == GGML_HINT_SRC0_IS_HADAMARD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ggml_is_contiguous(src0) &&
|
||||
ggml_is_contiguous(src1) &&
|
||||
src1->type == GGML_TYPE_F32 &&
|
||||
|
||||
@@ -678,7 +678,18 @@ function(ggml_add_cpu_backend_variant_impl tag_name)
|
||||
endif()
|
||||
|
||||
if (NOT SME_ENABLED MATCHES -1)
|
||||
list(APPEND GGML_KLEIDIAI_SOURCES
|
||||
list(APPEND GGML_KLEIDIAI_SME_SOURCES
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi8cxp/kai_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa.c
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi8cxp/kai_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa_asm.S
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi8cxp/kai_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot.c
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi8cxp/kai_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot_asm.S
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_f32p_f32p/kai_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa.c
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_f32p_f32p/kai_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa_asm.S)
|
||||
set_source_files_properties(${GGML_KLEIDIAI_SME_SOURCES}
|
||||
PROPERTIES COMPILE_OPTIONS "-fno-tree-vectorize;${ARCH_FLAGS_TEMP}+sve+sve2+sme")
|
||||
list(APPEND GGML_CPU_SOURCES ${GGML_KLEIDIAI_SME_SOURCES})
|
||||
|
||||
list(APPEND GGML_KLEIDIAI_SME2_SOURCES
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qsi8d32p_qsi4c32p/kai_matmul_clamp_f32_qsi8d32p1x4_qsi4c32p4vlx4_1x4vl_sme2_sdot.c
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi8cxp/kai_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme2_mopa.c
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/matmul_clamp_f32_qai8dxp_qsi8cxp/kai_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme2_mopa_asm.S
|
||||
@@ -698,7 +709,10 @@ function(ggml_add_cpu_backend_variant_impl tag_name)
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/pack/kai_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme.c
|
||||
${KLEIDIAI_SRC}/kai/ukernels/matmul/pack/kai_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme_asm.S
|
||||
${KLEIDIAI_SRC}/kai/kai_common_sme_asm.S)
|
||||
set(PRIVATE_ARCH_FLAGS "-fno-tree-vectorize;${PRIVATE_ARCH_FLAGS}+sve+sve2+sme2+fp16")
|
||||
set_source_files_properties(${GGML_KLEIDIAI_SME2_SOURCES}
|
||||
PROPERTIES COMPILE_OPTIONS "-fno-tree-vectorize;${ARCH_FLAGS_TEMP}+sve+sve2+sme2+fp16")
|
||||
list(APPEND GGML_CPU_SOURCES ${GGML_KLEIDIAI_SME2_SOURCES})
|
||||
set(PRIVATE_ARCH_FLAGS "-fno-tree-vectorize;${PRIVATE_ARCH_FLAGS}")
|
||||
endif()
|
||||
|
||||
if (NOT SVE_ENABLED MATCHES -1)
|
||||
|
||||
@@ -28,6 +28,7 @@ struct aarch64_features {
|
||||
bool has_sve2 = false;
|
||||
bool has_i8mm = false;
|
||||
bool has_sme = false;
|
||||
bool has_sme2 = false;
|
||||
|
||||
aarch64_features() {
|
||||
#if defined(__linux__)
|
||||
@@ -56,6 +57,10 @@ struct aarch64_features {
|
||||
has_sme = static_cast<bool>(oldp);
|
||||
}
|
||||
|
||||
if (sysctlbyname("hw.optional.arm.FEAT_SME2", &oldp, &size, NULL, 0) == 0) {
|
||||
has_sme2 = static_cast<bool>(oldp);
|
||||
}
|
||||
|
||||
// Apple apparently does not implement SVE yet
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -2064,6 +2064,18 @@ static void ggml_compute_forward(struct ggml_compute_params * params, struct ggm
|
||||
{
|
||||
ggml_compute_forward_lightning_indexer(params, tensor);
|
||||
} break;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
{
|
||||
ggml_compute_forward_dsv4_hc_comb(params, tensor);
|
||||
} break;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
{
|
||||
ggml_compute_forward_dsv4_hc_pre(params, tensor);
|
||||
} break;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
{
|
||||
ggml_compute_forward_dsv4_hc_post(params, tensor);
|
||||
} break;
|
||||
case GGML_OP_MAP_CUSTOM1:
|
||||
{
|
||||
ggml_compute_forward_map_custom1(params, tensor);
|
||||
@@ -2244,6 +2256,9 @@ static int ggml_get_n_tasks(struct ggml_tensor * node, int n_threads) {
|
||||
case GGML_OP_COUNT_EQUAL:
|
||||
case GGML_OP_SOLVE_TRI:
|
||||
case GGML_OP_GATED_DELTA_NET:
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
{
|
||||
n_tasks = n_threads;
|
||||
} break;
|
||||
@@ -3792,6 +3807,14 @@ int ggml_cpu_has_sme(void) {
|
||||
#endif
|
||||
}
|
||||
|
||||
int ggml_cpu_has_sme2(void) {
|
||||
#if defined(__ARM_ARCH) && defined(__ARM_FEATURE_SME2)
|
||||
return 1;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void ggml_cpu_init(void) {
|
||||
// needed to initialize ggml_time
|
||||
{
|
||||
|
||||
@@ -595,6 +595,9 @@ static ggml_backend_feature * ggml_backend_cpu_get_features(ggml_backend_reg_t r
|
||||
if (ggml_cpu_has_sme()) {
|
||||
features.push_back({ "SME", "1" });
|
||||
}
|
||||
if (ggml_cpu_has_sme2()) {
|
||||
features.push_back({ "SME2", "1" });
|
||||
}
|
||||
if (ggml_cpu_has_riscv_v()) {
|
||||
features.push_back({ "RISCV_V", "1" });
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "kai_matmul_clamp_f32_bf16p2vlx2_bf16p2vlx2_2vlx2vl_sme2_mopa.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme2_mopa.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme2_dot.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp1x8_qsi8cxp4x8_1x4_neon_dotprod.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4x4_1x4_neon_dotprod.h"
|
||||
#include "kai_matmul_clamp_f32_qai8dxp4x4_qsi8cxp4x4_16x4_neon_dotprod.h"
|
||||
@@ -21,6 +23,7 @@
|
||||
#include "kai_matmul_clamp_f32_qsi8d32p1x8_qsi4c32p8x8_1x8_sve_dotprod.h"
|
||||
#include "kai_matmul_clamp_f32_f16p1vlx2_qsi4c32p4vlx2_1vlx4vl_sme2_mopa.h"
|
||||
#include "kai_matmul_clamp_f32_f32p2vlx1_f32p2vlx1biasf32_sme2_mopa.h"
|
||||
#include "kai_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa.h"
|
||||
|
||||
#include "kai_lhs_pack_bf16p2vlx2_f32_sme.h"
|
||||
#include "kai_lhs_pack_f32p2vlx1_f32_sme.h"
|
||||
@@ -359,7 +362,7 @@ static ggml_kleidiai_kernels gemm_gemv_kernels[] = {
|
||||
/* .packed_stride_ex = */ &rhs_stride_fn4<kai_get_rhs_packed_stride_rhs_pack_nxk_qsi4c32ps1s0scalef16_qsu4c32s16s0_neon>,
|
||||
/* .pack_func_ex = */ &rhs_pack_fn12<kai_run_rhs_pack_nxk_qsi4c32ps1s0scalef16_qsu4c32s16s0_neon>,
|
||||
},
|
||||
/* .required_cpu = */ CPU_FEATURE_SME,
|
||||
/* .required_cpu = */ CPU_FEATURE_SME2,
|
||||
/* .lhs_type = */ GGML_TYPE_F32,
|
||||
/* .rhs_type = */ GGML_TYPE_Q4_0,
|
||||
/* .op_type = */ GGML_TYPE_F32,
|
||||
@@ -412,7 +415,7 @@ static ggml_kleidiai_kernels gemm_gemv_kernels[] = {
|
||||
/* .packed_stride_ex = */ &rhs_stride_fn1<kai_get_rhs_packed_stride_rhs_pack_kxn_bf16p2vlx2b_f32_x32_sme>,
|
||||
/* .pack_func_ex = */ &rhs_pack_fn13<kai_run_rhs_pack_kxn_bf16p2vlx2b_f32_x32_sme>,
|
||||
},
|
||||
/* .required_cpu = */ CPU_FEATURE_SME,
|
||||
/* .required_cpu = */ CPU_FEATURE_SME2,
|
||||
/* .lhs_type = */ GGML_TYPE_F32,
|
||||
/* .rhs_type = */ GGML_TYPE_F16,
|
||||
/* .op_type = */ GGML_TYPE_F32,
|
||||
@@ -749,6 +752,59 @@ static ggml_kleidiai_kernels gemm_gemv_kernels_q8[] = {
|
||||
/* .packed_stride_ex = */ &rhs_stride_fn4<kai_get_rhs_packed_stride_rhs_pack_nxk_qsi8cxp_qsi8cx_neon>,
|
||||
/* .pack_func_ex = */ &rhs_pack_scale_fn12<kai_run_rhs_pack_nxk_qsi8cxp_qsi8cx_neon>,
|
||||
},
|
||||
/* .required_cpu = */ CPU_FEATURE_SME2,
|
||||
/* .lhs_type = */ GGML_TYPE_F32,
|
||||
/* .rhs_type = */ GGML_TYPE_Q8_0,
|
||||
/* .op_type = */ GGML_TYPE_F32,
|
||||
},
|
||||
{
|
||||
/* SME GEMM (pure SME, no SME2 required) */
|
||||
{
|
||||
/* .get_m_step = */ kai_get_m_step_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_n_step = */ kai_get_n_step_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_mr = */ kai_get_mr_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_nr = */ kai_get_nr_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_kr = */ kai_get_kr_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_sr = */ kai_get_sr_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_dst_offset = */ kai_get_dst_offset_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_dst_size = */ kai_get_dst_size_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa,
|
||||
/* .get_lhs_offset_ex = */ &kernel_offs_fn2<kai_get_lhs_packed_offset_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa>,
|
||||
/* .get_rhs_packed_offset_ex = */ &kernel_offs_fn2<kai_get_rhs_packed_offset_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa>,
|
||||
/* .run_kernel_ex = */ &kernel_run_float_fn10<kai_run_matmul_clamp_f32_qai8dxp1vlx4_qsi8cxp4vlx4_1vlx4vl_sme_mopa>,
|
||||
},
|
||||
/* .gemm_lhs_info = */ {
|
||||
/* .get_offset = */ kai_get_lhs_offset_lhs_quant_pack_qai8dxp_f32,
|
||||
/* .get_packed_offset_ex = */ &lhs_offs_fn5<kai_get_lhs_packed_offset_lhs_quant_pack_qai8dxp_f32>,
|
||||
/* .packed_size_ex = */ &lhs_ps_fn5<kai_get_lhs_packed_size_lhs_quant_pack_qai8dxp_f32>,
|
||||
/* .pack_func_ex = */ &lhs_pack_float_fn9_no_bl<kai_run_lhs_quant_pack_qai8dxp_f32>,
|
||||
},
|
||||
/* SME GEMV (pure SME, no SME2 required) */
|
||||
{
|
||||
/* .get_m_step = */ kai_get_m_step_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_n_step = */ kai_get_n_step_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_mr = */ kai_get_mr_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_nr = */ kai_get_nr_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_kr = */ kai_get_kr_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_sr = */ kai_get_sr_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_dst_offset = */ kai_get_dst_offset_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_dst_size = */ kai_get_dst_size_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot,
|
||||
/* .get_lhs_offset_ex = */ &kernel_offs_fn2<kai_get_lhs_packed_offset_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot>,
|
||||
/* .get_rhs_packed_offset_ex = */ &kernel_offs_fn2<kai_get_rhs_packed_offset_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot>,
|
||||
/* .run_kernel_ex = */ &kernel_run_float_fn10<kai_run_matmul_clamp_f32_qai8dxp1x4_qsi8cxp4vlx4_1x4vl_sme_dot>,
|
||||
},
|
||||
/* .gemv_lhs_info = */ {
|
||||
/* .get_offset = */ kai_get_lhs_offset_lhs_quant_pack_qai8dxp_f32,
|
||||
/* .get_packed_offset_ex = */ &lhs_offs_fn5<kai_get_lhs_packed_offset_lhs_quant_pack_qai8dxp_f32>,
|
||||
/* .packed_size_ex = */ &lhs_ps_fn5<kai_get_lhs_packed_size_lhs_quant_pack_qai8dxp_f32>,
|
||||
/* .pack_func_ex = */ &lhs_pack_float_fn9_no_bl<kai_run_lhs_quant_pack_qai8dxp_f32>,
|
||||
},
|
||||
/* .rhs_info = */ {
|
||||
/* .packed_stride = */ kai_get_rhs_packed_stride_rhs_pack_nxk_qsi8cxp_qsi8cx_neon,
|
||||
/* .to_float = */ dequantize_row_qsi8cxp,
|
||||
/* .packed_size_ex = */ &rhs_ps_fn5<kai_get_rhs_packed_size_rhs_pack_nxk_qsi8cxp_qsi8cx_neon>,
|
||||
/* .packed_stride_ex = */ &rhs_stride_fn4<kai_get_rhs_packed_stride_rhs_pack_nxk_qsi8cxp_qsi8cx_neon>,
|
||||
/* .pack_func_ex = */ &rhs_pack_scale_fn12<kai_run_rhs_pack_nxk_qsi8cxp_qsi8cx_neon>,
|
||||
},
|
||||
/* .required_cpu = */ CPU_FEATURE_SME,
|
||||
/* .lhs_type = */ GGML_TYPE_F32,
|
||||
/* .rhs_type = */ GGML_TYPE_Q8_0,
|
||||
@@ -871,7 +927,7 @@ static ggml_kleidiai_kernels gemm_gemv_kernels_q8[] = {
|
||||
static ggml_kleidiai_kernels ggml_kleidiai_kernels_f32[] = {
|
||||
#if defined(__ARM_FEATURE_SME)
|
||||
{
|
||||
/* SME GEMM */
|
||||
/* SME2 GEMM */
|
||||
{
|
||||
/* .get_m_step = */ kai_get_m_step_matmul_clamp_f32_f32p2vlx1_f32p2vlx1biasf32_sme2_mopa,
|
||||
/* .get_n_step = */ kai_get_n_step_matmul_clamp_f32_f32p2vlx1_f32p2vlx1biasf32_sme2_mopa,
|
||||
@@ -918,6 +974,59 @@ static ggml_kleidiai_kernels ggml_kleidiai_kernels_f32[] = {
|
||||
/* .packed_stride_ex = */ &rhs_stride_fn1<kai_get_rhs_packed_stride_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme>,
|
||||
/* .pack_func_ex = */ &rhs_pack_fn13<kai_run_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme>,
|
||||
},
|
||||
/* .required_cpu = */ CPU_FEATURE_SME2,
|
||||
/* .lhs_type = */ GGML_TYPE_F32,
|
||||
/* .rhs_type = */ GGML_TYPE_F32,
|
||||
/* .op_type = */ GGML_TYPE_F32,
|
||||
},
|
||||
{
|
||||
/* SME GEMM */
|
||||
{
|
||||
/* .get_m_step = */ kai_get_m_step_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_n_step = */ kai_get_n_step_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_mr = */ kai_get_mr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_nr = */ kai_get_nr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_kr = */ kai_get_kr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_sr = */ kai_get_sr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_dst_offset = */ kai_get_dst_offset_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_dst_size = */ kai_get_dst_size_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_lhs_offset_ex = */ &kernel_offs_fn2<kai_get_lhs_packed_offset_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa>,
|
||||
/* .get_rhs_packed_offset_ex = */ &kernel_offs_fn2<kai_get_rhs_packed_offset_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa>,
|
||||
/* .run_kernel_ex = */ &kernel_run_fn10<kai_run_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa>,
|
||||
},
|
||||
/* .gemm_lhs_info = */ {
|
||||
/* .get_offset = */ kai_get_lhs_offset_lhs_pack_f32p2vlx1_f32_sme,
|
||||
/* .get_packed_offset_ex = */ &lhs_offs_fn5<kai_get_lhs_packed_offset_lhs_pack_f32p2vlx1_f32_sme>,
|
||||
/* .packed_size_ex = */ &lhs_ps_fn5<kai_get_lhs_packed_size_lhs_pack_f32p2vlx1_f32_sme>,
|
||||
/* .pack_func_ex = */ &lhs_pack_void_fn9<kai_run_lhs_pack_f32p2vlx1_f32_sme>,
|
||||
},
|
||||
/* SME GEMV */
|
||||
{
|
||||
/* .get_m_step = */ kai_get_m_step_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_n_step = */ kai_get_n_step_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_mr = */ kai_get_mr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_nr = */ kai_get_nr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_kr = */ kai_get_kr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_sr = */ kai_get_sr_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_dst_offset = */ kai_get_dst_offset_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_dst_size = */ kai_get_dst_size_matmul_clamp_f32_f32p2vlx1_f32p2vlx1b_2vlx2vl_sme_mopa,
|
||||
/* .get_lhs_offset_ex = */ nullptr,
|
||||
/* .get_rhs_packed_offset_ex = */ nullptr,
|
||||
/* .run_kernel_ex = */ nullptr,
|
||||
},
|
||||
/* .gemv_lhs_info = */ {
|
||||
/* .get_offset = */ kai_get_lhs_offset_lhs_pack_f32p2vlx1_f32_sme,
|
||||
/* .get_packed_offset_ex = */ &lhs_offs_fn5<kai_get_lhs_packed_offset_lhs_pack_f32p2vlx1_f32_sme>,
|
||||
/* .packed_size_ex = */ &lhs_ps_fn5<kai_get_lhs_packed_size_lhs_pack_f32p2vlx1_f32_sme>,
|
||||
/* .pack_func_ex = */ &lhs_pack_void_fn9<kai_run_lhs_pack_f32p2vlx1_f32_sme>,
|
||||
},
|
||||
/* .rhs_info = */ {
|
||||
/* .packed_stride = */ nullptr,
|
||||
/* .to_float = */ nullptr,
|
||||
/* .packed_size_ex = */ &rhs_ps_fn2<kai_get_rhs_packed_size_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme>,
|
||||
/* .packed_stride_ex = */ &rhs_stride_fn1<kai_get_rhs_packed_stride_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme>,
|
||||
/* .pack_func_ex = */ &rhs_pack_fn13<kai_run_rhs_pack_nxk_f32p2vlx1biasf32_f32_f32_sme>,
|
||||
},
|
||||
/* .required_cpu = */ CPU_FEATURE_SME,
|
||||
/* .lhs_type = */ GGML_TYPE_F32,
|
||||
/* .rhs_type = */ GGML_TYPE_F32,
|
||||
|
||||
@@ -11,7 +11,8 @@ enum cpu_feature {
|
||||
CPU_FEATURE_DOTPROD = 1,
|
||||
CPU_FEATURE_I8MM = 2,
|
||||
CPU_FEATURE_SVE = 4,
|
||||
CPU_FEATURE_SME = 8
|
||||
CPU_FEATURE_SME = 8,
|
||||
CPU_FEATURE_SME2 = 16
|
||||
};
|
||||
|
||||
inline cpu_feature& operator|=(cpu_feature& lhs, cpu_feature rhs) {
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#ifndef HWCAP2_SME2
|
||||
#define HWCAP2_SME2 (1UL << 37)
|
||||
#endif
|
||||
#elif defined(__APPLE__)
|
||||
#include <string_view>
|
||||
#include <sys/sysctl.h>
|
||||
@@ -66,9 +69,15 @@ struct ggml_kleidiai_context {
|
||||
int chunk_multiplier;
|
||||
} static ctx = { CPU_FEATURE_NONE, nullptr, nullptr, nullptr, 0, -1, 4 };
|
||||
|
||||
static inline bool is_sme_family(cpu_feature f) {
|
||||
return (f & (CPU_FEATURE_SME | CPU_FEATURE_SME2)) != CPU_FEATURE_NONE;
|
||||
}
|
||||
|
||||
static const char* cpu_feature_to_string(cpu_feature f) {
|
||||
if (f == CPU_FEATURE_NONE) {
|
||||
return "NONE";
|
||||
} else if ((f & CPU_FEATURE_SME2) == CPU_FEATURE_SME2) {
|
||||
return "SME2";
|
||||
} else if ((f & CPU_FEATURE_SME) == CPU_FEATURE_SME) {
|
||||
return "SME";
|
||||
} else if ((f & CPU_FEATURE_SVE) == CPU_FEATURE_SVE) {
|
||||
@@ -251,6 +260,18 @@ static void init_kleidiai_context(void) {
|
||||
|
||||
if (sme_cores > 0) {
|
||||
ctx.features |= CPU_FEATURE_SME;
|
||||
#if defined(__aarch64__) && defined(__linux__)
|
||||
// ARM guarantees SME2 implies SME, so only check SME2 when SME is enabled.
|
||||
if (getauxval(AT_HWCAP2) & HWCAP2_SME2) {
|
||||
ctx.features |= CPU_FEATURE_SME2;
|
||||
}
|
||||
#elif defined(__aarch64__) && defined(__APPLE__)
|
||||
int feat_sme2 = 0;
|
||||
size_t size = sizeof(feat_sme2);
|
||||
if (sysctlbyname("hw.optional.arm.FEAT_SME2", &feat_sme2, &size, NULL, 0) == 0 && feat_sme2) {
|
||||
ctx.features |= CPU_FEATURE_SME2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Kernel selection
|
||||
@@ -279,10 +300,13 @@ static void init_kleidiai_context(void) {
|
||||
ctx.sme_thread_cap = (ctx.features & CPU_FEATURE_SME) ? sme_cores : 0;
|
||||
|
||||
if (ctx.features & CPU_FEATURE_SME) {
|
||||
const bool has_sme2 = (ctx.features & CPU_FEATURE_SME2) != CPU_FEATURE_NONE;
|
||||
if (sme_env_set && sme_env_ok && sme_cores > 0) {
|
||||
GGML_LOG_INFO("kleidiai: SME enabled (GGML_KLEIDIAI_SME=%d override)\n", sme_cores);
|
||||
GGML_LOG_INFO("kleidiai: SME%s enabled (GGML_KLEIDIAI_SME=%d override)\n",
|
||||
has_sme2 ? "2" : "", sme_cores);
|
||||
} else {
|
||||
GGML_LOG_INFO("kleidiai: SME enabled (runtime-detected SME cores=%d)\n", sme_cores);
|
||||
GGML_LOG_INFO("kleidiai: SME%s enabled (runtime-detected SME cores=%d)\n",
|
||||
has_sme2 ? "2" : "", sme_cores);
|
||||
}
|
||||
} else {
|
||||
GGML_LOG_INFO("kleidiai: SME disabled\n");
|
||||
@@ -442,8 +466,8 @@ static int kleidiai_collect_kernel_chain_common(
|
||||
return count;
|
||||
}
|
||||
|
||||
if ((primary->required_cpu & CPU_FEATURE_SME) == CPU_FEATURE_SME) {
|
||||
const cpu_feature fallback_mask = static_cast<cpu_feature>(features & ~CPU_FEATURE_SME);
|
||||
if (is_sme_family(primary->required_cpu)) {
|
||||
const cpu_feature fallback_mask = static_cast<cpu_feature>(features & ~CPU_FEATURE_SME & ~CPU_FEATURE_SME2);
|
||||
if (fallback_mask != CPU_FEATURE_NONE) {
|
||||
ggml_kleidiai_kernels * fallback = select_fallback(fallback_mask);
|
||||
if (fallback && fallback != primary &&
|
||||
@@ -1054,14 +1078,14 @@ class tensor_traits : public ggml::cpu::tensor_traits {
|
||||
|
||||
int sme_slot = -1;
|
||||
for (int i = 0; i < runtime_count; ++i) {
|
||||
if ((runtime[i].kernels->required_cpu & CPU_FEATURE_SME) == CPU_FEATURE_SME) {
|
||||
if (is_sme_family(runtime[i].kernels->required_cpu)) {
|
||||
sme_slot = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
int non_sme_slot = -1;
|
||||
for (int i = 0; i < runtime_count; ++i) {
|
||||
if ((runtime[i].kernels->required_cpu & CPU_FEATURE_SME) != CPU_FEATURE_SME) {
|
||||
if (!is_sme_family(runtime[i].kernels->required_cpu)) {
|
||||
non_sme_slot = i;
|
||||
break;
|
||||
}
|
||||
@@ -1099,7 +1123,7 @@ class tensor_traits : public ggml::cpu::tensor_traits {
|
||||
// Recompute SME slot based on the collapsed runtime[0]
|
||||
sme_slot = -1;
|
||||
if (runtime_count > 0 &&
|
||||
(runtime[0].kernels->required_cpu & CPU_FEATURE_SME) == CPU_FEATURE_SME) {
|
||||
is_sme_family(runtime[0].kernels->required_cpu)) {
|
||||
sme_slot = 0;
|
||||
}
|
||||
}
|
||||
@@ -1695,6 +1719,7 @@ class extra_buffer_type : ggml::cpu::extra_buffer_type {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1703,6 +1728,20 @@ class extra_buffer_type : ggml::cpu::extra_buffer_type {
|
||||
if (op->src[0]->buffer && op->src[0]->buffer->buft == ggml_backend_cpu_kleidiai_buffer_type()) {
|
||||
return (ggml::cpu::tensor_traits *) op->src[0]->extra;
|
||||
} else {
|
||||
// KleidiAI only has kernels for Q4_0 and Q8_0. For a quantized weight of any
|
||||
// other type (K-quants, IQ) it declines the op and returns nullptr below, so
|
||||
// KleidiAI does not accelerate it. Another CPU backend may still take the op,
|
||||
// and this can run during graph planning, so the message says what KleidiAI
|
||||
// did rather than what ends up executing. Warn once per process.
|
||||
if (ggml_is_quantized(op->src[0]->type) &&
|
||||
op->src[0]->type != GGML_TYPE_Q4_0 && op->src[0]->type != GGML_TYPE_Q8_0) {
|
||||
static std::atomic<bool> warned(false);
|
||||
if (!warned.exchange(true)) {
|
||||
GGML_LOG_WARN("kleidiai: no kernel for tensor type %s, not accelerated by KleidiAI "
|
||||
"(kernels available for Q4_0 and Q8_0)\n",
|
||||
ggml_type_name(op->src[0]->type));
|
||||
}
|
||||
}
|
||||
if (op->src[0]->type != GGML_TYPE_F16) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -2329,7 +2329,7 @@ class tinyBLAS_Q0_PPC {
|
||||
mc = 32;
|
||||
nc = 32;
|
||||
kc = 32;
|
||||
n_chunk = 32
|
||||
n_chunk = 32;
|
||||
#endif
|
||||
int64_t n_aligned = 0;
|
||||
if (n % n_chunk == 0) {
|
||||
|
||||
@@ -10944,6 +10944,291 @@ void ggml_compute_forward_gated_delta_net(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ggml_compute_forward_dsv4_hc_comb
|
||||
|
||||
static void ggml_dsv4_hc_comb_norm_cols(float * comb, float eps) {
|
||||
constexpr int64_t hc = 4;
|
||||
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
float sum = eps;
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
sum += comb[idst + hc*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
comb[idst + hc*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_dsv4_hc_comb_norm_rows(float * comb, float eps) {
|
||||
constexpr int64_t hc = 4;
|
||||
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
float sum = eps;
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
sum += comb[idst + hc*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
comb[idst + hc*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_compute_forward_dsv4_hc_comb_f32(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
const ggml_tensor * mixes = dst->src[0];
|
||||
const ggml_tensor * scale = dst->src[1];
|
||||
const ggml_tensor * base = dst->src[2];
|
||||
|
||||
GGML_ASSERT(mixes->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(scale->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(base->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
constexpr int64_t hc = 4;
|
||||
constexpr int64_t comb_offset = 2*hc;
|
||||
constexpr int64_t hc_mix_dim = (2 + hc)*hc;
|
||||
|
||||
const int64_t n_tokens = mixes->ne[1];
|
||||
|
||||
GGML_ASSERT(mixes->ne[0] == hc_mix_dim);
|
||||
GGML_ASSERT(dst->ne[0] == hc);
|
||||
GGML_ASSERT(dst->ne[1] == hc);
|
||||
GGML_ASSERT(dst->ne[2] == n_tokens);
|
||||
GGML_ASSERT(scale->ne[0] >= 3);
|
||||
GGML_ASSERT(base->ne[0] == hc_mix_dim);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbm, mixes, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbs, scale, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbb, base, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const float eps = ggml_get_op_params_f32(dst, 0);
|
||||
const int32_t n_iter = ggml_get_op_params_i32(dst, 1);
|
||||
GGML_ASSERT(n_iter > 0);
|
||||
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int64_t dr = (n_tokens + nth - 1) / nth;
|
||||
const int64_t it0 = dr * ith;
|
||||
const int64_t it1 = MIN(it0 + dr, n_tokens);
|
||||
|
||||
const float scale_comb = *(const float *) ((const char *) scale->data + 2*nbs0);
|
||||
|
||||
for (int64_t it = it0; it < it1; ++it) {
|
||||
float comb[hc*hc];
|
||||
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
float max = -INFINITY;
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
const int64_t idx = idst + hc*isrc;
|
||||
const float xv = *(const float *) ((const char *) mixes->data + (comb_offset + idx)*nbm0 + it*nbm1);
|
||||
const float bv = *(const float *) ((const char *) base->data + (comb_offset + idx)*nbb0);
|
||||
const float v = xv * scale_comb + bv;
|
||||
comb[idx] = v;
|
||||
max = MAX(max, v);
|
||||
}
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
const int64_t idx = idst + hc*isrc;
|
||||
const float v = expf(comb[idx] - max);
|
||||
comb[idx] = v;
|
||||
sum += v;
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
const int64_t idx = idst + hc*isrc;
|
||||
comb[idx] = comb[idx] * inv_sum + eps;
|
||||
}
|
||||
}
|
||||
|
||||
ggml_dsv4_hc_comb_norm_cols(comb, eps);
|
||||
for (int32_t i = 1; i < n_iter; ++i) {
|
||||
ggml_dsv4_hc_comb_norm_rows(comb, eps);
|
||||
ggml_dsv4_hc_comb_norm_cols(comb, eps);
|
||||
}
|
||||
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
for (int64_t idst = 0; idst < hc; ++idst) {
|
||||
const int64_t idx = idst + hc*isrc;
|
||||
*(float *) ((char *) dst->data + idst*nbd0 + isrc*nbd1 + it*nbd2) = comb[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_compute_forward_dsv4_hc_comb(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
|
||||
switch (src0->type) {
|
||||
case GGML_TYPE_F32:
|
||||
{
|
||||
ggml_compute_forward_dsv4_hc_comb_f32(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ggml_compute_forward_dsv4_hc_pre
|
||||
|
||||
static void ggml_compute_forward_dsv4_hc_pre_f32(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * weights = dst->src[1];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(weights->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t hc = x->ne[1];
|
||||
const int64_t n_tokens = x->ne[2];
|
||||
|
||||
GGML_ASSERT(dst->ne[0] == n_embd);
|
||||
GGML_ASSERT(dst->ne[1] == n_tokens);
|
||||
GGML_ASSERT(weights->ne[0] == hc);
|
||||
GGML_ASSERT(weights->ne[1] == n_tokens);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbw, weights, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int64_t nr = n_embd * n_tokens;
|
||||
const int64_t dr = (nr + nth - 1) / nth;
|
||||
const int64_t ir0 = dr * ith;
|
||||
const int64_t ir1 = MIN(ir0 + dr, nr);
|
||||
|
||||
for (int64_t ir = ir0; ir < ir1; ++ir) {
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t it = ir / n_embd;
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int64_t ih = 0; ih < hc; ++ih) {
|
||||
const float xv = *(const float *) ((const char *) x->data + i0*nbx0 + ih*nbx1 + it*nbx2);
|
||||
const float wv = *(const float *) ((const char *) weights->data + ih*nbw0 + it*nbw1);
|
||||
sum += xv * wv;
|
||||
}
|
||||
|
||||
*(float *) ((char *) dst->data + i0*nbd0 + it*nbd1) = sum;
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_compute_forward_dsv4_hc_pre(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
|
||||
switch (src0->type) {
|
||||
case GGML_TYPE_F32:
|
||||
{
|
||||
ggml_compute_forward_dsv4_hc_pre_f32(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ggml_compute_forward_dsv4_hc_post
|
||||
|
||||
static void ggml_compute_forward_dsv4_hc_post_f32(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * residual = dst->src[1];
|
||||
const ggml_tensor * post = dst->src[2];
|
||||
const ggml_tensor * comb = dst->src[3];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(residual->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(post->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(comb->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t n_tokens = x->ne[1];
|
||||
const int64_t hc = residual->ne[1];
|
||||
|
||||
GGML_ASSERT(dst->ne[0] == n_embd);
|
||||
GGML_ASSERT(dst->ne[1] == hc);
|
||||
GGML_ASSERT(dst->ne[2] == n_tokens);
|
||||
GGML_ASSERT(residual->ne[0] == n_embd);
|
||||
GGML_ASSERT(residual->ne[2] == n_tokens);
|
||||
GGML_ASSERT(post->ne[0] == hc);
|
||||
GGML_ASSERT(post->ne[1] == n_tokens);
|
||||
GGML_ASSERT(comb->ne[0] == hc);
|
||||
GGML_ASSERT(comb->ne[1] == hc);
|
||||
GGML_ASSERT(comb->ne[2] == n_tokens);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbr, residual, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbp, post, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbc, comb, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int ith = params->ith;
|
||||
const int nth = params->nth;
|
||||
|
||||
const int64_t nr = n_embd * hc * n_tokens;
|
||||
const int64_t dr = (nr + nth - 1) / nth;
|
||||
const int64_t ir0 = dr * ith;
|
||||
const int64_t ir1 = MIN(ir0 + dr, nr);
|
||||
|
||||
for (int64_t ir = ir0; ir < ir1; ++ir) {
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t idst = (ir / n_embd) % hc;
|
||||
const int64_t it = ir / (n_embd * hc);
|
||||
|
||||
const float xv = *(const float *) ((const char *) x->data + i0*nbx0 + it*nbx1);
|
||||
const float pv = *(const float *) ((const char *) post->data + idst*nbp0 + it*nbp1);
|
||||
|
||||
float sum = xv * pv;
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
const float rv = *(const float *) ((const char *) residual->data + i0*nbr0 + isrc*nbr1 + it*nbr2);
|
||||
const float cv = *(const float *) ((const char *) comb->data + idst*nbc0 + isrc*nbc1 + it*nbc2);
|
||||
sum += rv * cv;
|
||||
}
|
||||
|
||||
*(float *) ((char *) dst->data + i0*nbd0 + idst*nbd1 + it*nbd2) = sum;
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_compute_forward_dsv4_hc_post(
|
||||
const ggml_compute_params * params,
|
||||
ggml_tensor * dst) {
|
||||
const ggml_tensor * src0 = dst->src[0];
|
||||
|
||||
switch (src0->type) {
|
||||
case GGML_TYPE_F32:
|
||||
{
|
||||
ggml_compute_forward_dsv4_hc_post_f32(params, dst);
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
GGML_ABORT("fatal error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ggml_compute_forward_rwkv_wkv7
|
||||
|
||||
static void ggml_compute_forward_rwkv_wkv7_f32(
|
||||
|
||||
@@ -106,6 +106,9 @@ void ggml_compute_forward_solve_tri(const struct ggml_compute_params * params, s
|
||||
void ggml_compute_forward_gla(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_gated_delta_net(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_lightning_indexer(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_dsv4_hc_comb(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_dsv4_hc_pre(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_dsv4_hc_post(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_map_custom1(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_map_custom2(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
void ggml_compute_forward_map_custom3(const struct ggml_compute_params * params, struct ggml_tensor * dst);
|
||||
|
||||
@@ -362,6 +362,15 @@ static bool blackwell_mma_available(const int cc) {
|
||||
ggml_cuda_highest_compiled_arch(cc) < GGML_CUDA_CC_RUBIN;
|
||||
}
|
||||
|
||||
// Checks whether the tensor's base data pointer and higher-dimensional strides are byte-aligned to `alignment` bytes.
|
||||
static bool ggml_cuda_is_aligned(const ggml_tensor * tensor, const size_t alignment) {
|
||||
GGML_ASSERT(tensor != nullptr);
|
||||
return (reinterpret_cast<uintptr_t>(tensor->data) % alignment) == 0 &&
|
||||
tensor->nb[1] % alignment == 0 &&
|
||||
tensor->nb[2] % alignment == 0 &&
|
||||
tensor->nb[3] % alignment == 0;
|
||||
}
|
||||
|
||||
static constexpr __device__ int ggml_cuda_get_physical_warp_size() {
|
||||
#if defined(GGML_USE_HIP) && (defined(__GFX9__) || defined(__GFX8__))
|
||||
return 64;
|
||||
@@ -937,6 +946,9 @@ static __device__ __forceinline__ uint2 fast_div_modulo(uint32_t n, const uint3
|
||||
|
||||
typedef void (*dequantize_kernel_t)(const void * vx, const int64_t ib, const int iqs, float2 & v);
|
||||
|
||||
template<typename dst_t>
|
||||
using dequantize_kq_t = void (*)(const void * vx, const int64_t ib, dst_t * y, const int tid);
|
||||
|
||||
static __device__ __forceinline__ float get_alibi_slope(
|
||||
const float max_bias, const uint32_t h, const uint32_t n_head_log2, const float m0, const float m1
|
||||
) {
|
||||
|
||||
+26
-277
@@ -140,358 +140,107 @@ static __global__ void dequantize_block_q4_1(const void * __restrict__ vx, dst_t
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_q2_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_q2_K * x = (const block_q2_K *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t n = tid/32;
|
||||
const int64_t l = tid - 32*n;
|
||||
const int64_t is = 8*n + l/16;
|
||||
|
||||
const uint8_t q = x[i].qs[32*n + l];
|
||||
dst_t * y = yy + i*QK_K + 128*n;
|
||||
|
||||
float dall = __low2half(x[i].dm);
|
||||
float dmin = __high2half(x[i].dm);
|
||||
y[l+ 0] = ggml_cuda_cast<dst_t>(dall * (x[i].scales[is+0] & 0xF) * ((q >> 0) & 3) - dmin * (x[i].scales[is+0] >> 4));
|
||||
y[l+32] = ggml_cuda_cast<dst_t>(dall * (x[i].scales[is+2] & 0xF) * ((q >> 2) & 3) - dmin * (x[i].scales[is+2] >> 4));
|
||||
y[l+64] = ggml_cuda_cast<dst_t>(dall * (x[i].scales[is+4] & 0xF) * ((q >> 4) & 3) - dmin * (x[i].scales[is+4] >> 4));
|
||||
y[l+96] = ggml_cuda_cast<dst_t>(dall * (x[i].scales[is+6] & 0xF) * ((q >> 6) & 3) - dmin * (x[i].scales[is+6] >> 4));
|
||||
dequantize_q2_K(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_q3_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_q3_K * x = (const block_q3_K *) vx;
|
||||
|
||||
const int64_t r = threadIdx.x/4;
|
||||
const int64_t tid = r/2;
|
||||
const int64_t is0 = r%2;
|
||||
const int64_t l0 = 16*is0 + 4*(threadIdx.x%4);
|
||||
const int64_t n = tid / 4;
|
||||
const int64_t j = tid - 4*n;
|
||||
|
||||
uint8_t m = 1 << (4*n + j);
|
||||
int64_t is = 8*n + 2*j + is0;
|
||||
int shift = 2*j;
|
||||
|
||||
int8_t us = is < 4 ? (x[i].scales[is-0] & 0xF) | (((x[i].scales[is+8] >> 0) & 3) << 4) :
|
||||
is < 8 ? (x[i].scales[is-0] & 0xF) | (((x[i].scales[is+4] >> 2) & 3) << 4) :
|
||||
is < 12 ? (x[i].scales[is-8] >> 4) | (((x[i].scales[is+0] >> 4) & 3) << 4) :
|
||||
(x[i].scales[is-8] >> 4) | (((x[i].scales[is-4] >> 6) & 3) << 4);
|
||||
float d_all = x[i].d;
|
||||
float dl = d_all * (us - 32);
|
||||
|
||||
dst_t * y = yy + i*QK_K + 128*n + 32*j;
|
||||
const uint8_t * q = x[i].qs + 32*n;
|
||||
const uint8_t * hm = x[i].hmask;
|
||||
|
||||
for (int l = l0; l < l0+4; ++l) {
|
||||
y[l] = ggml_cuda_cast<dst_t>(dl * ((int8_t)((q[l] >> shift) & 3) - ((hm[l] & m) ? 0 : 4)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __device__ void get_scale_min_k4(int j, const uint8_t * q, uint8_t & d, uint8_t & m) {
|
||||
if (j < 4) {
|
||||
d = q[j] & 63; m = q[j + 4] & 63;
|
||||
} else {
|
||||
d = (q[j+4] & 0xF) | ((q[j-4] >> 6) << 4);
|
||||
m = (q[j+4] >> 4) | ((q[j-0] >> 6) << 4);
|
||||
}
|
||||
dequantize_q3_K(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_q4_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const block_q4_K * x = (const block_q4_K *) vx;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
// assume 32 threads
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8;
|
||||
const int64_t ir = tid%8;
|
||||
const int64_t is = 2*il;
|
||||
const int64_t n = 4;
|
||||
|
||||
dst_t * y = yy + i*QK_K + 64*il + n*ir;
|
||||
|
||||
const float dall = __low2half(x[i].dm);
|
||||
const float dmin = __high2half(x[i].dm);
|
||||
|
||||
const uint8_t * q = x[i].qs + 32*il + n*ir;
|
||||
|
||||
uint8_t sc, m;
|
||||
get_scale_min_k4(is + 0, x[i].scales, sc, m);
|
||||
const float d1 = dall * sc; const float m1 = dmin * m;
|
||||
get_scale_min_k4(is + 1, x[i].scales, sc, m);
|
||||
const float d2 = dall * sc; const float m2 = dmin * m;
|
||||
for (int l = 0; l < n; ++l) {
|
||||
y[l + 0] = ggml_cuda_cast<dst_t>(d1 * (q[l] & 0xF) - m1);
|
||||
y[l +32] = ggml_cuda_cast<dst_t>(d2 * (q[l] >> 4) - m2);
|
||||
}
|
||||
dequantize_q4_K(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_q5_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const block_q5_K * x = (const block_q5_K *) vx;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
// assume 64 threads - this is very slightly better than the one below
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/16; // il is in 0...3
|
||||
const int64_t ir = tid%16; // ir is in 0...15
|
||||
const int64_t is = 2*il; // is is in 0...6
|
||||
|
||||
dst_t * y = yy + i*QK_K + 64*il + 2*ir;
|
||||
|
||||
const float dall = __low2half(x[i].dm);
|
||||
const float dmin = __high2half(x[i].dm);
|
||||
|
||||
const uint8_t * ql = x[i].qs + 32*il + 2*ir;
|
||||
const uint8_t * qh = x[i].qh + 2*ir;
|
||||
|
||||
uint8_t sc, m;
|
||||
get_scale_min_k4(is + 0, x[i].scales, sc, m);
|
||||
const float d1 = dall * sc; const float m1 = dmin * m;
|
||||
get_scale_min_k4(is + 1, x[i].scales, sc, m);
|
||||
const float d2 = dall * sc; const float m2 = dmin * m;
|
||||
|
||||
uint8_t hm = 1 << (2*il);
|
||||
y[ 0] = ggml_cuda_cast<dst_t>(d1 * ((ql[ 0] & 0xF) + (qh[ 0] & hm ? 16 : 0)) - m1);
|
||||
y[ 1] = ggml_cuda_cast<dst_t>(d1 * ((ql[ 1] & 0xF) + (qh[ 1] & hm ? 16 : 0)) - m1);
|
||||
hm <<= 1;
|
||||
y[32] = ggml_cuda_cast<dst_t>(d2 * ((ql[ 0] >> 4) + (qh[ 0] & hm ? 16 : 0)) - m2);
|
||||
y[33] = ggml_cuda_cast<dst_t>(d2 * ((ql[ 1] >> 4) + (qh[ 1] & hm ? 16 : 0)) - m2);
|
||||
dequantize_q5_K(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_q6_K(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const block_q6_K * x = (const block_q6_K *) vx;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
// assume 64 threads - this is very slightly better than the one below
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t ip = tid/32; // ip is 0 or 1
|
||||
const int64_t il = tid - 32*ip; // 0...32
|
||||
const int64_t is = 8*ip + il/16;
|
||||
|
||||
dst_t * y = yy + i*QK_K + 128*ip + il;
|
||||
|
||||
const float d = x[i].d;
|
||||
|
||||
const uint8_t * ql = x[i].ql + 64*ip + il;
|
||||
const uint8_t qh = x[i].qh[32*ip + il];
|
||||
const int8_t * sc = x[i].scales + is;
|
||||
|
||||
y[ 0] = ggml_cuda_cast<dst_t>(d * sc[0] * ((int8_t)((ql[ 0] & 0xF) | (((qh >> 0) & 3) << 4)) - 32));
|
||||
y[32] = ggml_cuda_cast<dst_t>(d * sc[2] * ((int8_t)((ql[32] & 0xF) | (((qh >> 2) & 3) << 4)) - 32));
|
||||
y[64] = ggml_cuda_cast<dst_t>(d * sc[4] * ((int8_t)((ql[ 0] >> 4) | (((qh >> 4) & 3) << 4)) - 32));
|
||||
y[96] = ggml_cuda_cast<dst_t>(d * sc[6] * ((int8_t)((ql[32] >> 4) | (((qh >> 6) & 3) << 4)) - 32));
|
||||
dequantize_q6_K(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq2_xxs(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq2_xxs * x = (const block_iq2_xxs *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const uint16_t * q2 = x[i].qs + 4*ib;
|
||||
const uint8_t * aux8 = (const uint8_t *)q2;
|
||||
const uint8_t * grid = (const uint8_t *)(iq2xxs_grid + aux8[il]);
|
||||
const uint32_t aux32 = q2[2] | (q2[3] << 16);
|
||||
const float d = (float)x[i].d * (0.5f + (aux32 >> 28)) * 0.25f;
|
||||
const uint8_t signs = ksigns_iq2xs[(aux32 >> 7*il) & 127];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f));
|
||||
}
|
||||
dequantize_iq2_xxs(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq2_xs(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq2_xs * x = (const block_iq2_xs *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const uint16_t * q2 = x[i].qs + 4*ib;
|
||||
const uint8_t * grid = (const uint8_t *)(iq2xs_grid + (q2[il] & 511));
|
||||
const float d = (float)x[i].d * (0.5f + ((x[i].scales[ib] >> 4*(il/2)) & 0xf)) * 0.25f;
|
||||
const uint8_t signs = ksigns_iq2xs[q2[il] >> 9];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f));
|
||||
}
|
||||
dequantize_iq2_xs(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq2_s(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq2_s * x = (const block_iq2_s *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const uint8_t * grid = (const uint8_t *)(iq2s_grid + (x[i].qs[4*ib+il] | ((x[i].qh[ib] << (8-2*il)) & 0x300)));
|
||||
const float d = (float)x[i].d * (0.5f + ((x[i].scales[ib] >> 4*(il/2)) & 0xf)) * 0.25f;
|
||||
const uint8_t signs = x[i].qs[QK_K/8+4*ib+il];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f));
|
||||
}
|
||||
dequantize_iq2_s(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq3_xxs(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq3_xxs * x = (const block_iq3_xxs *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const uint8_t * q3 = x[i].qs + 8*ib;
|
||||
const uint16_t * gas = (const uint16_t *)(x[i].qs + QK_K/4) + 2*ib;
|
||||
const uint8_t * grid1 = (const uint8_t *)(iq3xxs_grid + q3[2*il+0]);
|
||||
const uint8_t * grid2 = (const uint8_t *)(iq3xxs_grid + q3[2*il+1]);
|
||||
const uint32_t aux32 = gas[0] | (gas[1] << 16);
|
||||
const float d = (float)x[i].d * (0.5f + (aux32 >> 28)) * 0.5f;
|
||||
const uint8_t signs = ksigns_iq2xs[(aux32 >> 7*il) & 127];
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+0] = ggml_cuda_cast<dst_t>(d * grid1[j] * (signs & kmask_iq2xs[j+0] ? -1.f : 1.f));
|
||||
y[j+4] = ggml_cuda_cast<dst_t>(d * grid2[j] * (signs & kmask_iq2xs[j+4] ? -1.f : 1.f));
|
||||
}
|
||||
dequantize_iq3_xxs(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq3_s(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq3_s * x = (const block_iq3_s *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const uint8_t * qs = x[i].qs + 8*ib;
|
||||
const uint8_t * grid1 = (const uint8_t *)(iq3s_grid + (qs[2*il+0] | ((x[i].qh[ib] << (8-2*il)) & 256)));
|
||||
const uint8_t * grid2 = (const uint8_t *)(iq3s_grid + (qs[2*il+1] | ((x[i].qh[ib] << (7-2*il)) & 256)));
|
||||
const float d = (float)x[i].d * (1 + 2*((x[i].scales[ib/2] >> 4*(ib%2)) & 0xf));
|
||||
const uint8_t signs = x[i].signs[4*ib + il];
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+0] = ggml_cuda_cast<dst_t>(d * grid1[j] * (signs & kmask_iq2xs[j+0] ? -1.f : 1.f));
|
||||
y[j+4] = ggml_cuda_cast<dst_t>(d * grid2[j] * (signs & kmask_iq2xs[j+4] ? -1.f : 1.f));
|
||||
}
|
||||
dequantize_iq3_s(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq1_s(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq1_s * x = (const block_iq1_s *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const float delta = x[i].qh[ib] & 0x8000 ? -1 - IQ1S_DELTA : -1 + IQ1S_DELTA;
|
||||
const float d = (float)x[i].d * (2*((x[i].qh[ib] >> 12) & 7) + 1);
|
||||
uint32_t grid32[2]; const int8_t * q = (const int8_t *)grid32;
|
||||
grid32[0] = iq1s_grid_gpu[x[i].qs[4*ib+il] | (((x[i].qh[ib] >> 3*il) & 7) << 8)];
|
||||
grid32[1] = (grid32[0] >> 4) & 0x0f0f0f0f;
|
||||
grid32[0] &= 0x0f0f0f0f;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * (q[j] + delta));
|
||||
}
|
||||
dequantize_iq1_s(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq1_m(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq1_m * x = (const block_iq1_m *) vx;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 8*il;
|
||||
const uint16_t * sc = (const uint16_t *)x[i].scales;
|
||||
iq1m_scale_t scale;
|
||||
scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000);
|
||||
const int64_t ib16 = 2*ib + il/2; // sc[ib16/4] >> 3*(ib16%4) -> sc[ib/2] >> 3*((2*ib+il/2)%4);
|
||||
const float d = (float)scale.f16 * (2*((sc[ib16/4] >> 3*(ib16%4)) & 0x7) + 1);
|
||||
const float delta = x[i].qh[2*ib+il/2] & (0x08 << 4*(il%2)) ? -1 - IQ1M_DELTA : -1 + IQ1M_DELTA;
|
||||
uint32_t grid32[2]; const int8_t * q = (const int8_t *)grid32;
|
||||
grid32[0] = iq1s_grid_gpu[x[i].qs[4*ib+il] | (((x[i].qh[2*ib+il/2] >> 4*(il%2)) & 7) << 8)];
|
||||
grid32[1] = (grid32[0] >> 4) & 0x0f0f0f0f;
|
||||
grid32[0] &= 0x0f0f0f0f;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * (q[j] + delta));
|
||||
}
|
||||
dequantize_iq1_m(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq4_nl(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq4_nl * x = (const block_iq4_nl *) vx + i*(QK_K/QK4_NL);
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 4*il;
|
||||
const uint8_t * q4 = x[ib].qs + 4*il;
|
||||
const float d = (float)x[ib].d;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+ 0] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] & 0xf]);
|
||||
y[j+16] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] >> 4]);
|
||||
}
|
||||
dequantize_iq4_nl(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_iq4_xs(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_iq4_xs * x = (const block_iq4_xs *)vx;
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 4*il;
|
||||
const uint8_t * q4 = x[i].qs + 16*ib + 4*il;
|
||||
const float d = (float)x[i].d * ((((x[i].scales_l[ib/2] >> 4*(ib%2)) & 0xf) | (((x[i].scales_h >> 2*ib) & 3) << 4)) - 32);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+ 0] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] & 0xf]);
|
||||
y[j+16] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] >> 4]);
|
||||
}
|
||||
dequantize_iq4_xs(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void dequantize_block_mxfp4(const void * __restrict__ vx, dst_t * __restrict__ yy) {
|
||||
const int64_t i = blockIdx.x;
|
||||
|
||||
const int64_t i = blockIdx.x;
|
||||
const block_mxfp4 * x = (const block_mxfp4 *) vx + i*(QK_K/QK_MXFP4);
|
||||
|
||||
const int64_t tid = threadIdx.x;
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + i*QK_K + 32*ib + 4*il;
|
||||
const uint8_t * q4 = x[ib].qs + 4*il;
|
||||
const float d = ggml_cuda_e8m0_to_fp32(x[ib].e);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+ 0] = ggml_cuda_cast<dst_t>(d * kvalues_mxfp4[q4[j] & 0xf]*0.5f);
|
||||
y[j+16] = ggml_cuda_cast<dst_t>(d * kvalues_mxfp4[q4[j] >> 4]*0.5f);
|
||||
}
|
||||
dequantize_mxfp4(vx, i, yy + i*QK_K, threadIdx.x);
|
||||
}
|
||||
|
||||
template <int qk, int qr, dequantize_kernel_t dequantize_kernel, typename dst_t>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "common.cuh"
|
||||
#include "convert.cuh"
|
||||
|
||||
static __device__ __forceinline__ void dequantize_q1_0(const void * vx, const int64_t ib, const int iqs, float2 & v){
|
||||
const block_q1_0 * x = (const block_q1_0 *) vx;
|
||||
@@ -97,3 +98,335 @@ static __device__ __forceinline__ void dequantize_q8_0(const void * vx, const in
|
||||
v.x *= d;
|
||||
v.y *= d;
|
||||
}
|
||||
|
||||
//================================== k-quants
|
||||
|
||||
// Each call dequantizes one super-block of QK_K values into y using the
|
||||
// thread layout of the caller: 32 threads for q4_K, 64 threads otherwise.
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_q2_K(const void * vx, const int64_t ib, dst_t * yy, const int tid) {
|
||||
const block_q2_K * x = (const block_q2_K *) vx;
|
||||
|
||||
const int64_t n = tid/32;
|
||||
const int64_t l = tid - 32*n;
|
||||
const int64_t is = 8*n + l/16;
|
||||
|
||||
const uint8_t q = x[ib].qs[32*n + l];
|
||||
dst_t * y = yy + 128*n;
|
||||
|
||||
float dall = __low2half(x[ib].dm);
|
||||
float dmin = __high2half(x[ib].dm);
|
||||
y[l+ 0] = ggml_cuda_cast<dst_t>(dall * (x[ib].scales[is+0] & 0xF) * ((q >> 0) & 3) - dmin * (x[ib].scales[is+0] >> 4));
|
||||
y[l+32] = ggml_cuda_cast<dst_t>(dall * (x[ib].scales[is+2] & 0xF) * ((q >> 2) & 3) - dmin * (x[ib].scales[is+2] >> 4));
|
||||
y[l+64] = ggml_cuda_cast<dst_t>(dall * (x[ib].scales[is+4] & 0xF) * ((q >> 4) & 3) - dmin * (x[ib].scales[is+4] >> 4));
|
||||
y[l+96] = ggml_cuda_cast<dst_t>(dall * (x[ib].scales[is+6] & 0xF) * ((q >> 6) & 3) - dmin * (x[ib].scales[is+6] >> 4));
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_q3_K(const void * vx, const int64_t ib, dst_t * yy, const int tid) {
|
||||
const block_q3_K * x = (const block_q3_K *) vx;
|
||||
|
||||
const int64_t r = tid/4;
|
||||
const int64_t t = r/2;
|
||||
const int64_t is0 = r%2;
|
||||
const int64_t l0 = 16*is0 + 4*(tid%4);
|
||||
const int64_t n = t / 4;
|
||||
const int64_t j = t - 4*n;
|
||||
|
||||
uint8_t m = 1 << (4*n + j);
|
||||
int64_t is = 8*n + 2*j + is0;
|
||||
int shift = 2*j;
|
||||
|
||||
int8_t us = is < 4 ? (x[ib].scales[is-0] & 0xF) | (((x[ib].scales[is+8] >> 0) & 3) << 4) :
|
||||
is < 8 ? (x[ib].scales[is-0] & 0xF) | (((x[ib].scales[is+4] >> 2) & 3) << 4) :
|
||||
is < 12 ? (x[ib].scales[is-8] >> 4) | (((x[ib].scales[is+0] >> 4) & 3) << 4) :
|
||||
(x[ib].scales[is-8] >> 4) | (((x[ib].scales[is-4] >> 6) & 3) << 4);
|
||||
float d_all = x[ib].d;
|
||||
float dl = d_all * (us - 32);
|
||||
|
||||
dst_t * y = yy + 128*n + 32*j;
|
||||
const uint8_t * q = x[ib].qs + 32*n;
|
||||
const uint8_t * hm = x[ib].hmask;
|
||||
|
||||
for (int l = l0; l < l0+4; ++l) {
|
||||
y[l] = ggml_cuda_cast<dst_t>(dl * ((int8_t)((q[l] >> shift) & 3) - ((hm[l] & m) ? 0 : 4)));
|
||||
}
|
||||
}
|
||||
|
||||
static inline __device__ void get_scale_min_k4(int j, const uint8_t * q, uint8_t & d, uint8_t & m) {
|
||||
if (j < 4) {
|
||||
d = q[j] & 63; m = q[j + 4] & 63;
|
||||
} else {
|
||||
d = (q[j+4] & 0xF) | ((q[j-4] >> 6) << 4);
|
||||
m = (q[j+4] >> 4) | ((q[j-0] >> 6) << 4);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_q4_K(const void * vx, const int64_t ib, dst_t * yy, const int tid) {
|
||||
const block_q4_K * x = (const block_q4_K *) vx;
|
||||
|
||||
// assume 32 threads
|
||||
const int64_t il = tid/8;
|
||||
const int64_t ir = tid%8;
|
||||
const int64_t is = 2*il;
|
||||
const int64_t n = 4;
|
||||
|
||||
dst_t * y = yy + 64*il + n*ir;
|
||||
|
||||
const float dall = __low2half(x[ib].dm);
|
||||
const float dmin = __high2half(x[ib].dm);
|
||||
|
||||
const uint8_t * q = x[ib].qs + 32*il + n*ir;
|
||||
|
||||
uint8_t sc, m;
|
||||
get_scale_min_k4(is + 0, x[ib].scales, sc, m);
|
||||
const float d1 = dall * sc; const float m1 = dmin * m;
|
||||
get_scale_min_k4(is + 1, x[ib].scales, sc, m);
|
||||
const float d2 = dall * sc; const float m2 = dmin * m;
|
||||
for (int l = 0; l < n; ++l) {
|
||||
y[l + 0] = ggml_cuda_cast<dst_t>(d1 * (q[l] & 0xF) - m1);
|
||||
y[l +32] = ggml_cuda_cast<dst_t>(d2 * (q[l] >> 4) - m2);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_q5_K(const void * vx, const int64_t ib, dst_t * yy, const int tid) {
|
||||
const block_q5_K * x = (const block_q5_K *) vx;
|
||||
|
||||
// assume 64 threads - this is very slightly better than the one below
|
||||
const int64_t il = tid/16; // il is in 0...3
|
||||
const int64_t ir = tid%16; // ir is in 0...15
|
||||
const int64_t is = 2*il; // is is in 0...6
|
||||
|
||||
dst_t * y = yy + 64*il + 2*ir;
|
||||
|
||||
const float dall = __low2half(x[ib].dm);
|
||||
const float dmin = __high2half(x[ib].dm);
|
||||
|
||||
const uint8_t * ql = x[ib].qs + 32*il + 2*ir;
|
||||
const uint8_t * qh = x[ib].qh + 2*ir;
|
||||
|
||||
uint8_t sc, m;
|
||||
get_scale_min_k4(is + 0, x[ib].scales, sc, m);
|
||||
const float d1 = dall * sc; const float m1 = dmin * m;
|
||||
get_scale_min_k4(is + 1, x[ib].scales, sc, m);
|
||||
const float d2 = dall * sc; const float m2 = dmin * m;
|
||||
|
||||
uint8_t hm = 1 << (2*il);
|
||||
y[ 0] = ggml_cuda_cast<dst_t>(d1 * ((ql[ 0] & 0xF) + (qh[ 0] & hm ? 16 : 0)) - m1);
|
||||
y[ 1] = ggml_cuda_cast<dst_t>(d1 * ((ql[ 1] & 0xF) + (qh[ 1] & hm ? 16 : 0)) - m1);
|
||||
hm <<= 1;
|
||||
y[32] = ggml_cuda_cast<dst_t>(d2 * ((ql[ 0] >> 4) + (qh[ 0] & hm ? 16 : 0)) - m2);
|
||||
y[33] = ggml_cuda_cast<dst_t>(d2 * ((ql[ 1] >> 4) + (qh[ 1] & hm ? 16 : 0)) - m2);
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_q6_K(const void * vx, const int64_t ib, dst_t * yy, const int tid) {
|
||||
const block_q6_K * x = (const block_q6_K *) vx;
|
||||
|
||||
// assume 64 threads - this is very slightly better than the one below
|
||||
const int64_t ip = tid/32; // ip is 0 or 1
|
||||
const int64_t il = tid - 32*ip; // 0...32
|
||||
const int64_t is = 8*ip + il/16;
|
||||
|
||||
dst_t * y = yy + 128*ip + il;
|
||||
|
||||
const float d = x[ib].d;
|
||||
|
||||
const uint8_t * ql = x[ib].ql + 64*ip + il;
|
||||
const uint8_t qh = x[ib].qh[32*ip + il];
|
||||
const int8_t * sc = x[ib].scales + is;
|
||||
|
||||
y[ 0] = ggml_cuda_cast<dst_t>(d * sc[0] * ((int8_t)((ql[ 0] & 0xF) | (((qh >> 0) & 3) << 4)) - 32));
|
||||
y[32] = ggml_cuda_cast<dst_t>(d * sc[2] * ((int8_t)((ql[32] & 0xF) | (((qh >> 2) & 3) << 4)) - 32));
|
||||
y[64] = ggml_cuda_cast<dst_t>(d * sc[4] * ((int8_t)((ql[ 0] >> 4) | (((qh >> 4) & 3) << 4)) - 32));
|
||||
y[96] = ggml_cuda_cast<dst_t>(d * sc[6] * ((int8_t)((ql[32] >> 4) | (((qh >> 6) & 3) << 4)) - 32));
|
||||
}
|
||||
|
||||
//================================== i-quants
|
||||
|
||||
// Each call dequantizes one super-block of QK_K values into y with 32
|
||||
// threads; iq4_nl packs QK_K/QK4_NL sub-blocks per super-block.
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq2_xxs(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq2_xxs * x = (const block_iq2_xxs *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const uint16_t * q2 = x[ibs].qs + 4*ib;
|
||||
const uint8_t * aux8 = (const uint8_t *)q2;
|
||||
const uint8_t * grid = (const uint8_t *)(iq2xxs_grid + aux8[il]);
|
||||
const uint32_t aux32 = q2[2] | (q2[3] << 16);
|
||||
const float d = (float)x[ibs].d * (0.5f + (aux32 >> 28)) * 0.25f;
|
||||
const uint8_t signs = ksigns_iq2xs[(aux32 >> 7*il) & 127];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq2_xs(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq2_xs * x = (const block_iq2_xs *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const uint16_t * q2 = x[ibs].qs + 4*ib;
|
||||
const uint8_t * grid = (const uint8_t *)(iq2xs_grid + (q2[il] & 511));
|
||||
const float d = (float)x[ibs].d * (0.5f + ((x[ibs].scales[ib] >> 4*(il/2)) & 0xf)) * 0.25f;
|
||||
const uint8_t signs = ksigns_iq2xs[q2[il] >> 9];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq2_s(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq2_s * x = (const block_iq2_s *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const uint8_t * grid = (const uint8_t *)(iq2s_grid + (x[ibs].qs[4*ib+il] | ((x[ibs].qh[ib] << (8-2*il)) & 0x300)));
|
||||
const float d = (float)x[ibs].d * (0.5f + ((x[ibs].scales[ib] >> 4*(il/2)) & 0xf)) * 0.25f;
|
||||
const uint8_t signs = x[ibs].qs[QK_K/8+4*ib+il];
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * grid[j] * (signs & kmask_iq2xs[j] ? -1.f : 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq3_xxs(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq3_xxs * x = (const block_iq3_xxs *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const uint8_t * q3 = x[ibs].qs + 8*ib;
|
||||
const uint16_t * gas = (const uint16_t *)(x[ibs].qs + QK_K/4) + 2*ib;
|
||||
const uint8_t * grid1 = (const uint8_t *)(iq3xxs_grid + q3[2*il+0]);
|
||||
const uint8_t * grid2 = (const uint8_t *)(iq3xxs_grid + q3[2*il+1]);
|
||||
const uint32_t aux32 = gas[0] | (gas[1] << 16);
|
||||
const float d = (float)x[ibs].d * (0.5f + (aux32 >> 28)) * 0.5f;
|
||||
const uint8_t signs = ksigns_iq2xs[(aux32 >> 7*il) & 127];
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+0] = ggml_cuda_cast<dst_t>(d * grid1[j] * (signs & kmask_iq2xs[j+0] ? -1.f : 1.f));
|
||||
y[j+4] = ggml_cuda_cast<dst_t>(d * grid2[j] * (signs & kmask_iq2xs[j+4] ? -1.f : 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq3_s(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq3_s * x = (const block_iq3_s *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const uint8_t * qs = x[ibs].qs + 8*ib;
|
||||
const uint8_t * grid1 = (const uint8_t *)(iq3s_grid + (qs[2*il+0] | ((x[ibs].qh[ib] << (8-2*il)) & 256)));
|
||||
const uint8_t * grid2 = (const uint8_t *)(iq3s_grid + (qs[2*il+1] | ((x[ibs].qh[ib] << (7-2*il)) & 256)));
|
||||
const float d = (float)x[ibs].d * (1 + 2*((x[ibs].scales[ib/2] >> 4*(ib%2)) & 0xf));
|
||||
const uint8_t signs = x[ibs].signs[4*ib + il];
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+0] = ggml_cuda_cast<dst_t>(d * grid1[j] * (signs & kmask_iq2xs[j+0] ? -1.f : 1.f));
|
||||
y[j+4] = ggml_cuda_cast<dst_t>(d * grid2[j] * (signs & kmask_iq2xs[j+4] ? -1.f : 1.f));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq1_s(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq1_s * x = (const block_iq1_s *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const float delta = x[ibs].qh[ib] & 0x8000 ? -1 - IQ1S_DELTA : -1 + IQ1S_DELTA;
|
||||
const float d = (float)x[ibs].d * (2*((x[ibs].qh[ib] >> 12) & 7) + 1);
|
||||
uint32_t grid32[2]; const int8_t * q = (const int8_t *)grid32;
|
||||
grid32[0] = iq1s_grid_gpu[x[ibs].qs[4*ib+il] | (((x[ibs].qh[ib] >> 3*il) & 7) << 8)];
|
||||
grid32[1] = (grid32[0] >> 4) & 0x0f0f0f0f;
|
||||
grid32[0] &= 0x0f0f0f0f;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * (q[j] + delta));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq1_m(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq1_m * x = (const block_iq1_m *) vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 8*il;
|
||||
const uint16_t * sc = (const uint16_t *)x[ibs].scales;
|
||||
iq1m_scale_t scale;
|
||||
scale.u16 = (sc[0] >> 12) | ((sc[1] >> 8) & 0x00f0) | ((sc[2] >> 4) & 0x0f00) | (sc[3] & 0xf000);
|
||||
const int64_t ib16 = 2*ib + il/2; // sc[ib16/4] >> 3*(ib16%4) -> sc[ib/2] >> 3*((2*ib+il/2)%4);
|
||||
const float d = (float)scale.f16 * (2*((sc[ib16/4] >> 3*(ib16%4)) & 0x7) + 1);
|
||||
const float delta = x[ibs].qh[2*ib+il/2] & (0x08 << 4*(il%2)) ? -1 - IQ1M_DELTA : -1 + IQ1M_DELTA;
|
||||
uint32_t grid32[2]; const int8_t * q = (const int8_t *)grid32;
|
||||
grid32[0] = iq1s_grid_gpu[x[ibs].qs[4*ib+il] | (((x[ibs].qh[2*ib+il/2] >> 4*(il%2)) & 7) << 8)];
|
||||
grid32[1] = (grid32[0] >> 4) & 0x0f0f0f0f;
|
||||
grid32[0] &= 0x0f0f0f0f;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
y[j] = ggml_cuda_cast<dst_t>(d * (q[j] + delta));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq4_nl(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_iq4_nl * x = (const block_iq4_nl *) vx + ibs*(QK_K/QK4_NL);
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 4*il;
|
||||
const uint8_t * q4 = x[ib].qs + 4*il;
|
||||
const float d = (float)x[ib].d;
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+ 0] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] & 0xf]);
|
||||
y[j+16] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] >> 4]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_iq4_xs(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
const block_iq4_xs * x = (const block_iq4_xs *)vx;
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 4*il;
|
||||
const uint8_t * q4 = x[ibs].qs + 16*ib + 4*il;
|
||||
const float d = (float)x[ibs].d * ((((x[ibs].scales_l[ib/2] >> 4*(ib%2)) & 0xf) | (((x[ibs].scales_h >> 2*ib) & 3) << 4)) - 32);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+ 0] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] & 0xf]);
|
||||
y[j+16] = ggml_cuda_cast<dst_t>(d * kvalues_iq4nl[q4[j] >> 4]);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __device__ __forceinline__ void dequantize_mxfp4(const void * vx, const int64_t ibs, dst_t * yy, const int tid) {
|
||||
|
||||
const block_mxfp4 * x = (const block_mxfp4 *) vx + ibs*(QK_K/QK_MXFP4);
|
||||
|
||||
const int64_t il = tid/8; // 0...3
|
||||
const int64_t ib = tid%8; // 0...7
|
||||
dst_t * y = yy + 32*ib + 4*il;
|
||||
const uint8_t * q4 = x[ib].qs + 4*il;
|
||||
const float d = ggml_cuda_e8m0_to_fp32(x[ib].e);
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
y[j+ 0] = ggml_cuda_cast<dst_t>(d * kvalues_mxfp4[q4[j] & 0xf]*0.5f);
|
||||
y[j+16] = ggml_cuda_cast<dst_t>(d * kvalues_mxfp4[q4[j] >> 4]*0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,294 @@
|
||||
#include "common.cuh"
|
||||
#include "dsv4-hc.cuh"
|
||||
|
||||
|
||||
static constexpr int DSV4_HC = 4;
|
||||
|
||||
|
||||
static __device__ void dsv4_hc_comb_norm_cols(float * comb, float eps) {
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
float sum = eps;
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
sum += comb[idst + DSV4_HC*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
comb[idst + DSV4_HC*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __device__ void dsv4_hc_comb_norm_rows(float * comb, float eps) {
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
float sum = eps;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
sum += comb[idst + DSV4_HC*isrc];
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
comb[idst + DSV4_HC*isrc] *= inv_sum;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __global__ void dsv4_hc_comb_f32(
|
||||
const float * mixes,
|
||||
const float * scale,
|
||||
const float * base,
|
||||
float * dst,
|
||||
int64_t n_tokens,
|
||||
int64_t sm0,
|
||||
int64_t sm1,
|
||||
int64_t ss0,
|
||||
int64_t sb0,
|
||||
int64_t sd0,
|
||||
int64_t sd1,
|
||||
int64_t sd2,
|
||||
float eps,
|
||||
int32_t n_iter) {
|
||||
constexpr int comb_offset = 2*DSV4_HC;
|
||||
|
||||
ggml_cuda_pdl_lc();
|
||||
const int64_t it = (int64_t) blockIdx.x * blockDim.x + threadIdx.x;
|
||||
|
||||
if (it >= n_tokens) {
|
||||
return;
|
||||
}
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
|
||||
const float scale_comb = scale[2*ss0];
|
||||
float comb[DSV4_HC*DSV4_HC];
|
||||
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
float max = -INFINITY;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
const float v = mixes[(comb_offset + idx)*sm0 + it*sm1] * scale_comb + base[(comb_offset + idx)*sb0];
|
||||
comb[idx] = v;
|
||||
max = fmaxf(max, v);
|
||||
}
|
||||
|
||||
float sum = 0.0f;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
const float v = expf(comb[idx] - max);
|
||||
comb[idx] = v;
|
||||
sum += v;
|
||||
}
|
||||
|
||||
const float inv_sum = 1.0f / sum;
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
comb[idx] = comb[idx] * inv_sum + eps;
|
||||
}
|
||||
}
|
||||
|
||||
dsv4_hc_comb_norm_cols(comb, eps);
|
||||
for (int32_t i = 1; i < n_iter; ++i) {
|
||||
dsv4_hc_comb_norm_rows(comb, eps);
|
||||
dsv4_hc_comb_norm_cols(comb, eps);
|
||||
}
|
||||
|
||||
for (int isrc = 0; isrc < DSV4_HC; ++isrc) {
|
||||
for (int idst = 0; idst < DSV4_HC; ++idst) {
|
||||
const int idx = idst + DSV4_HC*isrc;
|
||||
dst[idst*sd0 + isrc*sd1 + it*sd2] = comb[idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __global__ void dsv4_hc_pre_f32(
|
||||
const float * x,
|
||||
const float * weights,
|
||||
float * dst,
|
||||
int64_t n_embd,
|
||||
int64_t hc,
|
||||
int64_t n_tokens,
|
||||
int64_t sx0,
|
||||
int64_t sx1,
|
||||
int64_t sx2,
|
||||
int64_t sw0,
|
||||
int64_t sw1,
|
||||
int64_t sd0,
|
||||
int64_t sd1) {
|
||||
ggml_cuda_pdl_lc();
|
||||
const int64_t ir = (int64_t) blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int64_t nr = n_embd * n_tokens;
|
||||
|
||||
if (ir >= nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t it = ir / n_embd;
|
||||
|
||||
float sum = x[i0*sx0 + it*sx2] * weights[it*sw1];
|
||||
for (int64_t ih = 1; ih < hc; ++ih) {
|
||||
const float xv = x[i0*sx0 + ih*sx1 + it*sx2];
|
||||
const float wv = weights[ih*sw0 + it*sw1];
|
||||
sum += xv * wv;
|
||||
}
|
||||
|
||||
dst[i0*sd0 + it*sd1] = sum;
|
||||
}
|
||||
|
||||
static __global__ void dsv4_hc_post_f32(
|
||||
const float * x,
|
||||
const float * residual,
|
||||
const float * post,
|
||||
const float * comb,
|
||||
float * dst,
|
||||
int64_t n_embd,
|
||||
int64_t hc,
|
||||
int64_t n_tokens,
|
||||
int64_t sx0,
|
||||
int64_t sx1,
|
||||
int64_t sr0,
|
||||
int64_t sr1,
|
||||
int64_t sr2,
|
||||
int64_t sp0,
|
||||
int64_t sp1,
|
||||
int64_t sc0,
|
||||
int64_t sc1,
|
||||
int64_t sc2,
|
||||
int64_t sd0,
|
||||
int64_t sd1,
|
||||
int64_t sd2) {
|
||||
ggml_cuda_pdl_lc();
|
||||
const int64_t ir = (int64_t) blockIdx.x * blockDim.x + threadIdx.x;
|
||||
const int64_t nr = n_embd * hc * n_tokens;
|
||||
|
||||
if (ir >= nr) {
|
||||
return;
|
||||
}
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
|
||||
const int64_t i0 = ir % n_embd;
|
||||
const int64_t idst = (ir / n_embd) % hc;
|
||||
const int64_t it = ir / (n_embd * hc);
|
||||
|
||||
float sum = x[i0*sx0 + it*sx1] * post[idst*sp0 + it*sp1];
|
||||
for (int64_t isrc = 0; isrc < hc; ++isrc) {
|
||||
sum += residual[i0*sr0 + isrc*sr1 + it*sr2] * comb[idst*sc0 + isrc*sc1 + it*sc2];
|
||||
}
|
||||
|
||||
dst[i0*sd0 + idst*sd1 + it*sd2] = sum;
|
||||
}
|
||||
|
||||
void ggml_cuda_op_dsv4_hc_comb(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
|
||||
const ggml_tensor * mixes = dst->src[0];
|
||||
const ggml_tensor * scale = dst->src[1];
|
||||
const ggml_tensor * base = dst->src[2];
|
||||
|
||||
GGML_ASSERT(mixes->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(scale->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(base->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
constexpr int64_t hc_mix_dim = (2 + DSV4_HC)*DSV4_HC;
|
||||
|
||||
GGML_ASSERT(mixes->ne[0] == hc_mix_dim);
|
||||
GGML_ASSERT(dst->ne[0] == DSV4_HC);
|
||||
GGML_ASSERT(dst->ne[1] == DSV4_HC);
|
||||
GGML_ASSERT(dst->ne[2] == mixes->ne[1]);
|
||||
GGML_ASSERT(scale->ne[0] >= 3);
|
||||
GGML_ASSERT(base->ne[0] == hc_mix_dim);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbm, mixes, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbs, scale, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbb, base, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_tokens = mixes->ne[1];
|
||||
const float eps = ggml_get_op_params_f32(dst, 0);
|
||||
const int32_t n_iter = ggml_get_op_params_i32(dst, 1);
|
||||
|
||||
const int block_size = 256;
|
||||
const dim3 block_dims(block_size, 1, 1);
|
||||
const dim3 grid_dims((n_tokens + block_size - 1) / block_size, 1, 1);
|
||||
const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(grid_dims, block_dims, 0, ctx.stream());
|
||||
|
||||
ggml_cuda_kernel_launch(dsv4_hc_comb_f32, launch_params,
|
||||
(const float *) mixes->data, (const float *) scale->data, (const float *) base->data, (float *) dst->data,
|
||||
n_tokens,
|
||||
nbm0 / sizeof(float), nbm1 / sizeof(float),
|
||||
nbs0 / sizeof(float),
|
||||
nbb0 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float), nbd2 / sizeof(float),
|
||||
eps, n_iter);
|
||||
}
|
||||
|
||||
void ggml_cuda_op_dsv4_hc_pre(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * weights = dst->src[1];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(weights->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbw, weights, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t hc = x->ne[1];
|
||||
const int64_t n_tokens = x->ne[2];
|
||||
|
||||
const int block_size = 256;
|
||||
const int64_t nr = n_embd * n_tokens;
|
||||
const dim3 block_dims(block_size, 1, 1);
|
||||
const dim3 grid_dims((nr + block_size - 1) / block_size, 1, 1);
|
||||
const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(grid_dims, block_dims, 0, ctx.stream());
|
||||
|
||||
ggml_cuda_kernel_launch(dsv4_hc_pre_f32, launch_params,
|
||||
(const float *) x->data, (const float *) weights->data, (float *) dst->data,
|
||||
n_embd, hc, n_tokens,
|
||||
nbx0 / sizeof(float), nbx1 / sizeof(float), nbx2 / sizeof(float),
|
||||
nbw0 / sizeof(float), nbw1 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float));
|
||||
}
|
||||
|
||||
void ggml_cuda_op_dsv4_hc_post(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
|
||||
const ggml_tensor * x = dst->src[0];
|
||||
const ggml_tensor * residual = dst->src[1];
|
||||
const ggml_tensor * post = dst->src[2];
|
||||
const ggml_tensor * comb = dst->src[3];
|
||||
|
||||
GGML_ASSERT(x->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(residual->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(post->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(comb->type == GGML_TYPE_F32);
|
||||
GGML_ASSERT(dst->type == GGML_TYPE_F32);
|
||||
|
||||
GGML_TENSOR_LOCALS(size_t, nbx, x, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbr, residual, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbp, post, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbc, comb, nb);
|
||||
GGML_TENSOR_LOCALS(size_t, nbd, dst, nb);
|
||||
|
||||
const int64_t n_embd = x->ne[0];
|
||||
const int64_t n_tokens = x->ne[1];
|
||||
const int64_t hc = residual->ne[1];
|
||||
|
||||
const int block_size = 256;
|
||||
const int64_t nr = n_embd * hc * n_tokens;
|
||||
const dim3 block_dims(block_size, 1, 1);
|
||||
const dim3 grid_dims((nr + block_size - 1) / block_size, 1, 1);
|
||||
const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params(grid_dims, block_dims, 0, ctx.stream());
|
||||
|
||||
ggml_cuda_kernel_launch(dsv4_hc_post_f32, launch_params,
|
||||
(const float *) x->data, (const float *) residual->data,
|
||||
(const float *) post->data, (const float *) comb->data, (float *) dst->data,
|
||||
n_embd, hc, n_tokens,
|
||||
nbx0 / sizeof(float), nbx1 / sizeof(float),
|
||||
nbr0 / sizeof(float), nbr1 / sizeof(float), nbr2 / sizeof(float),
|
||||
nbp0 / sizeof(float), nbp1 / sizeof(float),
|
||||
nbc0 / sizeof(float), nbc1 / sizeof(float), nbc2 / sizeof(float),
|
||||
nbd0 / sizeof(float), nbd1 / sizeof(float), nbd2 / sizeof(float));
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "common.cuh"
|
||||
#include "ggml.h"
|
||||
|
||||
void ggml_cuda_op_dsv4_hc_comb(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
|
||||
void ggml_cuda_op_dsv4_hc_pre(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
|
||||
void ggml_cuda_op_dsv4_hc_post(ggml_backend_cuda_context & ctx, ggml_tensor * dst);
|
||||
+197
-22
@@ -40,6 +40,35 @@ static __global__ void k_get_rows(
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t, dequantize_kq_t<dst_t> dequantize_kq>
|
||||
static __global__ void k_get_rows_kq(
|
||||
const void * __restrict__ src0, const int32_t * __restrict__ src1, dst_t * __restrict__ dst,
|
||||
const int64_t ne00, /*const int64_t ne01, const int64_t ne02, const int64_t ne03,*/
|
||||
/*const int64_t ne10,*/ const int64_t ne11, const uint3 ne12_fdv, /*const int64_t ne13,*/
|
||||
/*const size_t s0,*/ const size_t s1, const size_t s2, const size_t s3,
|
||||
/*const size_t nb00,*/ const size_t nb01, const size_t nb02, const size_t nb03,
|
||||
const size_t s10, const size_t s11, const size_t s12/*, const size_t s13*/) {
|
||||
|
||||
ggml_cuda_pdl_sync();
|
||||
const int64_t nsb = ne00/QK_K; // super-blocks per row
|
||||
for (int64_t z = blockIdx.z; z < ne11*(int64_t)ne12_fdv.z; z += gridDim.z) {
|
||||
// The x and y dimensions of the grid are swapped because the maximum allowed grid size for x is higher.
|
||||
const int i10 = blockIdx.x;
|
||||
const uint2 dm = fast_div_modulo((uint32_t)z, ne12_fdv);
|
||||
const int i11 = dm.x;
|
||||
const int i12 = dm.y;
|
||||
|
||||
const int i01 = src1[i10*s10 + i11*s11 + i12*s12];
|
||||
|
||||
dst_t * dst_row = dst + i10*s1 + i11*s2 + i12*s3;
|
||||
const void * src0_row = (const char *) src0 + i01*nb01 + i11*nb02 + i12*nb03;
|
||||
|
||||
for (int64_t ib = blockIdx.y; ib < nsb; ib += gridDim.y) {
|
||||
dequantize_kq(src0_row, ib, dst_row + ib*QK_K, threadIdx.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename src0_t, typename dst_t>
|
||||
static __global__ void k_get_rows_float(
|
||||
const src0_t * src0_ptr, const int32_t * src1_ptr, dst_t * dst_ptr,
|
||||
@@ -55,27 +84,51 @@ static __global__ void k_get_rows_float(
|
||||
dst_t * GGML_CUDA_RESTRICT dst = dst_ptr;
|
||||
ggml_cuda_pdl_sync();
|
||||
for (int64_t z = blockIdx.z; z < ne11*(int64_t)ne12_fdv.z; z += gridDim.z) {
|
||||
// The x and y dimensions of the grid are swapped because the maximum allowed grid size for x is higher.
|
||||
const int i10 = blockIdx.x;
|
||||
const uint2 dm = fast_div_modulo((uint32_t)z, ne12_fdv);
|
||||
const int i11 = dm.x;
|
||||
const int i12 = dm.y;
|
||||
|
||||
const int i01 = src1[i10*s10 + i11*s11 + i12*s12];
|
||||
|
||||
dst_t * GGML_CUDA_RESTRICT dst_row = dst + i10*s1 + i11*s2 + i12*s3;
|
||||
const src0_t * GGML_CUDA_RESTRICT src0_row = (const src0_t *)((const char *) src0 + i01*nb01 + i11*nb02 + i12*nb03);
|
||||
|
||||
for (int64_t i00 = blockIdx.y*blockDim.x + threadIdx.x; i00 < ne00; i00 += gridDim.y*blockDim.x) {
|
||||
// The x and y dimensions of the grid are swapped because the maximum allowed grid size for x is higher.
|
||||
const int i10 = blockIdx.x;
|
||||
const uint2 dm = fast_div_modulo((uint32_t)z, ne12_fdv);
|
||||
const int i11 = dm.x;
|
||||
const int i12 = dm.y;
|
||||
|
||||
if (i00 >= ne00) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int i01 = src1[i10*s10 + i11*s11 + i12*s12];
|
||||
|
||||
dst_t * dst_row = dst + i10*s1 + i11*s2 + i12*s3;
|
||||
const src0_t * src0_row = (const src0_t *)((const char *) src0 + i01*nb01 + i11*nb02 + i12*nb03);
|
||||
|
||||
dst_row[i00] = ggml_cuda_cast<dst_t>(src0_row[i00]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename dst_t>
|
||||
static __global__ void k_get_rows_float_vec(
|
||||
const dst_t * src0_ptr, const int32_t * src1_ptr, dst_t * dst_ptr,
|
||||
const int64_t ne00v,
|
||||
const int64_t ne11, const uint3 ne12_fdv,
|
||||
const size_t s1, const size_t s2, const size_t s3,
|
||||
const size_t nb01, const size_t nb02, const size_t nb03,
|
||||
const size_t s10, const size_t s11, const size_t s12) {
|
||||
|
||||
ggml_cuda_pdl_lc();
|
||||
ggml_cuda_pdl_sync();
|
||||
for (int64_t z = blockIdx.z; z < ne11*(int64_t)ne12_fdv.z; z += gridDim.z) {
|
||||
const int i10 = blockIdx.x;
|
||||
const uint2 dm = fast_div_modulo((uint32_t)z, ne12_fdv);
|
||||
const int i11 = dm.x;
|
||||
const int i12 = dm.y;
|
||||
|
||||
const int i01 = src1_ptr[i10*s10 + i11*s11 + i12*s12];
|
||||
|
||||
int4 * GGML_CUDA_RESTRICT dst_row = (int4 *) (dst_ptr + i10*s1 + i11*s2 + i12*s3);
|
||||
const int4 * GGML_CUDA_RESTRICT src0_row = (const int4 *)((const char *) src0_ptr + i01*nb01 + i11*nb02 + i12*nb03);
|
||||
|
||||
for (int64_t i = blockIdx.y*blockDim.x + threadIdx.x; i < ne00v; i += gridDim.y*blockDim.x) {
|
||||
dst_row[i] = src0_row[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename grad_t, typename dst_t>
|
||||
static __global__ void k_get_rows_back_float(
|
||||
const grad_t * __restrict__ grad, const int32_t * __restrict__ rows, dst_t * __restrict__ dst,
|
||||
@@ -140,16 +193,18 @@ static void get_rows_cuda_q(
|
||||
s10, s11, s12/*, s13*/);
|
||||
}
|
||||
|
||||
template<typename src0_t, typename dst_t>
|
||||
static void get_rows_cuda_float(
|
||||
const src0_t * src0_d, const int32_t * src1_d, dst_t * dst_d,
|
||||
template<int block_dim, typename dst_t, dequantize_kq_t<dst_t> dequantize_kq>
|
||||
static void get_rows_cuda_kq(
|
||||
const void * src0_d, const int32_t * src1_d, dst_t * dst_d,
|
||||
const int64_t ne00, const size_t nb01, const size_t nb02, const size_t nb03,
|
||||
const int64_t ne10, const int64_t ne11, const int64_t ne12, const size_t nb10, const size_t nb11, const size_t nb12,
|
||||
const size_t nb1, const size_t nb2, const size_t nb3,
|
||||
cudaStream_t stream) {
|
||||
const dim3 block_dims(CUDA_GET_ROWS_BLOCK_SIZE, 1, 1);
|
||||
const int block_num_y = (ne00 + CUDA_GET_ROWS_BLOCK_SIZE - 1) / CUDA_GET_ROWS_BLOCK_SIZE;
|
||||
const dim3 block_nums(ne10, MIN(block_num_y, UINT16_MAX), MIN(ne11*ne12, UINT16_MAX));
|
||||
GGML_ASSERT(ne00 % QK_K == 0);
|
||||
const int64_t nsb = ne00/QK_K;
|
||||
|
||||
const dim3 block_dims(block_dim, 1, 1);
|
||||
const dim3 block_nums(ne10, MIN(nsb, UINT16_MAX), MIN(ne11*ne12, UINT16_MAX));
|
||||
|
||||
// strides in elements
|
||||
// const size_t s0 = nb0 / sizeof(dst_t);
|
||||
@@ -166,6 +221,67 @@ static void get_rows_cuda_float(
|
||||
GGML_ASSERT(ne11 <= std::numeric_limits<uint32_t>::max() / ne12);
|
||||
const uint3 ne12_fdv = init_fastdiv_values(ne12);
|
||||
|
||||
k_get_rows_kq<dst_t, dequantize_kq><<<block_nums, block_dims, 0, stream>>>(
|
||||
src0_d, src1_d, dst_d,
|
||||
ne00, /*ne01, ne02, ne03,*/
|
||||
/*ne10,*/ ne11, ne12_fdv, /*ne13,*/
|
||||
/* s0,*/ s1, s2, s3,
|
||||
/* nb00,*/ nb01, nb02, nb03,
|
||||
s10, s11, s12/*, s13*/);
|
||||
}
|
||||
|
||||
template<typename src0_t, typename dst_t>
|
||||
static void get_rows_cuda_float(
|
||||
const src0_t * src0_d, const int32_t * src1_d, dst_t * dst_d,
|
||||
const int64_t ne00, const size_t nb01, const size_t nb02, const size_t nb03,
|
||||
const int64_t ne10, const int64_t ne11, const int64_t ne12, const size_t nb10, const size_t nb11, const size_t nb12,
|
||||
const size_t nb1, const size_t nb2, const size_t nb3,
|
||||
cudaStream_t stream) {
|
||||
const dim3 block_dims(CUDA_GET_ROWS_BLOCK_SIZE, 1, 1);
|
||||
|
||||
// strides in elements
|
||||
// const size_t s0 = nb0 / sizeof(dst_t);
|
||||
const size_t s1 = nb1 / sizeof(dst_t);
|
||||
const size_t s2 = nb2 / sizeof(dst_t);
|
||||
const size_t s3 = nb3 / sizeof(dst_t);
|
||||
|
||||
const size_t s10 = nb10 / sizeof(int32_t);
|
||||
const size_t s11 = nb11 / sizeof(int32_t);
|
||||
const size_t s12 = nb12 / sizeof(int32_t);
|
||||
// const size_t s13 = nb13 / sizeof(int32_t);
|
||||
|
||||
GGML_ASSERT(ne12 > 0);
|
||||
GGML_ASSERT(ne11 <= std::numeric_limits<uint32_t>::max() / ne12);
|
||||
const uint3 ne12_fdv = init_fastdiv_values(ne12);
|
||||
|
||||
if constexpr (std::is_same<src0_t, dst_t>::value) {
|
||||
constexpr int VEC = 16 / sizeof(dst_t);
|
||||
const int64_t ne00v = ne00 / VEC;
|
||||
const int64_t vec_block_num_y = (ne00v + CUDA_GET_ROWS_BLOCK_SIZE - 1) / CUDA_GET_ROWS_BLOCK_SIZE;
|
||||
const bool enough_blocks = vec_block_num_y * ne10 * ne11 * ne12 >= 128;
|
||||
const bool can_vec = VEC > 1 && enough_blocks &&
|
||||
(ne00 % VEC == 0) &&
|
||||
(nb01 % 16 == 0) && (nb02 % 16 == 0) && (nb03 % 16 == 0) &&
|
||||
(nb1 % 16 == 0) && (nb2 % 16 == 0) && (nb3 % 16 == 0) &&
|
||||
(((uintptr_t) src0_d) % 16 == 0) && (((uintptr_t) dst_d) % 16 == 0);
|
||||
|
||||
if (can_vec) {
|
||||
const int block_num_y = vec_block_num_y;
|
||||
const dim3 block_nums(ne10, MIN(block_num_y, UINT16_MAX), MIN(ne11*ne12, UINT16_MAX));
|
||||
const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{block_nums, block_dims, 0, stream};
|
||||
ggml_cuda_kernel_launch(k_get_rows_float_vec<dst_t>, launch_params,
|
||||
(const dst_t *) src0_d, src1_d, dst_d,
|
||||
ne00v, ne11, ne12_fdv,
|
||||
s1, s2, s3,
|
||||
nb01, nb02, nb03,
|
||||
s10, s11, s12);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const int block_num_y = (ne00 + CUDA_GET_ROWS_BLOCK_SIZE - 1) / CUDA_GET_ROWS_BLOCK_SIZE;
|
||||
const dim3 block_nums(ne10, MIN(block_num_y, UINT16_MAX), MIN(ne11*ne12, UINT16_MAX));
|
||||
|
||||
const ggml_cuda_kernel_launch_params launch_params = ggml_cuda_kernel_launch_params{block_nums, block_dims, 0, stream};
|
||||
ggml_cuda_kernel_launch(k_get_rows_float<src0_t, dst_t>, launch_params,
|
||||
src0_d, src1_d, dst_d,
|
||||
@@ -224,8 +340,67 @@ static void ggml_cuda_get_rows_switch_src0_type(
|
||||
get_rows_cuda_q<QK8_0, QR8_0, dequantize_q8_0>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q2_K:
|
||||
get_rows_cuda_kq<64, dst_t, dequantize_q2_K<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q3_K:
|
||||
get_rows_cuda_kq<64, dst_t, dequantize_q3_K<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q4_K:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_q4_K<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q5_K:
|
||||
get_rows_cuda_kq<64, dst_t, dequantize_q5_K<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_Q6_K:
|
||||
get_rows_cuda_kq<64, dst_t, dequantize_q6_K<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq2_xxs<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq2_xs<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ2_S:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq2_s<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq3_xxs<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ3_S:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq3_s<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ1_S:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq1_s<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ1_M:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq1_m<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ4_NL:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq4_nl<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_IQ4_XS:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_iq4_xs<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
case GGML_TYPE_MXFP4:
|
||||
get_rows_cuda_kq<32, dst_t, dequantize_mxfp4<dst_t>>(src0_d, src1_d, dst_d,
|
||||
ne00, nb01, nb02, nb03, ne10, ne11, ne12, nb10, nb11, nb12, nb1, nb2, nb3, stream);
|
||||
break;
|
||||
default:
|
||||
// TODO: k-quants
|
||||
GGML_ABORT("%s: unsupported src0 type: %s\n", __func__, ggml_type_name(src0_type));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@
|
||||
#include "ggml-cuda/wkv.cuh"
|
||||
#include "ggml-cuda/gla.cuh"
|
||||
#include "ggml-cuda/gated_delta_net.cuh"
|
||||
#include "ggml-cuda/dsv4-hc.cuh"
|
||||
#include "ggml-cuda/set.cuh"
|
||||
#include "ggml-cuda/set-rows.cuh"
|
||||
#include "ggml-cuda/pad_reflect_1d.cuh"
|
||||
@@ -2319,6 +2320,15 @@ static bool ggml_cuda_compute_forward(ggml_backend_cuda_context & ctx, struct gg
|
||||
case GGML_OP_GATED_DELTA_NET:
|
||||
ggml_cuda_op_gated_delta_net(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
ggml_cuda_op_dsv4_hc_comb(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
ggml_cuda_op_dsv4_hc_pre(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
ggml_cuda_op_dsv4_hc_post(ctx, dst);
|
||||
break;
|
||||
case GGML_OP_RWKV_WKV7:
|
||||
ggml_cuda_op_rwkv_wkv7(ctx, dst);
|
||||
break;
|
||||
@@ -2693,6 +2703,7 @@ static int ggml_cuda_try_gdn_cache_fusion(
|
||||
|
||||
static bool ggml_cuda_topk_moe_fusion(const struct ggml_cgraph * cgraph, int node_idx, ggml_cuda_topk_moe_args & args) {
|
||||
args.sigmoid = false;
|
||||
args.sqrt_softplus = false;
|
||||
args.softmax = false;
|
||||
args.delayed_softmax = false;
|
||||
args.prob_bias = false;
|
||||
@@ -2706,10 +2717,17 @@ static bool ggml_cuda_topk_moe_fusion(const struct ggml_cgraph * cgraph, int nod
|
||||
}
|
||||
|
||||
if (nodes[node_idx]->op == GGML_OP_UNARY) {
|
||||
if (ggml_get_unary_op(nodes[node_idx]) != GGML_UNARY_OP_SIGMOID) {
|
||||
const ggml_unary_op unary_op = ggml_get_unary_op(nodes[node_idx]);
|
||||
if (unary_op == GGML_UNARY_OP_SIGMOID) {
|
||||
args.sigmoid = true;
|
||||
} else if (unary_op == GGML_UNARY_OP_SOFTPLUS && node_idx + 1 < n_nodes &&
|
||||
nodes[node_idx + 1]->op == GGML_OP_SQRT && nodes[node_idx + 1]->src[0] == nodes[node_idx]) {
|
||||
// sqrt(softplus(x)) scoring (DeepSeek-V4)
|
||||
args.sqrt_softplus = true;
|
||||
node_idx++;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
args.sigmoid = true;
|
||||
}
|
||||
|
||||
if (nodes[node_idx]->op == GGML_OP_ARGSORT) {
|
||||
@@ -2718,7 +2736,7 @@ static bool ggml_cuda_topk_moe_fusion(const struct ggml_cgraph * cgraph, int nod
|
||||
|
||||
node_idx++;
|
||||
|
||||
if (args.sigmoid || args.softmax) {
|
||||
if (args.sigmoid || args.sqrt_softplus || args.softmax) {
|
||||
// SOFTMAX -> RESHAPE
|
||||
if (node_idx >= n_nodes || nodes[node_idx]->op != GGML_OP_RESHAPE ||
|
||||
nodes[node_idx]->src[0] != nodes[node_idx - 1]) {
|
||||
@@ -3162,21 +3180,27 @@ static int ggml_cuda_try_fuse(ggml_backend_cuda_context * cuda_ctx, ggml_cgraph
|
||||
const ggml_tensor * scale = nullptr;
|
||||
|
||||
if (!args.delayed_softmax) {
|
||||
ggml_op gating_op = args.sigmoid ? GGML_OP_UNARY : GGML_OP_SOFT_MAX;
|
||||
int out_nodes[2]; // nodes which can't be elided
|
||||
int out_nodes[2]; // nodes which can't be elided
|
||||
|
||||
if (args.sigmoid) {
|
||||
ops.insert(ops.end(), { GGML_OP_UNARY });
|
||||
} else if (args.sqrt_softplus) {
|
||||
ops.insert(ops.end(), { GGML_OP_UNARY, GGML_OP_SQRT });
|
||||
} else {
|
||||
ops.insert(ops.end(), { GGML_OP_SOFT_MAX });
|
||||
}
|
||||
const int i_probs = i + (int) ops.size() - 1; // last node of the gating activation
|
||||
|
||||
if (args.prob_bias) {
|
||||
bias = cgraph->nodes[i + 2]->src[1];
|
||||
ops.insert(ops.end(), { gating_op, GGML_OP_RESHAPE, GGML_OP_ADD, GGML_OP_ARGSORT, GGML_OP_VIEW,
|
||||
bias = cgraph->nodes[i_probs + 2]->src[1];
|
||||
ops.insert(ops.end(), { GGML_OP_RESHAPE, GGML_OP_ADD, GGML_OP_ARGSORT, GGML_OP_VIEW,
|
||||
GGML_OP_GET_ROWS });
|
||||
out_nodes[0] = i + 4;
|
||||
ids = cgraph->nodes[i + 4];
|
||||
out_nodes[0] = i_probs + 4;
|
||||
} else {
|
||||
ops.insert(ops.end(),
|
||||
{ gating_op, GGML_OP_RESHAPE, GGML_OP_ARGSORT, GGML_OP_VIEW, GGML_OP_GET_ROWS });
|
||||
out_nodes[0] = i + 3;
|
||||
ids = cgraph->nodes[i + 3];
|
||||
ops.insert(ops.end(), { GGML_OP_RESHAPE, GGML_OP_ARGSORT, GGML_OP_VIEW, GGML_OP_GET_ROWS });
|
||||
out_nodes[0] = i_probs + 3;
|
||||
}
|
||||
ids = cgraph->nodes[out_nodes[0]];
|
||||
|
||||
if (args.norm) {
|
||||
ops.insert(ops.end(),
|
||||
@@ -4821,7 +4845,25 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
case GGML_TYPE_Q5_0:
|
||||
case GGML_TYPE_Q5_1:
|
||||
case GGML_TYPE_Q8_0:
|
||||
case GGML_TYPE_Q2_K:
|
||||
case GGML_TYPE_Q3_K:
|
||||
case GGML_TYPE_Q4_K:
|
||||
case GGML_TYPE_Q5_K:
|
||||
case GGML_TYPE_Q6_K:
|
||||
case GGML_TYPE_IQ2_XXS:
|
||||
case GGML_TYPE_IQ2_XS:
|
||||
case GGML_TYPE_IQ2_S:
|
||||
case GGML_TYPE_IQ3_XXS:
|
||||
case GGML_TYPE_IQ3_S:
|
||||
case GGML_TYPE_IQ1_S:
|
||||
case GGML_TYPE_IQ1_M:
|
||||
case GGML_TYPE_IQ4_XS:
|
||||
return true;
|
||||
case GGML_TYPE_IQ4_NL:
|
||||
case GGML_TYPE_MXFP4:
|
||||
// 32-value sub-blocks, the row size does not guarantee
|
||||
// the QK_K super-blocks the get_rows kernel iterates on
|
||||
return op->src[0]->ne[0] % QK_K == 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
@@ -5088,6 +5130,16 @@ static bool ggml_backend_cuda_device_supports_op(ggml_backend_dev_t dev, const g
|
||||
#else
|
||||
return true;
|
||||
#endif // GGML_USE_MUSA
|
||||
case GGML_OP_DSV4_HC_COMB:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->src[2]->type == GGML_TYPE_F32 && op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_DSV4_HC_PRE:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_DSV4_HC_POST:
|
||||
return op->src[0]->type == GGML_TYPE_F32 && op->src[1]->type == GGML_TYPE_F32 &&
|
||||
op->src[2]->type == GGML_TYPE_F32 && op->src[3]->type == GGML_TYPE_F32 &&
|
||||
op->type == GGML_TYPE_F32;
|
||||
case GGML_OP_FLASH_ATTN_EXT:
|
||||
return ggml_cuda_flash_attn_ext_supported(dev_ctx->device, op);
|
||||
case GGML_OP_CROSS_ENTROPY_LOSS:
|
||||
|
||||
+23
-10
@@ -130,14 +130,20 @@ void ggml_cuda_mul_mat_q(
|
||||
const size_t nbytes_src1_q8_1 = ne13*ne12 * ne11*ne10_padded * y_block_size/y_values_per_block +
|
||||
ggml_cuda_mmq_get_J_max(src0->type, fallback, cc, ne11) * sizeof(block_q8_1_mmq);
|
||||
ggml_cuda_pool_alloc<char> src1_q8_1(ctx.pool(), nbytes_src1_q8_1);
|
||||
ggml_cuda_pool_alloc<float> src1_scale(ctx.pool());
|
||||
if (src0->type == GGML_TYPE_NVFP4 && use_native_fp4) {
|
||||
src1_scale.alloc(ne13*ne12*ne11);
|
||||
}
|
||||
|
||||
{
|
||||
const int64_t s11 = src1->nb[1] / ts_src1;
|
||||
const int64_t s12 = src1->nb[2] / ts_src1;
|
||||
const int64_t s13 = src1->nb[3] / ts_src1;
|
||||
if (use_native_fp4) {
|
||||
static constexpr size_t align_float8 = 32;
|
||||
const bool use_aligned_float8 = ggml_cuda_is_aligned(src1, align_float8);
|
||||
static_assert(sizeof(block_fp4_mmq) == 4 * sizeof(block_q8_1));
|
||||
quantize_mmq_fp4_cuda(src1_d, nullptr, src1_q8_1.get(), src0->type, ne10, s11, s12, s13, ne10_padded,
|
||||
quantize_mmq_fp4_cuda(src1_d, nullptr, src1_q8_1.get(), src1_scale.ptr, src0->type, use_aligned_float8, ne10, s11, s12, s13, ne10_padded,
|
||||
ne11, ne12, ne13, stream);
|
||||
|
||||
} else {
|
||||
@@ -155,6 +161,7 @@ void ggml_cuda_mul_mat_q(
|
||||
|
||||
const mmq_args args = {
|
||||
src0_d, src0->type, (const int *) src1_q8_1.ptr, nullptr, nullptr, dst_d,
|
||||
src0->type == GGML_TYPE_NVFP4 && use_native_fp4 ? src1_scale.ptr : nullptr,
|
||||
ne00, ne01, ne1, s01, ne11, s1,
|
||||
ne02, ne12, s02, s12, s2,
|
||||
ne03, ne13, s03, s13, s3,
|
||||
@@ -192,6 +199,10 @@ void ggml_cuda_mul_mat_q(
|
||||
const size_t nbytes_src1_q8_1 = ne12*n_expert_used*ne10_padded * y_block_size/y_values_per_block +
|
||||
ggml_cuda_mmq_get_J_max(src0->type, fallback, cc, ne11) * sizeof(block_q8_1_mmq);
|
||||
ggml_cuda_pool_alloc<char> src1_q8_1(ctx.pool(), nbytes_src1_q8_1);
|
||||
ggml_cuda_pool_alloc<float> src1_scale(ctx.pool());
|
||||
if (src0->type == GGML_TYPE_NVFP4 && use_native_fp4) {
|
||||
src1_scale.alloc(ne12*n_expert_used);
|
||||
}
|
||||
|
||||
const int64_t ne11_flat = ne12*n_expert_used;
|
||||
const int64_t ne12_flat = 1;
|
||||
@@ -202,18 +213,19 @@ void ggml_cuda_mul_mat_q(
|
||||
const int64_t s12 = src1->nb[2] / ts_src1;
|
||||
const int64_t s13 = src1->nb[3] / ts_src1;
|
||||
|
||||
if (dedup_bcast) {
|
||||
// quantize each token once, scatter its block to all n_expert_used slots
|
||||
if (use_native_fp4) {
|
||||
quantize_scatter_mmq_fp4_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10,
|
||||
if (use_native_fp4) {
|
||||
static constexpr size_t align_float8 = 32;
|
||||
const bool use_aligned_float8 = ggml_cuda_is_aligned(src1, align_float8);
|
||||
if (dedup_bcast) {
|
||||
quantize_scatter_mmq_fp4_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src1_scale.ptr, src0->type, use_aligned_float8, ne10,
|
||||
/*stride_token=*/s12, ne10_padded, ne12, ne11_flat, n_expert_used, stream);
|
||||
} else {
|
||||
quantize_scatter_mmq_q8_1_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10,
|
||||
/*stride_token=*/s12, ne10_padded, ne12, ne11_flat, n_expert_used, stream);
|
||||
quantize_mmq_fp4_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src1_scale.ptr, src0->type, use_aligned_float8, ne10, s11, s12, s13,
|
||||
ne10_padded, ne11_flat, ne12_flat, ne13_flat, stream);
|
||||
}
|
||||
} else if (use_native_fp4) {
|
||||
quantize_mmq_fp4_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10, s11, s12, s13,
|
||||
ne10_padded, ne11_flat, ne12_flat, ne13_flat, stream);
|
||||
} else if (dedup_bcast) {
|
||||
quantize_scatter_mmq_q8_1_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10,
|
||||
/*stride_token=*/s12, ne10_padded, ne12, ne11_flat, n_expert_used, stream);
|
||||
} else {
|
||||
quantize_mmq_q8_1_cuda(src1_d, ids_src1.get(), src1_q8_1.get(), src0->type, ne10, s11, s12, s13,
|
||||
ne10_padded, ne11_flat, ne12_flat, ne13_flat, stream);
|
||||
@@ -229,6 +241,7 @@ void ggml_cuda_mul_mat_q(
|
||||
// Note that ne02 is used instead of ne12 because the number of y channels determines the z dimension of the CUDA grid.
|
||||
const mmq_args args = {
|
||||
src0_d, src0->type, (const int *) src1_q8_1.get(), ids_dst.get(), expert_bounds.get(), dst_d,
|
||||
src1_scale.ptr,
|
||||
ne00, ne01, ne_get_rows, s01, ne_get_rows, s1,
|
||||
ne02, ne02, s02, s12, s2,
|
||||
ne03, ne13, s03, s13, s3,
|
||||
|
||||
+89
-18
@@ -13,7 +13,7 @@
|
||||
typedef void (*ggml_cuda_mmq_load_tiles_t)(const char * __restrict__ x, int * x_tile, const int kbx0, const int i_max, const int stride);
|
||||
typedef void (*ggml_cuda_mmq_vec_dot_t)(const int * __restrict__ x, const int * __restrict__ y, float * __restrict__ sum, const int k00);
|
||||
typedef void (*ggml_cuda_mmq_write_back_t)(const float * __restrict__ sum, const int32_t * __restrict__ get_rows_to_sorted,
|
||||
float * __restrict__ dst, const int stride, const int i_max, const int j_max);
|
||||
float * __restrict__ dst, const float * __restrict__ y_scale, const int stride, const int i_max, const int j_max);
|
||||
|
||||
enum mmq_q8_1_ds_layout {
|
||||
MMQ_Q8_1_DS_LAYOUT_D4,
|
||||
@@ -413,11 +413,13 @@ static __host__ int ggml_cuda_mmq_get_nbytes_shared_x(const ggml_cuda_mmq_config
|
||||
|
||||
template <ggml_type type, int J, bool fallback> static __device__ __forceinline__ void ggml_cuda_mmq_write_back_dp4a(
|
||||
const float * __restrict__ sum, const int32_t * __restrict__ ids_dst, float * __restrict__ dst,
|
||||
const int stride, const int i_max, const int j_max) {
|
||||
const float * __restrict__ y_scale, const int stride, const int i_max, const int j_max) {
|
||||
constexpr int warp_size = ggml_cuda_get_physical_warp_size();
|
||||
constexpr int nwarps = ggml_cuda_mmq_get_nthreads(type, J, fallback) / warp_size;
|
||||
constexpr int I = ggml_cuda_mmq_get_I(type, J, fallback);
|
||||
|
||||
const bool y_scale_used = y_scale != nullptr;
|
||||
|
||||
#pragma unroll
|
||||
for (int j0 = 0; j0 < J; j0 += nwarps) {
|
||||
const int j = j0 + threadIdx.y;
|
||||
@@ -434,7 +436,16 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
continue;
|
||||
}
|
||||
|
||||
dst[ids_dst[j]*stride + i] = sum[(j0/nwarps) * (I/warp_size) + i0/warp_size];
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
if (y_scale_used) {
|
||||
dst[ids_dst[j]*stride + i] = y_scale[j] * sum[(j0/nwarps) * (I/warp_size) + i0/warp_size];
|
||||
} else {
|
||||
dst[ids_dst[j]*stride + i] = sum[(j0/nwarps) * (I/warp_size) + i0/warp_size];
|
||||
}
|
||||
} else {
|
||||
dst[ids_dst[j]*stride + i] = sum[(j0/nwarps) * (I/warp_size) + i0/warp_size];
|
||||
GGML_UNUSED(y_scale_used);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -442,7 +453,8 @@ template <ggml_type type, int J, bool fallback> static __device__ __forceinline_
|
||||
template<ggml_type type, int J, bool fallback>
|
||||
static __device__ __forceinline__ void ggml_cuda_mmq_write_back_mma(
|
||||
const float * __restrict__ sum, const int * __restrict__ ids_dst, float * __restrict__ dst,
|
||||
const int stride, const int i_max, const int j_max) {
|
||||
const float * __restrict__ y_scale, const int stride, const int i_max, const int j_max) {
|
||||
|
||||
#if defined(AMD_MFMA_AVAILABLE) || defined(AMD_WMMA_AVAILABLE)
|
||||
typedef tile<16, 16, int, DATA_LAYOUT_J_MAJOR> tile_C;
|
||||
#else
|
||||
@@ -457,6 +469,8 @@ static __device__ __forceinline__ void ggml_cuda_mmq_write_back_mma(
|
||||
|
||||
const int i0 = (threadIdx.y / ntx) * (ntx*tile_C::I);
|
||||
|
||||
const bool y_scale_used = y_scale != nullptr;
|
||||
|
||||
#pragma unroll
|
||||
for (int j0 = 0; j0 < J; j0 += ntx*tile_C::J) {
|
||||
#pragma unroll
|
||||
@@ -475,7 +489,16 @@ static __device__ __forceinline__ void ggml_cuda_mmq_write_back_mma(
|
||||
continue;
|
||||
}
|
||||
|
||||
dst[ids_dst[j]*stride + i] = sum[(j0/tile_C::J + n)*tile_C::ne + l];
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
if (y_scale_used) {
|
||||
dst[ids_dst[j]*stride + i] = y_scale[j] * sum[(j0/tile_C::J + n)*tile_C::ne + l];
|
||||
} else {
|
||||
dst[ids_dst[j]*stride + i] = sum[(j0/tile_C::J + n)*tile_C::ne + l];
|
||||
}
|
||||
} else {
|
||||
dst[ids_dst[j]*stride + i] = sum[(j0/tile_C::J + n)*tile_C::ne + l];
|
||||
GGML_UNUSED(y_scale_used);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -819,6 +842,7 @@ template <ggml_type type, int J, bool fallback, bool fixup>
|
||||
static __device__ __forceinline__ void mul_mat_q_process_tile(
|
||||
const char * __restrict__ x, const int offset_x, const int * __restrict__ y,
|
||||
const int * __restrict__ ids_dst, float * __restrict__ dst, float * __restrict__ tmp_fixup,
|
||||
const float * __restrict__ y_scale,
|
||||
const int stride_row_x, const int ncols_y, const int stride_col_dst,
|
||||
const int tile_x_max_i, const int tile_y_max_j, const int kb0_start, const int kb0_stop) {
|
||||
|
||||
@@ -884,9 +908,9 @@ static __device__ __forceinline__ void mul_mat_q_process_tile(
|
||||
}
|
||||
|
||||
if (fixup) {
|
||||
write_back(sum, ids_dst, tmp_fixup + blockIdx.x*(J*I), I, I, J);
|
||||
write_back(sum, ids_dst, tmp_fixup + blockIdx.x*(J*I), y_scale, I, I, J);
|
||||
} else {
|
||||
write_back(sum, ids_dst, dst, stride_col_dst, tile_x_max_i, tile_y_max_j);
|
||||
write_back(sum, ids_dst, dst, y_scale, stride_col_dst, tile_x_max_i, tile_y_max_j);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,6 +922,7 @@ __launch_bounds__(ggml_cuda_mmq_get_nthreads(type, J, fallback), ggml_cuda_mmq_g
|
||||
static __global__ void mul_mat_q(
|
||||
const char * __restrict__ x, const int * __restrict__ y, const int32_t * __restrict__ ids_dst,
|
||||
const int32_t * __restrict__ expert_bounds, float * __restrict__ dst, float * __restrict__ tmp_fixup,
|
||||
const float * __restrict__ y_scale,
|
||||
const uint3 blocks_per_ne00, const int nrows_x, const int ncols_dst, const int stride_row_x, const int ncols_y, const int stride_col_dst,
|
||||
const uint3 channel_ratio, const uint3 nchannels_y, const int stride_channel_x, const int stride_channel_y, const int stride_channel_dst,
|
||||
const uint3 sample_ratio, const uint3 nsamples_y, const int stride_sample_x, const int stride_sample_y, const int stride_sample_dst,
|
||||
@@ -943,8 +968,14 @@ static __global__ void mul_mat_q(
|
||||
int col_low = 0;
|
||||
int col_high = ncols_dst;
|
||||
int col_diff = ncols_dst;
|
||||
int offset_y = wt*stride_sample_y + zt*stride_channel_y;
|
||||
int offset_dst = wt*stride_sample_dst + zt*stride_channel_dst + jt*J*stride_col_dst;
|
||||
int offset_y = wt*stride_sample_y + zt*stride_channel_y;
|
||||
int offset_dst = wt*stride_sample_dst + zt*stride_channel_dst + jt*J*stride_col_dst;
|
||||
int offset_y_scale;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale = wt*nchannels_y.z*ncols_y + zt*ncols_y;
|
||||
} else {
|
||||
GGML_UNUSED(offset_y_scale);
|
||||
}
|
||||
|
||||
if (ids_dst) {
|
||||
col_low = expert_bounds[zt + 0];
|
||||
@@ -953,6 +984,9 @@ static __global__ void mul_mat_q(
|
||||
|
||||
offset_y = 0;
|
||||
offset_dst = 0;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale = 0;
|
||||
}
|
||||
|
||||
if (jt*J >= col_diff) {
|
||||
return;
|
||||
@@ -974,6 +1008,11 @@ static __global__ void mul_mat_q(
|
||||
|
||||
offset_y += (col_low + jt*J)*(sizeof(block_q8_1_mmq)/sizeof(int));
|
||||
offset_dst += it*I;
|
||||
const float * y_scale_tile = nullptr;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale += col_low + jt*J;
|
||||
y_scale_tile = y_scale ? y_scale + offset_y_scale : nullptr;
|
||||
}
|
||||
|
||||
const int tile_x_max_i = nrows_x - it*I - 1;
|
||||
const int tile_y_max_j = col_diff - jt*J - 1;
|
||||
@@ -982,7 +1021,8 @@ static __global__ void mul_mat_q(
|
||||
|
||||
constexpr bool fixup = false;
|
||||
mul_mat_q_process_tile<type, J, fallback, fixup>
|
||||
(x, offset_x, y + offset_y, ids_dst_shared, dst + offset_dst, tmp_fixup, stride_row_x, ncols_y, stride_col_dst,
|
||||
(x, offset_x, y + offset_y, ids_dst_shared, dst + offset_dst, tmp_fixup, y_scale_tile,
|
||||
stride_row_x, ncols_y, stride_col_dst,
|
||||
tile_x_max_i, tile_y_max_j, 0, blocks_per_ne00.z);
|
||||
return;
|
||||
}
|
||||
@@ -1016,8 +1056,14 @@ static __global__ void mul_mat_q(
|
||||
int col_low = 0;
|
||||
int col_high = ncols_dst;
|
||||
int col_diff = ncols_dst;
|
||||
int offset_y = wt*stride_sample_y + zt*stride_channel_y;
|
||||
int offset_dst = wt*stride_sample_dst + zt*stride_channel_dst + jt*J*stride_col_dst;
|
||||
int offset_y = wt*stride_sample_y + zt*stride_channel_y;
|
||||
int offset_dst = wt*stride_sample_dst + zt*stride_channel_dst + jt*J*stride_col_dst;
|
||||
int offset_y_scale;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale = wt*nchannels_y.z*ncols_y + zt*ncols_y;
|
||||
} else {
|
||||
GGML_UNUSED(offset_y_scale);
|
||||
}
|
||||
|
||||
if (ids_dst) {
|
||||
col_low = expert_bounds[zt + 0];
|
||||
@@ -1026,6 +1072,9 @@ static __global__ void mul_mat_q(
|
||||
|
||||
offset_y = 0;
|
||||
offset_dst = 0;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale = 0;
|
||||
}
|
||||
|
||||
if (jt*J >= col_diff) {
|
||||
kbc += blocks_per_ne00.z;
|
||||
@@ -1053,6 +1102,11 @@ static __global__ void mul_mat_q(
|
||||
|
||||
offset_y += (col_low + jt * J) * (sizeof(block_q8_1_mmq) / sizeof(int));
|
||||
offset_dst += it*I;
|
||||
const float * y_scale_tile = nullptr;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale += col_low + jt * J;
|
||||
y_scale_tile = y_scale ? y_scale + offset_y_scale : nullptr;
|
||||
}
|
||||
|
||||
const int tile_x_max_i = nrows_x - it*I - 1;
|
||||
const int tile_y_max_j = col_diff - jt*J - 1;
|
||||
@@ -1061,7 +1115,8 @@ static __global__ void mul_mat_q(
|
||||
|
||||
constexpr bool fixup = false; // All but (potentially) the last iterations write their data to dst rather than the fixup buffer.
|
||||
mul_mat_q_process_tile<type, J, fallback, fixup>
|
||||
(x, offset_x, y + offset_y, ids_dst_shared, dst + offset_dst, tmp_fixup, stride_row_x, ncols_y, stride_col_dst,
|
||||
(x, offset_x, y + offset_y, ids_dst_shared, dst + offset_dst, tmp_fixup, y_scale_tile,
|
||||
stride_row_x, ncols_y, stride_col_dst,
|
||||
tile_x_max_i, tile_y_max_j, kb0_start, kb0_stop);
|
||||
|
||||
kbc += blocks_per_ne00.z;
|
||||
@@ -1090,8 +1145,14 @@ static __global__ void mul_mat_q(
|
||||
int col_low = 0;
|
||||
int col_high = ncols_dst;
|
||||
int col_diff = ncols_dst;
|
||||
int offset_y = wt*stride_sample_y + zt*stride_channel_y;
|
||||
int offset_dst = wt*stride_sample_dst + zt*stride_channel_dst + jt*J*stride_col_dst;
|
||||
int offset_y = wt*stride_sample_y + zt*stride_channel_y;
|
||||
int offset_dst = wt*stride_sample_dst + zt*stride_channel_dst + jt*J*stride_col_dst;
|
||||
int offset_y_scale;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale = wt*nchannels_y.z*ncols_y + zt*ncols_y;
|
||||
} else {
|
||||
GGML_UNUSED(offset_y_scale);
|
||||
}
|
||||
|
||||
if (ids_dst) {
|
||||
col_low = expert_bounds[zt + 0];
|
||||
@@ -1100,6 +1161,9 @@ static __global__ void mul_mat_q(
|
||||
|
||||
offset_y = 0;
|
||||
offset_dst = 0;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale = 0;
|
||||
}
|
||||
|
||||
if (jt*J >= col_diff) {
|
||||
return;
|
||||
@@ -1122,6 +1186,11 @@ static __global__ void mul_mat_q(
|
||||
|
||||
offset_y += (col_low + jt * J) * (sizeof(block_q8_1_mmq) / sizeof(int));
|
||||
offset_dst += it*I;
|
||||
const float * y_scale_tile = nullptr;
|
||||
if constexpr (type == GGML_TYPE_NVFP4) {
|
||||
offset_y_scale += col_low + jt * J;
|
||||
y_scale_tile = y_scale ? y_scale + offset_y_scale : nullptr;
|
||||
}
|
||||
|
||||
const int tile_x_max_i = nrows_x - it*I - 1;
|
||||
const int tile_y_max_j = col_diff - jt*J - 1;
|
||||
@@ -1130,7 +1199,8 @@ static __global__ void mul_mat_q(
|
||||
|
||||
constexpr bool fixup = true; // Last index writes its data to fixup buffer to avoid data races with other blocks.
|
||||
mul_mat_q_process_tile<type, J, fallback, fixup>
|
||||
(x, offset_x, y + offset_y, ids_dst_shared, dst + offset_dst, tmp_fixup, stride_row_x, ncols_y, stride_col_dst,
|
||||
(x, offset_x, y + offset_y, ids_dst_shared, dst + offset_dst, tmp_fixup, y_scale_tile,
|
||||
stride_row_x, ncols_y, stride_col_dst,
|
||||
tile_x_max_i, tile_y_max_j, kb0_start, kb0_stop);
|
||||
}
|
||||
|
||||
@@ -1274,6 +1344,7 @@ static __global__ void mul_mat_q_stream_k_fixup(
|
||||
|
||||
struct mmq_args {
|
||||
const char * x; ggml_type type_x; const int * y; const int32_t * ids_dst; const int32_t * expert_bounds; float * dst;
|
||||
const float * y_scale;
|
||||
int64_t ncols_x; int64_t nrows_x; int64_t ncols_dst; int64_t stride_row_x; int64_t ncols_y; int64_t nrows_dst;
|
||||
int64_t nchannels_x; int64_t nchannels_y; int64_t stride_channel_x; int64_t stride_channel_y; int64_t stride_channel_dst;
|
||||
int64_t nsamples_x; int64_t nsamples_y; int64_t stride_sample_x; int64_t stride_sample_y; int64_t stride_sample_dst;
|
||||
@@ -1323,7 +1394,7 @@ static void launch_mul_mat_q(ggml_backend_cuda_context & ctx, const mmq_args & a
|
||||
|
||||
if (!ggml_cuda_mmq_get_stream_k(type, J, fallback, cc)) {
|
||||
mul_mat_q<type, J, fallback><<<block_nums_xy_tiling, block_dims, nbytes_shared, stream>>>
|
||||
(args.x, args.y, args.ids_dst, args.expert_bounds, args.dst, nullptr,
|
||||
(args.x, args.y, args.ids_dst, args.expert_bounds, args.dst, nullptr, args.y_scale,
|
||||
blocks_per_ne00_fd, args.nrows_x, args.ncols_dst, args.stride_row_x, args.ncols_y, args.nrows_dst,
|
||||
channel_ratio_fd, nchannels_y_fd, args.stride_channel_x, args.stride_channel_y, args.stride_channel_dst,
|
||||
sample_ratio_fd, nsamples_y_fd, args.stride_sample_x, args.stride_sample_y, args.stride_sample_dst,
|
||||
@@ -1352,7 +1423,7 @@ static void launch_mul_mat_q(ggml_backend_cuda_context & ctx, const mmq_args & a
|
||||
const dim3 block_dims_fixup(block_dims.x, block_dims.y/2, block_dims.z);
|
||||
|
||||
mul_mat_q<type, J, fallback><<<block_nums_stream_k, block_dims, nbytes_shared, stream>>>
|
||||
(args.x, args.y, args.ids_dst, args.expert_bounds, args.dst, tmp_fixup.ptr,
|
||||
(args.x, args.y, args.ids_dst, args.expert_bounds, args.dst, tmp_fixup.ptr, args.y_scale,
|
||||
blocks_per_ne00_fd, args.nrows_x, args.ncols_dst, args.stride_row_x, args.ncols_y, args.nrows_dst,
|
||||
channel_ratio_fd, nchannels_y_fd, args.stride_channel_x, args.stride_channel_y, args.stride_channel_dst,
|
||||
sample_ratio_fd, nsamples_y_fd, args.stride_sample_x, args.stride_sample_y, args.stride_sample_dst,
|
||||
|
||||
+245
-94
@@ -1,6 +1,55 @@
|
||||
#include "quantize.cuh"
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(BLACKWELL_MMA_AVAILABLE)
|
||||
// this maps to 256-bit loads in PTX on supported devices,
|
||||
// and otherwise falls back to 2 128-bit loads
|
||||
struct __builtin_align__(32) float8 {
|
||||
float x; float y; float z; float w;
|
||||
float p; float q; float r; float s;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if CUDART_VERSION >= 12080
|
||||
static __device__ __forceinline__ float nvfp4_native_scale_error(
|
||||
const float vals[QK_NVFP4_SUB], const float inv_col_scale, const float inv_scale, const float scale) {
|
||||
const float scale_dequant = 2.0f * scale;
|
||||
float err = 0.0f;
|
||||
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB; k += 4) {
|
||||
const float v0 = vals[k + 0] * inv_col_scale;
|
||||
const float v1 = vals[k + 1] * inv_col_scale;
|
||||
const float v2 = vals[k + 2] * inv_col_scale;
|
||||
const float v3 = vals[k + 3] * inv_col_scale;
|
||||
|
||||
const __nv_fp4x4_e2m1 q(make_float4(v0 * inv_scale, v1 * inv_scale, v2 * inv_scale, v3 * inv_scale));
|
||||
const __nv_fp4x4_storage_t q_storage = q.__x;
|
||||
const __nv_fp4x2_storage_t q_lo = static_cast<__nv_fp4x2_storage_t>(q_storage);
|
||||
const __nv_fp4x2_storage_t q_hi = static_cast<__nv_fp4x2_storage_t>(q_storage >> 8U);
|
||||
|
||||
const __half2_raw hraw2_lo = __nv_cvt_fp4x2_to_halfraw2(q_lo, __NV_E2M1);
|
||||
const __half2_raw hraw2_hi = __nv_cvt_fp4x2_to_halfraw2(q_hi, __NV_E2M1);
|
||||
const __half2 h2_lo = static_cast<__half2>(hraw2_lo);
|
||||
const __half2 h2_hi = static_cast<__half2>(hraw2_hi);
|
||||
const float2 dq_lo = __half22float2(h2_lo);
|
||||
const float2 dq_hi = __half22float2(h2_hi);
|
||||
|
||||
const float err0 = fabsf(v0) - fabsf(dq_lo.x) * scale_dequant;
|
||||
const float err1 = fabsf(v1) - fabsf(dq_lo.y) * scale_dequant;
|
||||
const float err2 = fabsf(v2) - fabsf(dq_hi.x) * scale_dequant;
|
||||
const float err3 = fabsf(v3) - fabsf(dq_hi.y) * scale_dequant;
|
||||
|
||||
err = fmaf(err0, err0, err);
|
||||
err = fmaf(err1, err1, err);
|
||||
err = fmaf(err2, err2, err);
|
||||
err = fmaf(err3, err3, err);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
#endif // CUDART_VERSION >= 12080
|
||||
|
||||
__launch_bounds__(CUDA_QUANTIZE_BLOCK_SIZE, 1)
|
||||
static __global__ void quantize_q8_1(
|
||||
const float * x_ptr, void * vy_ptr,
|
||||
@@ -74,115 +123,209 @@ __device__ __forceinline__ uint8_t compute_e8m0_scale(float amax) {
|
||||
return static_cast<uint8_t>(biased);
|
||||
}
|
||||
|
||||
|
||||
// scatter: grid over tokens, quantize once, write to all the token's compact rows
|
||||
template <bool scatter>
|
||||
template <bool scatter, bool use_aligned_float8>
|
||||
static __global__ void quantize_mmq_nvfp4(
|
||||
const float * __restrict__ x, const int32_t * __restrict__ ids, void * __restrict__ vy,
|
||||
const float * __restrict__ x, const int32_t * __restrict__ ids, void * __restrict__ vy, float * __restrict__ scale,
|
||||
const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
|
||||
const int64_t ne0, const int64_t ne1, const int64_t ne2, const int n_expert_used) {
|
||||
#if defined(BLACKWELL_MMA_AVAILABLE)
|
||||
|
||||
const int64_t i0_base = ((int64_t) blockDim.x * blockIdx.y + threadIdx.x) * QK_NVFP4_SUB;
|
||||
if (i0_base >= ne0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t k_block = i0_base / QK_FP4_MMQ;
|
||||
const int64_t blocks_per_col = (ne0 + QK_FP4_MMQ - 1) / QK_FP4_MMQ;
|
||||
if (k_block >= blocks_per_col) {
|
||||
return;
|
||||
}
|
||||
const int sub = (i0_base % QK_FP4_MMQ) / QK_NVFP4_SUB;
|
||||
|
||||
int64_t base_idx;
|
||||
if constexpr (scatter) {
|
||||
base_idx = (int64_t) blockIdx.x * s02; // one physical row per token
|
||||
} else {
|
||||
const int64_t i2 = blockIdx.z % ne2;
|
||||
const int64_t i3 = blockIdx.z / ne2;
|
||||
const int64_t i2 = blockIdx.y % ne2;
|
||||
const int64_t i3 = blockIdx.y / ne2;
|
||||
const int64_t i01 = ids ? ids[blockIdx.x] : blockIdx.x;
|
||||
base_idx = i3 * s03 + i2 * s02 + i01 * s01;
|
||||
}
|
||||
const float * __restrict__ x_row = x + base_idx;
|
||||
|
||||
float vals_raw[QK_NVFP4_SUB];
|
||||
float amax_raw = 0.0f;
|
||||
float amax = 0.0f;
|
||||
if constexpr (use_aligned_float8) {
|
||||
for (int64_t i0 = 8 * threadIdx.x; i0 < ne00; i0 += 8 * blockDim.x) {
|
||||
const float * x_base = x_row + i0;
|
||||
const float8 v = reinterpret_cast<const float8 *>(x_base)[0];
|
||||
amax = fmaxf(amax, fabsf(v.x));
|
||||
amax = fmaxf(amax, fabsf(v.y));
|
||||
amax = fmaxf(amax, fabsf(v.z));
|
||||
amax = fmaxf(amax, fabsf(v.w));
|
||||
amax = fmaxf(amax, fabsf(v.p));
|
||||
amax = fmaxf(amax, fabsf(v.q));
|
||||
amax = fmaxf(amax, fabsf(v.r));
|
||||
amax = fmaxf(amax, fabsf(v.s));
|
||||
}
|
||||
} else {
|
||||
for (int64_t i0 = threadIdx.x; i0 < ne00; i0 += blockDim.x) {
|
||||
amax = fmaxf(amax, fabsf(x_row[i0]));
|
||||
}
|
||||
}
|
||||
|
||||
amax = warp_reduce_max<WARP_SIZE>(amax);
|
||||
|
||||
__shared__ float warp_amax[CUDA_QUANTIZE_BLOCK_SIZE_MMQ / WARP_SIZE];
|
||||
const int lane = threadIdx.x % WARP_SIZE;
|
||||
const int warp = threadIdx.x / WARP_SIZE;
|
||||
|
||||
if (lane == 0) {
|
||||
warp_amax[warp] = amax;
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
if (warp == 0) {
|
||||
amax = threadIdx.x < int(CUDA_QUANTIZE_BLOCK_SIZE_MMQ / WARP_SIZE) ? warp_amax[lane] : 0.0f;
|
||||
amax = warp_reduce_max<WARP_SIZE>(amax);
|
||||
if (lane == 0) {
|
||||
warp_amax[0] = amax / (6.0f * 448.0f);
|
||||
if constexpr (scatter) {
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB; k++) {
|
||||
const int64_t i00 = i0_base + k;
|
||||
if (i00 < ne00) {
|
||||
const float v = x[base_idx + i00];
|
||||
vals_raw[k] = v;
|
||||
amax_raw = fmaxf(amax_raw, fabsf(v));
|
||||
} else {
|
||||
vals_raw[k] = 0.0f;
|
||||
for (int slot = 0; slot < n_expert_used; ++slot) {
|
||||
const int64_t i = ids[(int64_t) blockIdx.x * n_expert_used + slot];
|
||||
scale[i] = warp_amax[0];
|
||||
}
|
||||
} else {
|
||||
scale[blockIdx.y * ne1 + blockIdx.x] = warp_amax[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr int test_offsets[5] = { 0, -1, 1, -2, 2};
|
||||
const int first_fp8_code = (int) ggml_cuda_fp32_to_ue4m3(amax_raw / 6.0f);
|
||||
|
||||
float best_err = FLT_MAX;
|
||||
uint8_t fp8_code = 0;
|
||||
float subblock_scale = 0.0f;
|
||||
|
||||
#pragma unroll // Check +/- 2 to find best code to reduce NVFP4 activation loss. Negligible overhead on Blackwell.
|
||||
for (int i = 0; i < 5; i++) {
|
||||
const int test_code = first_fp8_code + test_offsets[i];
|
||||
if (test_code < 0 || test_code > 0x7e) {
|
||||
continue;
|
||||
}
|
||||
const uint8_t code = (uint8_t) test_code;
|
||||
const float test_scale = ggml_cuda_ue4m3_to_fp32(code);
|
||||
const float test_inv_scale = test_scale > 0.0f ? 0.5f / test_scale : 0.0f;
|
||||
float cur_err = 0.0f;
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
|
||||
const float v = vals_raw[k];
|
||||
const uint8_t q = ggml_cuda_float_to_fp4_e2m1(v, test_inv_scale);
|
||||
const float err_diff = fabsf(v) - fabsf(kvalues_mxfp4[q & 0x7]) * test_scale;
|
||||
cur_err = fmaf(err_diff, err_diff, cur_err);
|
||||
}
|
||||
|
||||
if (cur_err < best_err) {
|
||||
best_err = cur_err;
|
||||
fp8_code = test_code;
|
||||
subblock_scale = test_scale;
|
||||
}
|
||||
}
|
||||
|
||||
const float inv_scale = subblock_scale > 0.0f ? 0.5f / subblock_scale : 0.0f;
|
||||
uint32_t q0 = 0;
|
||||
uint32_t q1 = 0;
|
||||
#pragma unroll // this is faster than the previous __nv_fp4x4_e2m1
|
||||
for (int k = 0; k < QK_NVFP4_SUB / 4; ++k) {
|
||||
q0 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 0], inv_scale) << (8 * k);
|
||||
q0 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 8], inv_scale) << (8 * k + 4);
|
||||
q1 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 4], inv_scale) << (8 * k);
|
||||
q1 |= (uint32_t) ggml_cuda_float_to_fp4_e2m1(vals_raw[k + 12], inv_scale) << (8 * k + 4);
|
||||
}
|
||||
__syncthreads();
|
||||
|
||||
block_fp4_mmq * y = (block_fp4_mmq *) vy;
|
||||
if constexpr (scatter) {
|
||||
const int64_t n_subblocks = (ne0 + QK_NVFP4_SUB - 1) / QK_NVFP4_SUB;
|
||||
|
||||
for (int64_t isb = threadIdx.x; isb < n_subblocks; isb += blockDim.x) {
|
||||
const int64_t i0_base = isb * QK_NVFP4_SUB;
|
||||
const int64_t k_block = i0_base / QK_FP4_MMQ;
|
||||
const int sub = (i0_base % QK_FP4_MMQ) / QK_NVFP4_SUB;
|
||||
|
||||
const float row_scale = warp_amax[0];
|
||||
const float inv_col_scale = row_scale > 0.0f ? 1.0f / row_scale : 0.0f;
|
||||
|
||||
float vals[QK_NVFP4_SUB];
|
||||
if constexpr (use_aligned_float8) {
|
||||
const float * x_base = x_row + i0_base;
|
||||
const float8 v0 = i0_base + 7 < ne00 ? reinterpret_cast<const float8 *>(x_base)[0] : float8{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
||||
const float8 v1 = i0_base + 15 < ne00 ? reinterpret_cast<const float8 *>(x_base + 8)[0] : float8{0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
||||
vals[0] = v0.x; vals[1] = v0.y; vals[2] = v0.z; vals[3] = v0.w;
|
||||
vals[4] = v0.p; vals[5] = v0.q; vals[6] = v0.r; vals[7] = v0.s;
|
||||
vals[8] = v1.x; vals[9] = v1.y; vals[10] = v1.z; vals[11] = v1.w;
|
||||
vals[12] = v1.p; vals[13] = v1.q; vals[14] = v1.r; vals[15] = v1.s;
|
||||
} else {
|
||||
#pragma unroll
|
||||
for (int slot = 0; slot < n_expert_used; ++slot) {
|
||||
const int64_t i = ids[(int64_t) blockIdx.x * n_expert_used + slot];
|
||||
block_fp4_mmq * yb = y + (k_block * ne1 + i);
|
||||
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
|
||||
const int64_t i00 = i0_base + k;
|
||||
vals[k] = i00 < ne00 ? x_row[i00] : 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t q0 = 0;
|
||||
uint32_t q1 = 0;
|
||||
|
||||
float amax_sub = 0.0f;
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
|
||||
amax_sub = fmaxf(amax_sub, fabsf(vals[k] * inv_col_scale));
|
||||
}
|
||||
|
||||
static constexpr int test_offsets[5] = { 0, -1, 1, -2, 2 };
|
||||
const int first_fp8_code = (int) ggml_cuda_fp32_to_ue4m3(amax_sub / 6.0f);
|
||||
|
||||
uint8_t fp8_code = (uint8_t) first_fp8_code;
|
||||
float subblock_scale = ggml_cuda_ue4m3_to_fp32(fp8_code);
|
||||
float inv_scale_err = subblock_scale > 0.0f ? 0.5f / subblock_scale : 0.0f;
|
||||
#if CUDART_VERSION >= 12080
|
||||
float best_err = nvfp4_native_scale_error(vals, inv_col_scale, inv_scale_err, subblock_scale);
|
||||
#else
|
||||
float best_err = 0.0f;
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
|
||||
const float v = vals[k] * inv_col_scale;
|
||||
const uint8_t q = ggml_cuda_float_to_fp4_e2m1(v, inv_scale_err);
|
||||
const float err_diff = fabsf(v) - fabsf(kvalues_fp4[q & 0x7]) * subblock_scale;
|
||||
best_err = fmaf(err_diff, err_diff, best_err);
|
||||
}
|
||||
#endif // CUDART_VERSION >= 12080
|
||||
|
||||
#pragma unroll
|
||||
for (int i = 1; i < 5; ++i) {
|
||||
const int test_code = first_fp8_code + test_offsets[i];
|
||||
if (test_code < 0 || test_code > 0x7e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const float test_scale = ggml_cuda_ue4m3_to_fp32((uint8_t) test_code);
|
||||
const float test_inv_scale = test_scale > 0.0f ? 0.5f / test_scale : 0.0f;
|
||||
#if CUDART_VERSION >= 12080
|
||||
const float cur_err = nvfp4_native_scale_error(vals, inv_col_scale, test_inv_scale, test_scale);
|
||||
#else
|
||||
float cur_err = 0.0f;
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB; ++k) {
|
||||
const float v = vals[k] * inv_col_scale;
|
||||
const uint8_t q = ggml_cuda_float_to_fp4_e2m1(v, test_inv_scale);
|
||||
const float err_diff = fabsf(v) - fabsf(kvalues_fp4[q & 0x7]) * test_scale;
|
||||
cur_err = fmaf(err_diff, err_diff, cur_err);
|
||||
}
|
||||
#endif // CUDART_VERSION >= 12080
|
||||
|
||||
if (cur_err < best_err) {
|
||||
best_err = cur_err;
|
||||
fp8_code = (uint8_t) test_code;
|
||||
subblock_scale = test_scale;
|
||||
}
|
||||
}
|
||||
#if CUDART_VERSION >= 12080
|
||||
const float inv_scale = subblock_scale > 0.0f ? 0.5f / subblock_scale : 0.0f;
|
||||
const float s = inv_col_scale * inv_scale;
|
||||
|
||||
__nv_fp4x4_e2m1 q0_lo(make_float4(vals[0] * s, vals[8] * s, vals[1] * s, vals[9] * s));
|
||||
__nv_fp4x4_e2m1 q0_hi(make_float4(vals[2] * s, vals[10] * s, vals[3] * s, vals[11] * s));
|
||||
__nv_fp4x4_e2m1 q1_lo(make_float4(vals[4] * s, vals[12] * s, vals[5] * s, vals[13] * s));
|
||||
__nv_fp4x4_e2m1 q1_hi(make_float4(vals[6] * s, vals[14] * s, vals[7] * s, vals[15] * s));
|
||||
|
||||
const char2 q0_lo_c = *reinterpret_cast<char2 *>(&q0_lo);
|
||||
const char2 q0_hi_c = *reinterpret_cast<char2 *>(&q0_hi);
|
||||
const char2 q1_lo_c = *reinterpret_cast<char2 *>(&q1_lo);
|
||||
const char2 q1_hi_c = *reinterpret_cast<char2 *>(&q1_hi);
|
||||
|
||||
q0 = uint32_t(uint8_t(q0_lo_c.x)) | (uint32_t(uint8_t(q0_lo_c.y)) << 8) |
|
||||
(uint32_t(uint8_t(q0_hi_c.x)) << 16) | (uint32_t(uint8_t(q0_hi_c.y)) << 24);
|
||||
q1 = uint32_t(uint8_t(q1_lo_c.x)) | (uint32_t(uint8_t(q1_lo_c.y)) << 8) |
|
||||
(uint32_t(uint8_t(q1_hi_c.x)) << 16) | (uint32_t(uint8_t(q1_hi_c.y)) << 24);
|
||||
#else
|
||||
const float inv_scale = subblock_scale > 0.0f ? 0.5f / subblock_scale : 0.0f;
|
||||
#pragma unroll
|
||||
for (int k = 0; k < QK_NVFP4_SUB / 4; ++k) {
|
||||
q0 |= uint32_t(ggml_cuda_float_to_fp4_e2m1(vals[k + 0] * inv_col_scale, inv_scale)) << (8 * k);
|
||||
q0 |= uint32_t(ggml_cuda_float_to_fp4_e2m1(vals[k + 8] * inv_col_scale, inv_scale)) << (8 * k + 4);
|
||||
q1 |= uint32_t(ggml_cuda_float_to_fp4_e2m1(vals[k + 4] * inv_col_scale, inv_scale)) << (8 * k);
|
||||
q1 |= uint32_t(ggml_cuda_float_to_fp4_e2m1(vals[k + 12] * inv_col_scale, inv_scale)) << (8 * k + 4);
|
||||
}
|
||||
#endif // CUDART_VERSION >= 12080
|
||||
|
||||
if constexpr (scatter) {
|
||||
#pragma unroll
|
||||
for (int slot = 0; slot < n_expert_used; ++slot) {
|
||||
const int64_t i = ids[(int64_t) blockIdx.x * n_expert_used + slot];
|
||||
block_fp4_mmq * yb = y + (k_block * ne1 + i);
|
||||
uint32_t * yqs = reinterpret_cast<uint32_t *>(yb->qs);
|
||||
yqs[2 * sub + 0] = q0;
|
||||
yqs[2 * sub + 1] = q1;
|
||||
reinterpret_cast<uint8_t *>(yb->d4)[sub] = fp8_code;
|
||||
}
|
||||
} else {
|
||||
block_fp4_mmq * yb = y + (blockIdx.y * ((int64_t) blocks_per_col * ne1) + k_block * ne1 + blockIdx.x);
|
||||
uint32_t * yqs = reinterpret_cast<uint32_t *>(yb->qs);
|
||||
yqs[2 * sub + 0] = q0;
|
||||
yqs[2 * sub + 1] = q1;
|
||||
reinterpret_cast<uint8_t *>(yb->d4)[sub] = fp8_code;
|
||||
}
|
||||
} else {
|
||||
block_fp4_mmq * yb = y + (blockIdx.z * ((int64_t) blocks_per_col * ne1) + k_block * ne1 + blockIdx.x);
|
||||
uint32_t * yqs = reinterpret_cast<uint32_t *>(yb->qs);
|
||||
yqs[2 * sub + 0] = q0;
|
||||
yqs[2 * sub + 1] = q1;
|
||||
reinterpret_cast<uint8_t *>(yb->d4)[sub] = fp8_code;
|
||||
}
|
||||
GGML_UNUSED(n_expert_used);
|
||||
#else
|
||||
GGML_UNUSED(n_expert_used);
|
||||
GGML_UNUSED_VARS(x, ids, vy, scale, ne00, s01, s02, s03, ne0, ne1, ne2, n_expert_used);
|
||||
NO_DEVICE_CODE; // This is for Blackwell NVFP4 activations only.
|
||||
#endif // defined(BLACKWELL_MMA_AVAILABLE)
|
||||
|
||||
@@ -491,18 +634,22 @@ void quantize_scatter_mmq_q8_1_cuda(
|
||||
|
||||
// scatter=true reuses the quant kernels: grid over tokens, ids = inverse map (token slot -> compact row)
|
||||
void quantize_scatter_mmq_fp4_cuda(
|
||||
const float * x, const int32_t * ids_src1_inv, void * vy, const ggml_type type_src0,
|
||||
const float * x, const int32_t * ids_src1_inv, void * vy, float * scale, const ggml_type type_src0, const bool use_aligned_float8,
|
||||
const int64_t ne00, const int64_t stride_token, const int64_t ne0,
|
||||
const int64_t n_tokens, const int64_t nrows_dst, const int n_expert_used, cudaStream_t stream) {
|
||||
GGML_ASSERT(ne0 > 0);
|
||||
if (type_src0 == GGML_TYPE_NVFP4) {
|
||||
GGML_ASSERT(scale);
|
||||
GGML_ASSERT(ne00 % QK_NVFP4 == 0);
|
||||
constexpr int nvfp4_block_size = 128;
|
||||
const int64_t block_num_y = (ne0 + QK_NVFP4_SUB * nvfp4_block_size - 1) / (QK_NVFP4_SUB * nvfp4_block_size);
|
||||
const dim3 block_size(nvfp4_block_size, 1, 1);
|
||||
const dim3 num_blocks(n_tokens, block_num_y, 1);
|
||||
quantize_mmq_nvfp4<true><<<num_blocks, block_size, 0, stream>>>(
|
||||
x, ids_src1_inv, vy, ne00, /*s01=*/0, /*s02=*/stride_token, /*s03=*/0, ne0, /*ne1=*/nrows_dst, /*ne2=*/1, n_expert_used);
|
||||
const dim3 block_size(CUDA_QUANTIZE_BLOCK_SIZE_MMQ, 1, 1);
|
||||
const dim3 num_blocks(n_tokens, 1, 1);
|
||||
if (use_aligned_float8) {
|
||||
quantize_mmq_nvfp4<true, true><<<num_blocks, block_size, 0, stream>>>(
|
||||
x, ids_src1_inv, vy, scale, ne00, /*s01=*/0, /*s02=*/stride_token, /*s03=*/0, ne0, /*ne1=*/nrows_dst, /*ne2=*/1, n_expert_used);
|
||||
} else {
|
||||
quantize_mmq_nvfp4<true, false><<<num_blocks, block_size, 0, stream>>>(
|
||||
x, ids_src1_inv, vy, scale, ne00, /*s01=*/0, /*s02=*/stride_token, /*s03=*/0, ne0, /*ne1=*/nrows_dst, /*ne2=*/1, n_expert_used);
|
||||
}
|
||||
} else {
|
||||
GGML_ASSERT(type_src0 == GGML_TYPE_MXFP4);
|
||||
constexpr int nwarps = 8;
|
||||
@@ -516,20 +663,24 @@ void quantize_scatter_mmq_fp4_cuda(
|
||||
}
|
||||
|
||||
void quantize_mmq_fp4_cuda(
|
||||
const float * x, const int32_t * ids, void * vy, const ggml_type type_src0,
|
||||
const float * x, const int32_t * ids, void * vy, float * scale, const ggml_type type_src0, const bool use_aligned_float8,
|
||||
const int64_t ne00, const int64_t s01, const int64_t s02, const int64_t s03,
|
||||
const int64_t ne0, const int64_t ne1, const int64_t ne2, const int64_t ne3, cudaStream_t stream) {
|
||||
GGML_ASSERT(type_src0 == GGML_TYPE_MXFP4 || type_src0 == GGML_TYPE_NVFP4);
|
||||
GGML_ASSERT(ne0 > 0);
|
||||
|
||||
if (type_src0 == GGML_TYPE_NVFP4) {
|
||||
GGML_ASSERT(scale);
|
||||
GGML_ASSERT(ne00 % QK_NVFP4 == 0);
|
||||
constexpr int nvfp4_block_size = 128;
|
||||
const int64_t block_num_y = (ne0 + QK_NVFP4_SUB * nvfp4_block_size - 1) / (QK_NVFP4_SUB * nvfp4_block_size);
|
||||
const dim3 block_size(nvfp4_block_size, 1, 1);
|
||||
const dim3 num_blocks(ne1, block_num_y, ne2 * ne3);
|
||||
quantize_mmq_nvfp4<false><<<num_blocks, block_size, 0, stream>>>(
|
||||
x, ids, vy, ne00, s01, s02, s03, ne0, ne1, ne2, /*n_expert_used=*/0);
|
||||
const dim3 block_size(CUDA_QUANTIZE_BLOCK_SIZE_MMQ, 1, 1);
|
||||
const dim3 num_blocks(ne1, ne2 * ne3, 1);
|
||||
if (use_aligned_float8) {
|
||||
quantize_mmq_nvfp4<false, true><<<num_blocks, block_size, 0, stream>>>(
|
||||
x, ids, vy, scale, ne00, s01, s02, s03, ne0, ne1, ne2, /*n_expert_used=*/0);
|
||||
} else {
|
||||
quantize_mmq_nvfp4<false, false><<<num_blocks, block_size, 0, stream>>>(
|
||||
x, ids, vy, scale, ne00, s01, s02, s03, ne0, ne1, ne2, /*n_expert_used=*/0);
|
||||
}
|
||||
} else {
|
||||
GGML_ASSERT(ne0 % (2 * QK_MXFP4) == 0);
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@ void quantize_mmq_q8_1_cuda(
|
||||
void quantize_mmq_fp4_cuda(const float * x,
|
||||
const int32_t * ids,
|
||||
void * vy,
|
||||
float * scale,
|
||||
ggml_type type_src0,
|
||||
bool use_aligned_float8,
|
||||
int64_t ne00,
|
||||
int64_t s01,
|
||||
int64_t s02,
|
||||
@@ -44,7 +46,9 @@ void quantize_mmq_fp4_cuda(const float * x,
|
||||
void quantize_scatter_mmq_fp4_cuda(const float * x,
|
||||
const int32_t * ids_src1_inv,
|
||||
void * vy,
|
||||
float * scale,
|
||||
ggml_type type_src0,
|
||||
bool use_aligned_float8,
|
||||
int64_t ne00,
|
||||
int64_t stride_token,
|
||||
int64_t ne0,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
// Kernel config struct - passed by value to CUDA kernel
|
||||
struct topk_moe_config {
|
||||
bool use_sigmoid;
|
||||
bool use_sqrt_softplus;
|
||||
bool with_norm;
|
||||
bool delayed_softmax;
|
||||
};
|
||||
@@ -67,6 +68,16 @@ __device__ void sigmoid_warp_inplace(float (&vals)[experts_per_thread], const in
|
||||
}
|
||||
}
|
||||
|
||||
template <int experts_per_thread, bool use_limit>
|
||||
__device__ void sqrt_softplus_warp_inplace(float (&vals)[experts_per_thread], const int limit, const int lane) {
|
||||
#pragma unroll
|
||||
for (int i = 0; i < experts_per_thread; i++) {
|
||||
const int idx = lane + i * WARP_SIZE;
|
||||
const bool active = !use_limit || (idx < limit);
|
||||
vals[i] = active ? sqrtf(vals[i] > 20.0f ? vals[i] : logf(1.0f + expf(vals[i]))) : -INFINITY;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This kernel does the following:
|
||||
1. optionally softmax over the logits per token [n_experts, n_tokens]
|
||||
@@ -115,6 +126,8 @@ __launch_bounds__(4 * WARP_SIZE, 1) __global__ void topk_moe_cuda(const float *
|
||||
if (!config.delayed_softmax) {
|
||||
if (config.use_sigmoid) {
|
||||
sigmoid_warp_inplace<experts_per_thread, false>(wt, n_experts, threadIdx.x);
|
||||
} else if (config.use_sqrt_softplus) {
|
||||
sqrt_softplus_warp_inplace<experts_per_thread, false>(wt, n_experts, threadIdx.x);
|
||||
} else {
|
||||
softmax_warp_inplace<experts_per_thread, false>(wt, n_experts, threadIdx.x);
|
||||
}
|
||||
@@ -364,9 +377,10 @@ void ggml_cuda_op_topk_moe(ggml_backend_cuda_context & ctx,
|
||||
}
|
||||
|
||||
topk_moe_config config;
|
||||
config.use_sigmoid = args.sigmoid;
|
||||
config.with_norm = with_norm;
|
||||
config.delayed_softmax = args.delayed_softmax;
|
||||
config.use_sigmoid = args.sigmoid;
|
||||
config.use_sqrt_softplus = args.sqrt_softplus;
|
||||
config.with_norm = with_norm;
|
||||
config.delayed_softmax = args.delayed_softmax;
|
||||
|
||||
if (bias) {
|
||||
launch_topk_moe_cuda<true>(ctx, logits_d, weights_d, ids_d, bias_d, n_rows, n_experts, n_expert_used, clamp_val,
|
||||
@@ -415,7 +429,7 @@ bool ggml_cuda_should_use_topk_moe(const ggml_tensor * gating_op,
|
||||
} else if (gating_op->op == GGML_OP_UNARY) {
|
||||
ggml_unary_op op = ggml_get_unary_op(gating_op);
|
||||
|
||||
if (op != GGML_UNARY_OP_SIGMOID) {
|
||||
if (op != GGML_UNARY_OP_SIGMOID && op != GGML_UNARY_OP_SOFTPLUS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
struct ggml_cuda_topk_moe_args {
|
||||
bool sigmoid{};
|
||||
bool sqrt_softplus{};
|
||||
bool softmax{};
|
||||
bool delayed_softmax{};
|
||||
bool prob_bias{};
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#include <algorithm>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
# endif
|
||||
# include <windows.h>
|
||||
# include <sal.h>
|
||||
#else
|
||||
# include <semaphore.h>
|
||||
@@ -28,7 +33,9 @@
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wnested-anon-types"
|
||||
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
|
||||
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
|
||||
#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
|
||||
|
||||
#include <AEEStdErr.h>
|
||||
#include <dspqueue.h>
|
||||
@@ -134,6 +141,8 @@ static const char * htp_event_name(uint16_t id) {
|
||||
case HTP_TRACE_EVT_HVX_FA_K_PREP: return "HVX_K_PREP";
|
||||
case HTP_TRACE_EVT_HVX_FA_V_PREP: return "HVX_V_PREP";
|
||||
case HTP_TRACE_EVT_HMX_COMP: return "HMX_COMP";
|
||||
case HTP_TRACE_EVT_L2FLUSH: return "L2FLUSH";
|
||||
case HTP_TRACE_EVT_INIT: return "INIT";
|
||||
default: return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
@@ -501,6 +510,8 @@ static void repack_q4_0_tiled(ggml_tensor * t, const void * data, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack q4_0_tiled tensor into q4_0 data
|
||||
@@ -554,6 +565,8 @@ static void repack_tiled_q4_0(void * data, const ggml_tensor * t, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack q4_1 data into q4_1_tiled tensor
|
||||
@@ -611,6 +624,8 @@ static void repack_q4_1_tiled(ggml_tensor * t, const void * data, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack q4_1_tiled tensor into q4_1 data
|
||||
@@ -665,6 +680,8 @@ static void repack_tiled_q4_1(void * data, const ggml_tensor * t, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack q8_0 data into q8_0_tiled tensor
|
||||
@@ -711,6 +728,8 @@ static void repack_q8_0_tiled(ggml_tensor * t, const void * data, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack q8_0_tiled tensor into q8_0 data
|
||||
@@ -761,6 +780,8 @@ static void repack_tiled_q8_0(void * data, const ggml_tensor * t, size_t size) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack mxfp4 data into mxfp4_tiled tensor
|
||||
@@ -812,6 +833,8 @@ static void repack_mxfp4_tiled(ggml_tensor * t, const void * data, size_t size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
// repack mxfp4_tiled tensor into mxfp4 data
|
||||
@@ -865,6 +888,8 @@ static void repack_tiled_mxfp4(void * data, const ggml_tensor * t, size_t size)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(size);
|
||||
}
|
||||
|
||||
static void ggml_backend_hexagon_buffer_set_tensor(ggml_backend_buffer_t buffer,
|
||||
@@ -965,11 +990,12 @@ static void ggml_backend_hexagon_buffer_get_tensor(ggml_backend_buffer_t buffer,
|
||||
static bool ggml_backend_hexagon_buffer_cpy_tensor(ggml_backend_buffer_t buffer,
|
||||
const struct ggml_tensor * src,
|
||||
struct ggml_tensor * dst) {
|
||||
// we might optimize this later, for now take the slow path (ie get/set_tensor)
|
||||
return false;
|
||||
|
||||
GGML_UNUSED(buffer);
|
||||
GGML_UNUSED(src);
|
||||
GGML_UNUSED(dst);
|
||||
// we might optimize this later, for now take the slow path (ie get/set_tensor)
|
||||
return false;
|
||||
}
|
||||
|
||||
static void ggml_backend_hexagon_buffer_clear(ggml_backend_buffer_t buffer, uint8_t value) {
|
||||
@@ -1025,9 +1051,9 @@ static ggml_backend_buffer_t ggml_backend_hexagon_repack_buffer_type_alloc_buffe
|
||||
}
|
||||
}
|
||||
|
||||
static size_t ggml_backend_hexagon_buffer_type_get_alignment(ggml_backend_buffer_type_t buffer_type) {
|
||||
static size_t ggml_backend_hexagon_buffer_type_get_alignment(ggml_backend_buffer_type_t buft) {
|
||||
return 128; // HVX alignment
|
||||
GGML_UNUSED(buffer_type);
|
||||
GGML_UNUSED(buft);
|
||||
}
|
||||
|
||||
static size_t ggml_backend_hexagon_buffer_type_get_alloc_size(ggml_backend_buffer_type_t buft, const struct ggml_tensor * t) {
|
||||
@@ -1039,20 +1065,24 @@ static size_t ggml_backend_hexagon_buffer_type_get_alloc_size(ggml_backend_buffe
|
||||
return ggml_row_size(t->type, ne0) * ne1 * ne2 * ne3;
|
||||
}
|
||||
return ggml_nbytes(t);
|
||||
|
||||
GGML_UNUSED(buft);
|
||||
}
|
||||
|
||||
static size_t ggml_backend_hexagon_buffer_type_get_max_size(ggml_backend_buffer_type_t buffer_type) {
|
||||
auto * context = static_cast<ggml_backend_hexagon_buffer_type_context *>(buffer_type->context);
|
||||
static size_t ggml_backend_hexagon_buffer_type_get_max_size(ggml_backend_buffer_type_t buft) {
|
||||
auto * context = static_cast<ggml_backend_hexagon_buffer_type_context *>(buft->context);
|
||||
return context->sess->max_bufsize;
|
||||
}
|
||||
|
||||
static bool ggml_backend_hexagon_buffer_type_is_host(ggml_backend_buffer_type_t buft) {
|
||||
return opt_hostbuf;
|
||||
|
||||
GGML_UNUSED(buft);
|
||||
}
|
||||
|
||||
static bool ggml_backend_hexagon_repack_buffer_type_is_host(ggml_backend_buffer_type_t buft) {
|
||||
return false;
|
||||
|
||||
GGML_UNUSED(buft);
|
||||
}
|
||||
|
||||
@@ -1098,6 +1128,14 @@ struct ggml_hexagon_opbatch {
|
||||
std::unordered_map<const ggml_tensor*, int> t_map; // tensor ptr to index
|
||||
std::unordered_multimap<void*, int> d_map; // tensor data to index
|
||||
|
||||
struct tensor_range {
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
int bi;
|
||||
std::vector<int> tensors;
|
||||
};
|
||||
std::vector<tensor_range> ranges;
|
||||
|
||||
unsigned int n_bufs; // num buffers in the batch
|
||||
unsigned int n_tens; // num tensors ...
|
||||
unsigned int n_ops; // num ops ...
|
||||
@@ -1117,6 +1155,7 @@ struct ggml_hexagon_opbatch {
|
||||
b_map.clear();
|
||||
t_map.clear();
|
||||
d_map.clear();
|
||||
ranges.clear();
|
||||
}
|
||||
|
||||
ggml_hexagon_opbatch(ggml_hexagon_session *sess, size_t batch_size, size_t max_vmem) {
|
||||
@@ -1124,7 +1163,7 @@ struct ggml_hexagon_opbatch {
|
||||
|
||||
n_bufs_max = HTP_OP_MAX_BUFS;
|
||||
n_ops_max = batch_size;
|
||||
n_tens_max = n_ops_max + n_ops_max * HTP_OP_MAX_INPUTS;
|
||||
n_tens_max = std::min<size_t>(n_ops_max + n_ops_max * HTP_OP_MAX_INPUTS, HTP_OP_MAX_TENSORS);
|
||||
|
||||
b_vmem_max = max_vmem;
|
||||
|
||||
@@ -1170,6 +1209,71 @@ struct ggml_hexagon_opbatch {
|
||||
return bi;
|
||||
}
|
||||
|
||||
void add_range(const htp_tensor * h, int ti) {
|
||||
uint64_t t_start = h->data;
|
||||
uint64_t t_end = t_start + h->size;
|
||||
int bi = h->bi;
|
||||
|
||||
int first_match = -1;
|
||||
int unused_idx = -1;
|
||||
for (size_t i = 0; i < ranges.size(); i++) {
|
||||
if (ranges[i].bi == -1) {
|
||||
unused_idx = i;
|
||||
continue;
|
||||
}
|
||||
if (ranges[i].bi != bi) {
|
||||
continue;
|
||||
}
|
||||
if (ranges[i].start >= t_end || ranges[i].end <= t_start) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (first_match == -1) {
|
||||
first_match = i;
|
||||
HEX_VERBOSE("ggml-hex: %s range-grow #%d : bi %d [%p, %p) + #%d [%p, %p) -> [%p, %p)\n",
|
||||
sess->c_name(), (int) i, ranges[i].bi,
|
||||
(void *) (h_bufs[ranges[i].bi].base + ranges[i].start),
|
||||
(void *) (h_bufs[ranges[i].bi].base + ranges[i].end),
|
||||
ti,
|
||||
(void *) (h_bufs[bi].base + t_start),
|
||||
(void *) (h_bufs[bi].base + t_end),
|
||||
(void *) (h_bufs[ranges[i].bi].base + std::min(ranges[i].start, t_start)),
|
||||
(void *) (h_bufs[ranges[i].bi].base + std::max(ranges[i].end, t_end)));
|
||||
|
||||
ranges[i].start = std::min(ranges[i].start, t_start);
|
||||
ranges[i].end = std::max(ranges[i].end, t_end);
|
||||
ranges[i].tensors.push_back(ti);
|
||||
} else {
|
||||
HEX_VERBOSE("ggml-hex: %s range-merge #%d [%p, %p) + #%d [%p, %p) -> [%p, %p)\n",
|
||||
sess->c_name(), first_match,
|
||||
(void *) (h_bufs[bi].base + ranges[first_match].start),
|
||||
(void *) (h_bufs[bi].base + ranges[first_match].end),
|
||||
(int) i,
|
||||
(void *) (h_bufs[bi].base + ranges[i].start),
|
||||
(void *) (h_bufs[bi].base + ranges[i].end),
|
||||
(void *) (h_bufs[bi].base + std::min(ranges[first_match].start, ranges[i].start)),
|
||||
(void *) (h_bufs[bi].base + std::max(ranges[first_match].end, ranges[i].end)));
|
||||
|
||||
ranges[first_match].start = std::min(ranges[first_match].start, ranges[i].start);
|
||||
ranges[first_match].end = std::max(ranges[first_match].end, ranges[i].end);
|
||||
ranges[first_match].tensors.insert(
|
||||
ranges[first_match].tensors.end(),
|
||||
ranges[i].tensors.begin(),
|
||||
ranges[i].tensors.end()
|
||||
);
|
||||
ranges[i].bi = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (first_match == -1) {
|
||||
if (unused_idx != -1) {
|
||||
ranges[unused_idx] = {t_start, t_end, bi, {ti}};
|
||||
} else {
|
||||
ranges.push_back({t_start, t_end, bi, {ti}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool same_shape(const htp_tensor * h, const ggml_tensor * t) const {
|
||||
int64_t ne0 = t->ne[0];
|
||||
int64_t ne1 = t->ne[1];
|
||||
@@ -1182,7 +1286,8 @@ struct ggml_hexagon_opbatch {
|
||||
int64_t nb2 = is_repack ? nb1 * ne1 : t->nb[2];
|
||||
int64_t nb3 = is_repack ? nb2 * t->ne[2] : t->nb[3];
|
||||
|
||||
return (h->ne[0] == ne0) && (h->ne[1] == ne1) && (h->ne[2] == t->ne[2]) && (h->ne[3] == t->ne[3]) &&
|
||||
return (h->type == t->type) &&
|
||||
(h->ne[0] == ne0) && (h->ne[1] == ne1) && (h->ne[2] == t->ne[2]) && (h->ne[3] == t->ne[3]) &&
|
||||
(h->nb[0] == t->nb[0]) && (h->nb[1] == nb1) && (h->nb[2] == nb2) && (h->nb[3] == nb3);
|
||||
}
|
||||
|
||||
@@ -1213,6 +1318,7 @@ struct ggml_hexagon_opbatch {
|
||||
|
||||
htp_tensor &h = h_tens[ti];
|
||||
h.bi = add_buffer(sbuf);
|
||||
h.ti = ti;
|
||||
h.data = t_offset;
|
||||
h.type = t->type;
|
||||
|
||||
@@ -1235,8 +1341,11 @@ struct ggml_hexagon_opbatch {
|
||||
h.nb[0] = t->nb[0]; h.nb[1] = t->nb[1]; h.nb[2] = t->nb[2]; h.nb[3] = t->nb[3];
|
||||
}
|
||||
|
||||
h.alias = ti;
|
||||
add_range(&h, ti);
|
||||
|
||||
h.flags = 0;
|
||||
if (ggml_backend_buffer_get_usage(t->buffer) == GGML_BACKEND_BUFFER_USAGE_COMPUTE) {
|
||||
if (ggml_backend_buffer_get_usage(t->buffer) != GGML_BACKEND_BUFFER_USAGE_WEIGHTS) {
|
||||
h.flags |= HTP_TENSOR_COMPUTE;
|
||||
}
|
||||
|
||||
@@ -1313,6 +1422,17 @@ struct ggml_hexagon_opbatch {
|
||||
o.dst[i] = (i < outputs.size() && outputs[i]) ? add_tensor(outputs[i]) : 0xffff;
|
||||
}
|
||||
}
|
||||
|
||||
void finalize_ranges() {
|
||||
for (const auto & r : ranges) {
|
||||
if (r.bi == -1) {
|
||||
continue;
|
||||
}
|
||||
for (size_t i = 0; i < r.tensors.size(); i++) {
|
||||
h_tens[r.tensors[i]].alias = r.tensors[(i + 1) % r.tensors.size()];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct ggml_hexagon_opqueue {
|
||||
@@ -1571,6 +1691,8 @@ void ggml_hexagon_session::flush_pending(bool all) {
|
||||
void ggml_hexagon_session::flush_batch() {
|
||||
if (op_batch->empty()) { return; }
|
||||
|
||||
op_batch->finalize_ranges();
|
||||
|
||||
htp_opbatch_req req {};
|
||||
dspqueue_buffer dbuf{};
|
||||
|
||||
@@ -1647,7 +1769,7 @@ void ggml_hexagon_session::allocate(int dev_id) noexcept(false) {
|
||||
|
||||
GGML_LOG_DEBUG("ggml-hex: %s allocating new session\n", this->name.c_str());
|
||||
|
||||
domain * my_domain = get_domain(this->domain_id);
|
||||
domain * my_domain = htpdrv_get_domain(this->domain_id);
|
||||
if (my_domain == NULL) {
|
||||
GGML_LOG_ERROR("ggml-hex: unable to get domain struct for CDSP\n");
|
||||
throw std::runtime_error("ggml-hex: failed to get CDSP domain (see log for details)");
|
||||
@@ -1793,16 +1915,6 @@ void ggml_hexagon_session::allocate(int dev_id) noexcept(false) {
|
||||
}
|
||||
}
|
||||
|
||||
if (opt_profile) {
|
||||
htp_iface_pmu_conf pmu_conf{};
|
||||
std::copy(opt_pmu_evt.begin(), opt_pmu_evt.end(), pmu_conf.events);
|
||||
|
||||
err = htp_iface_profiler(this->handle, opt_profile, &pmu_conf);
|
||||
if (err != 0) {
|
||||
GGML_LOG_ERROR("ggml-hex: failed to enable profiling: 0x%08x\n", (unsigned) err);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate buffers and state for op batching
|
||||
this->op_queue = new ggml_hexagon_opqueue(this, opt_opbatch, opt_opqueue);
|
||||
|
||||
@@ -1821,6 +1933,16 @@ void ggml_hexagon_session::allocate(int dev_id) noexcept(false) {
|
||||
throw std::runtime_error("ggml-hex: iface start failed (see log for details)");
|
||||
}
|
||||
this->valid_iface = true;
|
||||
|
||||
if (opt_profile) {
|
||||
htp_iface_pmu_conf pmu_conf{};
|
||||
std::copy(opt_pmu_evt.begin(), opt_pmu_evt.end(), pmu_conf.events);
|
||||
|
||||
err = htp_iface_profiler(this->handle, opt_profile, &pmu_conf);
|
||||
if (err != 0) {
|
||||
GGML_LOG_ERROR("ggml-hex: failed to enable profiling: 0x%08x\n", (unsigned) err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ggml_hexagon_session::release() noexcept(true) {
|
||||
@@ -1929,6 +2051,8 @@ static bool ggml_hexagon_flash_attn_is_hmx_eligible(
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sinks);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_precompute_flash_attn_params(
|
||||
@@ -2149,8 +2273,9 @@ static bool ggml_hexagon_supported_gated_delta_net(const struct ggml_hexagon_ses
|
||||
return false;
|
||||
}
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_matmul_is_hmx_eligible(
|
||||
@@ -2198,6 +2323,8 @@ static bool ggml_hexagon_matmul_is_hmx_eligible(
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(dst);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_precompute_hmx_mm_params(
|
||||
@@ -2234,109 +2361,15 @@ static bool ggml_hexagon_precompute_hmx_mm_params(
|
||||
if (is_batched_val && wtype == GGML_TYPE_F16 && group_size > 1) {
|
||||
// Try grouped path first
|
||||
const bool use_dma_activation = (src1->nb[1]/sizeof(float) > (size_t)ne00_padded);
|
||||
size_t best_mblocks = SIZE_MAX;
|
||||
int best_act_threads = 0;
|
||||
size_t best_m_chunk = 0;
|
||||
size_t best_n_chunk = 0;
|
||||
size_t best_vtcm_size = 0;
|
||||
|
||||
int act_threads = n_threads;
|
||||
while (act_threads >= 1) {
|
||||
const size_t f32_scratch_size = use_dma_activation ? hex_align_up(act_threads * HTP_MM_DMA_ACT_MULTIPLIER * ne00_padded * sizeof(float), HTP_MM_HMX_TILE_SIZE) : 0;
|
||||
size_t group_overhead = 256 + f32_scratch_size;
|
||||
size_t group_size_per_n, group_size_per_m, group_size_per_mn;
|
||||
htp_mm_hmx_get_batched_chunk_costs(ne00_padded, group_size, &group_size_per_n, &group_size_per_m, &group_size_per_mn);
|
||||
|
||||
size_t m_chunk_candidate = 0;
|
||||
size_t n_chunk_candidate = 0;
|
||||
size_t vtcm_size_candidate = 0;
|
||||
|
||||
if (htp_mm_hmx_compute_chunks(vtcm_budget, group_overhead, group_size_per_n, group_size_per_m, group_size_per_mn, hex_align_up(ne11, 32), ne01_padded,
|
||||
(size_t) ne01_padded * HTP_MM_HMX_COST_W_DEQUANT, (size_t) ne11 * HTP_MM_HMX_COST_A_CONVERT,
|
||||
&m_chunk_candidate, &n_chunk_candidate, &vtcm_size_candidate) == 0) {
|
||||
size_t exact_size = htp_mm_hmx_get_batched_vtcm_size(wtype, ne00_padded, m_chunk_candidate, n_chunk_candidate, group_size, use_dma_activation, pipeline, act_threads);
|
||||
if (exact_size <= vtcm_budget) {
|
||||
size_t mblocks = ((size_t) ne11 + m_chunk_candidate - 1) / m_chunk_candidate;
|
||||
if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads)) {
|
||||
best_mblocks = mblocks;
|
||||
best_act_threads = act_threads;
|
||||
best_m_chunk = m_chunk_candidate;
|
||||
best_n_chunk = n_chunk_candidate;
|
||||
best_vtcm_size = exact_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (act_threads == 1) {
|
||||
act_threads = 0;
|
||||
} else {
|
||||
act_threads /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_act_threads > 0) {
|
||||
m_chunk = best_m_chunk;
|
||||
n_chunk = best_n_chunk;
|
||||
vtcm_size = best_vtcm_size;
|
||||
act_threads_selected = best_act_threads;
|
||||
if (htp_mm_hmx_solve_batched_params(wtype, ne00_padded, ne01_padded, ne11, group_size, use_dma_activation, n_threads, pipeline, vtcm_budget, &m_chunk, &n_chunk, &act_threads_selected, &vtcm_size)) {
|
||||
use_grouped = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!use_grouped) {
|
||||
// Fallback to simple 2D path (group_size = 1)
|
||||
size_t best_mblocks = SIZE_MAX;
|
||||
int best_act_threads = 0;
|
||||
size_t best_m_chunk = 0;
|
||||
size_t best_n_chunk = 0;
|
||||
size_t best_vtcm_size = 0;
|
||||
|
||||
// For MUL_MAT_ID the kernel runs one 2D matmul per expert, with M equal to the number of rows routed to that expert.
|
||||
// A single expert can receive up to all routed rows (dst->ne[1]*dst->ne[2] = n_expert_used*n_tokens), so size the chunk
|
||||
// search for that upper bound rather than ne12 (token positions only).
|
||||
// We recompute m_chunk per expert against the actual count in the NPU kernel.
|
||||
const int m_id_rows = (int) ((size_t) dst->ne[1] * dst->ne[2]);
|
||||
const int m_for_chunks = is_matmul_id ? hex_align_up(m_id_rows, 32) : ne11_padded;
|
||||
const int m_for_cost = is_matmul_id ? m_id_rows : ne11;
|
||||
|
||||
int act_threads = n_threads;
|
||||
while (act_threads >= 1) {
|
||||
const size_t act_f32_size = is_matmul_id ? 0 : hex_align_up(act_threads * HTP_MM_DMA_ACT_MULTIPLIER * ne00_padded * sizeof(float), HTP_MM_HMX_TILE_SIZE);
|
||||
size_t simple_2d_overhead = 256 + act_f32_size;
|
||||
size_t simple_2d_size_per_n, simple_2d_size_per_m, simple_2d_size_per_mn;
|
||||
htp_mm_hmx_get_2d_chunk_costs(wtype, ne00_padded, pipeline, aligned_tile_size, &simple_2d_size_per_n, &simple_2d_size_per_m, &simple_2d_size_per_mn);
|
||||
|
||||
size_t m_chunk_candidate = 0;
|
||||
size_t n_chunk_candidate = 0;
|
||||
size_t vtcm_size_candidate = 0;
|
||||
|
||||
if (htp_mm_hmx_compute_chunks(vtcm_budget, simple_2d_overhead, simple_2d_size_per_n, simple_2d_size_per_m, simple_2d_size_per_mn, m_for_chunks, ne01_padded,
|
||||
(size_t) ne01_padded * HTP_MM_HMX_COST_W_DEQUANT, (size_t) m_for_cost * HTP_MM_HMX_COST_A_CONVERT,
|
||||
&m_chunk_candidate, &n_chunk_candidate, &vtcm_size_candidate) == 0) {
|
||||
size_t exact_size = htp_mm_hmx_get_2d_vtcm_size(wtype, ne00_padded, m_chunk_candidate, n_chunk_candidate, pipeline, is_matmul_id ? 0 : act_threads, aligned_tile_size);
|
||||
if (exact_size <= vtcm_budget) {
|
||||
size_t mblocks = ((size_t) m_for_cost + m_chunk_candidate - 1) / m_chunk_candidate;
|
||||
if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads)) {
|
||||
best_mblocks = mblocks;
|
||||
best_act_threads = act_threads;
|
||||
best_m_chunk = m_chunk_candidate;
|
||||
best_n_chunk = n_chunk_candidate;
|
||||
best_vtcm_size = exact_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (act_threads == 1) {
|
||||
act_threads = 0;
|
||||
} else {
|
||||
act_threads /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_act_threads > 0) {
|
||||
m_chunk = best_m_chunk;
|
||||
n_chunk = best_n_chunk;
|
||||
vtcm_size = best_vtcm_size;
|
||||
act_threads_selected = best_act_threads;
|
||||
} else {
|
||||
const int m_id_rows = (int) ((size_t) dst->ne[1] * dst->ne[2]);
|
||||
if (!htp_mm_hmx_solve_2d_params(wtype, ne00_padded, m_id_rows, ne01_padded, ne11_padded, ne11, n_threads, pipeline, is_matmul_id, aligned_tile_size, vtcm_budget, &m_chunk, &n_chunk, &act_threads_selected, &vtcm_size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -2352,6 +2385,8 @@ static bool ggml_hexagon_precompute_hmx_mm_params(
|
||||
kparams->src1_row_size = (wtype == GGML_TYPE_Q4_1) ? htp_mm_q8_1_tiled_row_size(ne10) : htp_mm_q8_0_tiled_row_size(ne10);
|
||||
kparams->vtcm_size = vtcm_size;
|
||||
kparams->vtcm_src0_size = 0;
|
||||
kparams->div_n_act_threads = init_fastdiv_values(act_threads_selected);
|
||||
kparams->div_ne00_padded = init_fastdiv_values(ne00_padded);
|
||||
kparams->vtcm_src1_size = 0;
|
||||
kparams->vtcm_dst_size = 0;
|
||||
|
||||
@@ -2361,6 +2396,8 @@ static bool ggml_hexagon_precompute_hmx_mm_params(
|
||||
kparams->kernel_type = HTP_MM_KERNEL_HMX_2D;
|
||||
}
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(src0);
|
||||
}
|
||||
|
||||
static void ggml_hexagon_precompute_hvx_mm_params(
|
||||
@@ -2955,6 +2992,8 @@ static bool ggml_hexagon_supported_binary(const struct ggml_hexagon_session * se
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_add_id(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -2981,6 +3020,8 @@ static bool ggml_hexagon_supported_add_id(const struct ggml_hexagon_session * se
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_unary(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3006,6 +3047,8 @@ static bool ggml_hexagon_supported_unary(const struct ggml_hexagon_session * ses
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_sum_rows(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3025,10 +3068,11 @@ static bool ggml_hexagon_supported_sum_rows(const struct ggml_hexagon_session *
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_activations(const struct ggml_hexagon_session * sess,
|
||||
const struct ggml_tensor * op) {
|
||||
static bool ggml_hexagon_supported_activations(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
const struct ggml_tensor * src0 = op->src[0];
|
||||
const struct ggml_tensor * src1 = op->src[1];
|
||||
const struct ggml_tensor * dst = op;
|
||||
@@ -3040,7 +3084,10 @@ static bool ggml_hexagon_supported_activations(const struct ggml_hexagon_session
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!ggml_is_contiguous(src0) || !ggml_is_contiguous(dst)) {
|
||||
if (!ggml_is_contiguous_1(src0)) {
|
||||
return false;
|
||||
}
|
||||
if (!ggml_is_contiguous(dst)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -3051,12 +3098,14 @@ static bool ggml_hexagon_supported_activations(const struct ggml_hexagon_session
|
||||
if (!ggml_are_same_shape(src0, src1)) {
|
||||
return false;
|
||||
}
|
||||
if (!ggml_is_contiguous(src1)) {
|
||||
if (!ggml_is_contiguous_1(src1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_softmax(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3122,6 +3171,8 @@ static bool ggml_hexagon_supported_softmax(const struct ggml_hexagon_session * s
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_set_rows(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3142,6 +3193,8 @@ static bool ggml_hexagon_supported_set_rows(const struct ggml_hexagon_session *
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_get_rows(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3162,6 +3215,8 @@ static bool ggml_hexagon_supported_get_rows(const struct ggml_hexagon_session *
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_argsort(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3182,6 +3237,8 @@ static bool ggml_hexagon_supported_argsort(const struct ggml_hexagon_session * s
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_rope(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3243,6 +3300,8 @@ static bool ggml_hexagon_supported_rope(const struct ggml_hexagon_session * sess
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_ssm_conv(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3282,6 +3341,8 @@ static bool ggml_hexagon_supported_ssm_conv(const struct ggml_hexagon_session *
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_pad(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3292,8 +3353,9 @@ static bool ggml_hexagon_supported_pad(const struct ggml_hexagon_session * sess,
|
||||
return false;
|
||||
}
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_cumsum(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3308,8 +3370,9 @@ static bool ggml_hexagon_supported_cumsum(const struct ggml_hexagon_session * se
|
||||
return false;
|
||||
}
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_diag(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3331,8 +3394,9 @@ static bool ggml_hexagon_supported_diag(const struct ggml_hexagon_session * sess
|
||||
return false;
|
||||
}
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_solve_tri(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3364,8 +3428,9 @@ static bool ggml_hexagon_supported_solve_tri(const struct ggml_hexagon_session *
|
||||
return false;
|
||||
}
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
return true;
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_tri(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -3415,6 +3480,7 @@ static htp_op_code op_remap_to_htp(const ggml_tensor * t) {
|
||||
case GGML_OP_RMS_NORM: return HTP_OP_RMS_NORM;
|
||||
case GGML_OP_CONCAT: return HTP_OP_CONCAT;
|
||||
case GGML_OP_SCALE: return HTP_OP_SCALE;
|
||||
case GGML_OP_CLAMP: return HTP_OP_CLAMP;
|
||||
case GGML_OP_SQR: return HTP_OP_SQR;
|
||||
case GGML_OP_SQRT: return HTP_OP_SQRT;
|
||||
case GGML_OP_SOFT_MAX: return HTP_OP_SOFTMAX;
|
||||
@@ -3812,6 +3878,8 @@ static void ggml_backend_hexagon_graph_optimize(ggml_backend_t backend, ggml_cgr
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GGML_UNUSED(backend);
|
||||
}
|
||||
|
||||
static struct ggml_backend_i hexagon_backend_i = {
|
||||
@@ -3930,6 +3998,8 @@ static bool ggml_hexagon_supported_buffers(ggml_hexagon_session *sess, const str
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_cpy(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
GGML_UNUSED(sess);
|
||||
|
||||
const struct ggml_tensor * src0 = op->src[0];
|
||||
const struct ggml_tensor * dst = op;
|
||||
|
||||
@@ -4000,6 +4070,7 @@ static bool ggml_hexagon_supported_concat(const struct ggml_hexagon_session * se
|
||||
}
|
||||
|
||||
return true;
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_hexagon_supported_fill(const struct ggml_hexagon_session * sess, const struct ggml_tensor * op) {
|
||||
@@ -4009,8 +4080,8 @@ static bool ggml_hexagon_supported_fill(const struct ggml_hexagon_session * sess
|
||||
return false;
|
||||
}
|
||||
|
||||
GGML_UNUSED(sess);
|
||||
return true;
|
||||
GGML_UNUSED(sess);
|
||||
}
|
||||
|
||||
static bool ggml_backend_hexagon_device_supports_op(ggml_backend_dev_t dev, const struct ggml_tensor * op) {
|
||||
@@ -4060,6 +4131,7 @@ static bool ggml_backend_hexagon_device_supports_op(ggml_backend_dev_t dev, cons
|
||||
case GGML_OP_L2_NORM:
|
||||
case GGML_OP_RMS_NORM:
|
||||
case GGML_OP_SCALE:
|
||||
case GGML_OP_CLAMP:
|
||||
supp = ggml_hexagon_supported_unary(sess, op);
|
||||
break;
|
||||
|
||||
@@ -4083,12 +4155,10 @@ static bool ggml_backend_hexagon_device_supports_op(ggml_backend_dev_t dev, cons
|
||||
case GGML_UNARY_OP_SIGMOID:
|
||||
case GGML_UNARY_OP_SOFTPLUS:
|
||||
case GGML_UNARY_OP_TANH:
|
||||
supp = ggml_hexagon_supported_unary(sess, op);
|
||||
break;
|
||||
case GGML_UNARY_OP_SILU:
|
||||
case GGML_UNARY_OP_GELU:
|
||||
case GGML_UNARY_OP_GELU_QUICK:
|
||||
supp = ggml_hexagon_supported_activations(sess, op);
|
||||
supp = ggml_hexagon_supported_unary(sess, op);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -4293,6 +4363,7 @@ static void * ggml_backend_hexagon_get_proc_address(ggml_backend_reg_t reg, cons
|
||||
}
|
||||
|
||||
return NULL;
|
||||
GGML_UNUSED(reg);
|
||||
}
|
||||
|
||||
template<typename T> std::vector<T> str_to_vec(const char* str) {
|
||||
@@ -4351,10 +4422,18 @@ static void ggml_hexagon_init(ggml_backend_reg * reg) {
|
||||
|
||||
// Init Arch first since it affects other defaults
|
||||
if (!str_arch) {
|
||||
int err = get_hex_arch_ver(CDSP_DOMAIN_ID, &opt_arch);
|
||||
int err = htpdrv_get_arch(CDSP_DOMAIN_ID, &opt_arch);
|
||||
if (err != 0) {
|
||||
GGML_LOG_ERROR("ggml-hex: failed to query HTP version (err %d) defaulting to v73\n", err);
|
||||
opt_arch = 73;
|
||||
} else {
|
||||
if (opt_arch < 73) {
|
||||
GGML_LOG_WARN("ggml-hex: Hexagon arch v%d is under supported range, capping at v73\n", opt_arch);
|
||||
opt_arch = 73;
|
||||
} else if (opt_arch > 81) {
|
||||
GGML_LOG_WARN("ggml-hex: Hexagon arch v%d is over supported range, capping at v81\n", opt_arch);
|
||||
opt_arch = 81;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (str_arch[0] == 'v' || str_arch[0] == 'V') {
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
// sample drv interface
|
||||
|
||||
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
|
||||
#include <filesystem>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _WIN32
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# ifndef NOMINMAX
|
||||
@@ -16,9 +11,17 @@
|
||||
# include <windows.h>
|
||||
# include <winevt.h>
|
||||
#else
|
||||
# include <dlfcn.h>
|
||||
# include <unistd.h>
|
||||
# include <dlfcn.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
|
||||
#pragma clang diagnostic ignored "-Wmissing-prototypes"
|
||||
#pragma clang diagnostic ignored "-Wsign-compare"
|
||||
#pragma clang diagnostic ignored "-Wlanguage-extension-token"
|
||||
#pragma clang diagnostic ignored "-Wmicrosoft-enum-value"
|
||||
#pragma clang diagnostic ignored "-Wnested-anon-types"
|
||||
|
||||
#include "ggml-impl.h"
|
||||
#include "htp-drv.h"
|
||||
#include "libdl.h"
|
||||
@@ -359,7 +362,7 @@ int htpdrv_init() {
|
||||
return AEE_SUCCESS;
|
||||
}
|
||||
|
||||
domain * get_domain(int domain_id) {
|
||||
domain * htpdrv_get_domain(int domain_id) {
|
||||
int i = 0;
|
||||
int size = sizeof(supported_domains) / sizeof(domain);
|
||||
|
||||
@@ -372,7 +375,7 @@ domain * get_domain(int domain_id) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_hex_arch_ver(int domain, int * arch) {
|
||||
int htpdrv_get_arch(int domain, int * arch) {
|
||||
if (!remote_handle_control_pfn) {
|
||||
GGML_LOG_ERROR("ggml-hex: remote_handle_control is not supported on this device\n");
|
||||
return AEE_EUNSUPPORTEDAPI;
|
||||
@@ -394,25 +397,7 @@ int get_hex_arch_ver(int domain, int * arch) {
|
||||
return err;
|
||||
}
|
||||
|
||||
switch (arch_ver.capability & 0xff) {
|
||||
case 0x68:
|
||||
*arch = 68;
|
||||
return 0;
|
||||
case 0x69:
|
||||
*arch = 69;
|
||||
return 0;
|
||||
case 0x73:
|
||||
*arch = 73;
|
||||
return 0;
|
||||
case 0x75:
|
||||
*arch = 75;
|
||||
return 0;
|
||||
case 0x79:
|
||||
*arch = 79;
|
||||
return 0;
|
||||
case 0x81:
|
||||
*arch = 81;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
uint32_t val = arch_ver.capability & 0xff;
|
||||
*arch = (int) ((val >> 4) * 10 + (val & 0x0f));
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -96,17 +96,17 @@ extern "C" {
|
||||
HTPDRV_API int htpdrv_init(void);
|
||||
|
||||
/**
|
||||
* get_domain API: get domain struct from domain value.
|
||||
* htpdrv_get_domain API: get domain struct from domain value.
|
||||
*
|
||||
* @param[in] domain value of a domain
|
||||
* @return Returns domain struct of the domain if it is supported or else
|
||||
* returns NULL.
|
||||
*
|
||||
*/
|
||||
HTPDRV_API domain * get_domain(int domain_id);
|
||||
HTPDRV_API domain * htpdrv_get_domain(int domain_id);
|
||||
|
||||
/**
|
||||
* get_hex_arch_ver API: query the Hexagon processor architecture version information
|
||||
* htpdrv_get_arch API: query the Hexagon processor architecture version information
|
||||
*
|
||||
* @param[in] domain_id value of a domain
|
||||
* @param[out] Arch version (73, 75, ...)
|
||||
@@ -114,7 +114,7 @@ HTPDRV_API domain * get_domain(int domain_id);
|
||||
* non-zero if error, return value points to the error.
|
||||
*
|
||||
*/
|
||||
HTPDRV_API int get_hex_arch_ver(int domain, int * arch);
|
||||
HTPDRV_API int htpdrv_get_arch(int domain, int * arch);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -17,9 +17,12 @@ set(HTP_LIB ggml-htp-${DSP_VERSION})
|
||||
add_library(${HTP_LIB} SHARED
|
||||
main.c
|
||||
htp_iface_skel.c
|
||||
worker-pool.c
|
||||
hex-dma.c
|
||||
work-queue.c
|
||||
dma-queue.c
|
||||
hmx-queue.c
|
||||
htp-tensor.c
|
||||
matmul-ops.c
|
||||
flash-attn-ops.c
|
||||
gated-delta-net-ops.c
|
||||
binary-ops.c
|
||||
unary-ops.c
|
||||
@@ -38,8 +41,6 @@ add_library(${HTP_LIB} SHARED
|
||||
diag-ops.c
|
||||
solve-tri-ops.c
|
||||
pad-ops.c
|
||||
flash-attn-ops.c
|
||||
matmul-ops.c
|
||||
argsort-ops.c
|
||||
)
|
||||
|
||||
|
||||
+392
-573
File diff suppressed because it is too large
Load Diff
@@ -345,7 +345,7 @@ static void htp_argsort_f32_##ne00##_##order_name(unsigned int n, unsigned int i
|
||||
int32_t * indices_buf = (int32_t *) (spad + values_size); \
|
||||
uint32_t nb01 = src0->nb[1]; \
|
||||
uint32_t nb1 = dst->nb[1]; \
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[i] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[i]; \
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, start_row); \
|
||||
for (uint32_t r = start_row; r < end_row; r++) { \
|
||||
uint32_t src_offset = r * nb01; \
|
||||
@@ -411,7 +411,7 @@ static void htp_argsort_f32_fallback(unsigned int n, unsigned int i, void * data
|
||||
const HVX_Vector ind_init_vec = *(HVX_Vector *)argosrt_ramp_lut;
|
||||
const HVX_Vector ind_diff_vec = Q6_V_vsplat_R(32);
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, start_row);
|
||||
|
||||
for (uint32_t r = start_row; r < end_row; r++) {
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "htp-ctx.h"
|
||||
#include "htp-ops.h"
|
||||
#include "htp-ops.h"
|
||||
#include "htp-tensor.h"
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "ggml-common.h"
|
||||
#include "htp-ctx.h"
|
||||
#include "htp-ops.h"
|
||||
#include "htp-tensor.h"
|
||||
#include "hvx-types.h"
|
||||
#include "hvx-utils.h"
|
||||
#include "hex-dma.h"
|
||||
@@ -255,16 +256,10 @@ int op_cumsum_f32(struct htp_ops_context * octx) {
|
||||
int op_cumsum(struct htp_ops_context * octx) {
|
||||
const struct htp_tensor * dst = octx->dst;
|
||||
|
||||
int err = HTP_STATUS_OK;
|
||||
|
||||
switch (dst->type) {
|
||||
case HTP_TYPE_F32:
|
||||
err = op_cumsum_f32(octx);
|
||||
break;
|
||||
return op_cumsum_f32(octx);
|
||||
default:
|
||||
err = HTP_STATUS_NO_SUPPORT;
|
||||
break;
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
#include "dma-queue.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
|
||||
static inline uint32_t pow2_ceil(uint32_t x) {
|
||||
if (x <= 1) {
|
||||
return 1;
|
||||
}
|
||||
int p = 2;
|
||||
x--;
|
||||
while (x >>= 1) {
|
||||
p <<= 1;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline uintptr_t align_up(uintptr_t addr, size_t align) {
|
||||
return (addr + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
size_t dma_queue_sizeof(size_t capacity) {
|
||||
capacity = pow2_ceil(capacity);
|
||||
|
||||
size_t size_q = sizeof(dma_queue);
|
||||
size_t offset_r = align_up(size_q, HEX_L2_LINE_SIZE);
|
||||
size_t size_r = sizeof(dma_ring);
|
||||
size_t offset_desc = align_up(offset_r + size_r, HEX_L2_LINE_SIZE);
|
||||
size_t size_desc = capacity * sizeof(dma_descriptor_2d);
|
||||
size_t offset_dptr = align_up(offset_desc + size_desc, HEX_L2_LINE_SIZE);
|
||||
size_t size_dptr = capacity * sizeof(dma_ptr);
|
||||
|
||||
return offset_dptr + size_dptr;
|
||||
}
|
||||
|
||||
size_t dma_queue_alignof(void) {
|
||||
return HEX_L2_LINE_SIZE;
|
||||
}
|
||||
|
||||
dma_queue_t dma_queue_init(void * ptr, size_t capacity, uintptr_t vtcm_base, size_t vtcm_size, struct htp_thread_trace * trace) {
|
||||
capacity = pow2_ceil(capacity);
|
||||
|
||||
size_t size_q = sizeof(dma_queue);
|
||||
size_t offset_r = align_up(size_q, HEX_L2_LINE_SIZE);
|
||||
size_t size_r = sizeof(dma_ring);
|
||||
size_t offset_desc = align_up(offset_r + size_r, HEX_L2_LINE_SIZE);
|
||||
size_t size_desc = capacity * sizeof(dma_descriptor_2d);
|
||||
size_t offset_dptr = align_up(offset_desc + size_desc, HEX_L2_LINE_SIZE);
|
||||
size_t size_dptr = capacity * sizeof(dma_ptr);
|
||||
|
||||
size_t total_size = offset_dptr + size_dptr;
|
||||
memset(ptr, 0, total_size);
|
||||
|
||||
dma_queue * q = (dma_queue *) ptr;
|
||||
dma_ring * r = (dma_ring *) ((uintptr_t) ptr + offset_r);
|
||||
|
||||
q->ring = r;
|
||||
q->nocache = 0;
|
||||
q->alias = false;
|
||||
|
||||
r->trace = trace;
|
||||
r->vtcm_base = vtcm_base;
|
||||
r->vtcm_end = vtcm_base + vtcm_size;
|
||||
r->capacity = capacity;
|
||||
r->idx_mask = capacity - 1;
|
||||
r->push_idx = 0;
|
||||
r->pop_idx = 0;
|
||||
|
||||
r->desc = (dma_descriptor_2d *) ((uintptr_t) ptr + offset_desc);
|
||||
r->dptr = (dma_ptr *) ((uintptr_t) ptr + offset_dptr);
|
||||
r->tail = &r->desc[capacity - 1];
|
||||
|
||||
FARF(HIGH, "dma-queue: capacity %u, unified memory size %zu\n", capacity, total_size);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void dma_queue_free(dma_queue_t q) {
|
||||
(void) q;
|
||||
}
|
||||
|
||||
size_t dma_queue_alias_sizeof(void) {
|
||||
return sizeof(dma_queue);
|
||||
}
|
||||
|
||||
dma_queue_t dma_queue_alias_init(void * ptr, dma_queue_t main_q, uint8_t nocache) {
|
||||
dma_queue * q = (dma_queue *) ptr;
|
||||
memset(q, 0, sizeof(dma_queue));
|
||||
|
||||
q->ring = main_q->ring;
|
||||
q->nocache = nocache;
|
||||
q->alias = true;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void dma_queue_alias_free(dma_queue_t q) {
|
||||
(void) q;
|
||||
}
|
||||
|
||||
void dma_queue_flush(dma_queue_t q) {
|
||||
while (dma_queue_pop(q).dst != NULL) ;
|
||||
}
|
||||
@@ -0,0 +1,396 @@
|
||||
#ifndef HTP_DMA_H
|
||||
#define HTP_DMA_H
|
||||
|
||||
#include <HAP_farf.h>
|
||||
#include <hexagon_types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "hex-utils.h"
|
||||
|
||||
#include "hex-profile.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Define the HW descriptor structs here since the ones in HexSDK are a bit out of date
|
||||
typedef struct dma_descriptor_1d_s {
|
||||
void * next;
|
||||
uint32_t size:24;
|
||||
uint32_t desc_size:2;
|
||||
uint32_t dst_comp:1;
|
||||
uint32_t src_comp:1;
|
||||
uint32_t dst_bypass:1;
|
||||
uint32_t src_bypass:1;
|
||||
uint32_t order:1;
|
||||
uint32_t done:1;
|
||||
void * src;
|
||||
void * dst;
|
||||
} dma_descriptor_1d;
|
||||
|
||||
#if __HVX_ARCH__ < 75
|
||||
|
||||
typedef struct dma_descriptor_2d_s {
|
||||
void * next;
|
||||
uint32_t reserved0:24;
|
||||
uint32_t desc_size:2;
|
||||
uint32_t dst_comp:1;
|
||||
uint32_t src_comp:1;
|
||||
uint32_t dst_bypass:1;
|
||||
uint32_t src_bypass:1;
|
||||
uint32_t order:1;
|
||||
uint32_t done:1;
|
||||
void * src;
|
||||
void * dst;
|
||||
uint32_t desc_type:8;
|
||||
uint32_t reserved1:24;
|
||||
uint32_t row_size:16;
|
||||
uint32_t nrows:16;
|
||||
uint32_t src_stride:16;
|
||||
uint32_t dst_stride:16;
|
||||
uint32_t src_offset:16;
|
||||
uint32_t dst_offset:16;
|
||||
} dma_descriptor_2d;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct dma_descriptor_2d_s {
|
||||
void * next;
|
||||
uint32_t dst_stride:24;
|
||||
uint32_t desc_size:2;
|
||||
uint32_t dst_comp:1;
|
||||
uint32_t src_comp:1;
|
||||
uint32_t dst_bypass:1;
|
||||
uint32_t src_bypass:1;
|
||||
uint32_t order:1;
|
||||
uint32_t done:1;
|
||||
void * src;
|
||||
void * dst;
|
||||
uint32_t desc_type:8;
|
||||
uint32_t reserved0:24;
|
||||
uint32_t row_size:24;
|
||||
uint32_t nrows_lo:8;
|
||||
uint32_t nrows_hi:8;
|
||||
uint32_t src_stride:24;
|
||||
uint32_t offset:24;
|
||||
uint32_t reserved1:8;
|
||||
} dma_descriptor_2d;
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void *dst;
|
||||
const void *src;
|
||||
} dma_ptr;
|
||||
|
||||
typedef struct dma_ring_s dma_ring;
|
||||
struct dma_ring_s {
|
||||
dma_descriptor_2d * desc; // descriptor pointers
|
||||
dma_descriptor_2d * tail; // tail pointer
|
||||
dma_ptr * dptr; // dst/src pointers
|
||||
uint32_t push_idx;
|
||||
uint32_t pop_idx;
|
||||
uint32_t capacity;
|
||||
uint32_t idx_mask;
|
||||
struct htp_thread_trace * trace;
|
||||
uintptr_t vtcm_base;
|
||||
uintptr_t vtcm_end;
|
||||
};
|
||||
|
||||
typedef struct dma_queue_s dma_queue;
|
||||
typedef dma_queue * dma_queue_t;
|
||||
|
||||
struct dma_queue_s {
|
||||
dma_ring * ring; // Points to the descriptor ring state
|
||||
uint8_t nocache; // Queue-specific bypass flag
|
||||
bool alias; // When set, dma_queue_delete will not free the ring
|
||||
};
|
||||
|
||||
void dma_queue_flush(dma_queue_t q);
|
||||
|
||||
size_t dma_queue_sizeof(size_t capacity);
|
||||
size_t dma_queue_alignof(void);
|
||||
dma_queue_t dma_queue_init(void * ptr, size_t capacity, uintptr_t vtcm_base, size_t vtcm_size, struct htp_thread_trace * trace);
|
||||
void dma_queue_free(dma_queue_t q);
|
||||
|
||||
size_t dma_queue_alias_sizeof(void);
|
||||
dma_queue_t dma_queue_alias_init(void * ptr, dma_queue_t main_q, uint8_t nocache);
|
||||
void dma_queue_alias_free(dma_queue_t q);
|
||||
|
||||
// TODO: technically we don't need these and could use Q6_dmstart/wait/etc instead
|
||||
// but those do not seem to always compiler properly.
|
||||
static inline void dmstart(void * next) {
|
||||
asm volatile(" release(%0):at" : : "r"(next));
|
||||
asm volatile(" dmstart(%0)" : : "r"(next));
|
||||
}
|
||||
|
||||
static inline void dmlink(void * cur, void * next) {
|
||||
asm volatile(" release(%0):at" : : "r"(next));
|
||||
asm volatile(" dmlink(%0, %1)" : : "r"(cur), "r"(next));
|
||||
}
|
||||
|
||||
static inline unsigned int dmpoll(void) {
|
||||
unsigned int ret = 0;
|
||||
asm volatile(" %0 = dmpoll" : "=r"(ret) : : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned int dmwait(void) {
|
||||
unsigned int ret = 0;
|
||||
asm volatile(" %0 = dmwait" : "=r"(ret) : : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline dma_ptr dma_make_ptr(void *dst, const void *src)
|
||||
{
|
||||
dma_ptr p = { dst, src };
|
||||
return p;
|
||||
}
|
||||
|
||||
static inline bool dma_is_vtcm(const dma_queue * q, const void * ptr) {
|
||||
return (uintptr_t) ptr >= q->ring->vtcm_base && (uintptr_t) ptr < q->ring->vtcm_end;
|
||||
}
|
||||
|
||||
static inline bool dma_queue_push_single_1d(dma_queue * q, dma_ptr dptr, size_t size) {
|
||||
dma_ring * r = q->ring;
|
||||
if (((r->push_idx + 1) & r->idx_mask) == r->pop_idx) {
|
||||
FARF(HIGH, "dma-push: queue full\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dma_descriptor_1d * desc = (dma_descriptor_1d *) &r->desc[r->push_idx];
|
||||
desc->src = (void *) dptr.src;
|
||||
desc->dst = (void *) dptr.dst;
|
||||
desc->size = size;
|
||||
|
||||
r->dptr[r->push_idx] = dptr;
|
||||
|
||||
if (size) {
|
||||
desc->next = NULL;
|
||||
desc->desc_size = 0; // 1D mode
|
||||
desc->src_bypass = dma_is_vtcm(q, dptr.src) ? 1 : q->nocache;
|
||||
desc->dst_bypass = dma_is_vtcm(q, dptr.dst) ? 1 : q->nocache;
|
||||
desc->order = 0;
|
||||
desc->done = 0;
|
||||
|
||||
htp_trace_event_start(r->trace, HTP_TRACE_EVT_DMA, r->push_idx);
|
||||
dmlink(r->tail, desc);
|
||||
r->tail = (dma_descriptor_2d *) desc;
|
||||
} else {
|
||||
desc->desc_size = 0;
|
||||
desc->done = 1;
|
||||
}
|
||||
|
||||
r->push_idx = (r->push_idx + 1) & r->idx_mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool dma_queue_push_single_2d(dma_queue * q, dma_ptr dptr, size_t dst_stride, size_t src_stride, size_t row_size, size_t nrows) {
|
||||
dma_ring * r = q->ring;
|
||||
if (((r->push_idx + 1) & r->idx_mask) == r->pop_idx) {
|
||||
FARF(HIGH, "dma-push: queue full\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dma_descriptor_2d * desc = &r->desc[r->push_idx];
|
||||
|
||||
desc->next = NULL;
|
||||
desc->reserved0 = 0;
|
||||
desc->reserved1 = 0;
|
||||
desc->desc_size = 1; // 2d mode
|
||||
desc->src_bypass = dma_is_vtcm(q, dptr.src) ? 1 : q->nocache;
|
||||
desc->dst_bypass = dma_is_vtcm(q, dptr.dst) ? 1 : q->nocache;
|
||||
desc->src_comp = 0;
|
||||
desc->dst_comp = 0;
|
||||
desc->order = 0;
|
||||
desc->done = 0;
|
||||
desc->src_stride = src_stride;
|
||||
desc->dst_stride = dst_stride;
|
||||
desc->src = (void *) dptr.src;
|
||||
desc->dst = (void *) dptr.dst;
|
||||
desc->row_size = row_size;
|
||||
|
||||
#if __HVX_ARCH__ < 75
|
||||
desc->desc_type = 0; // 2d (16-bit) mode
|
||||
desc->nrows = nrows;
|
||||
desc->src_offset = 0;
|
||||
desc->dst_offset = 0;
|
||||
#else
|
||||
desc->desc_type = 9; // 2d (24-bit) mode
|
||||
desc->nrows_lo = (nrows & 0xff);
|
||||
desc->nrows_hi = (nrows >> 8);
|
||||
desc->offset = 0;
|
||||
#endif
|
||||
|
||||
r->dptr[r->push_idx] = dptr;
|
||||
|
||||
if (nrows) {
|
||||
htp_trace_event_start(r->trace, HTP_TRACE_EVT_DMA, r->push_idx);
|
||||
dmlink(r->tail, desc);
|
||||
r->tail = desc;
|
||||
} else {
|
||||
desc->done = 1;
|
||||
}
|
||||
|
||||
r->push_idx = (r->push_idx + 1) & r->idx_mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline dma_ptr dma_queue_pop(dma_queue * q) {
|
||||
dma_ring * r = q->ring;
|
||||
dma_ptr dptr = { NULL };
|
||||
|
||||
if (r->push_idx == r->pop_idx) {
|
||||
return dptr;
|
||||
}
|
||||
|
||||
dma_descriptor_2d * desc = &r->desc[r->pop_idx];
|
||||
|
||||
// Wait for desc to complete
|
||||
if (!desc->done) {
|
||||
while (!desc->done) {
|
||||
dmpoll();
|
||||
}
|
||||
}
|
||||
htp_trace_event_stop(r->trace, HTP_TRACE_EVT_DMA, r->pop_idx);
|
||||
|
||||
dptr = r->dptr[r->pop_idx];
|
||||
|
||||
r->pop_idx = (r->pop_idx + 1) & r->idx_mask;
|
||||
return dptr;
|
||||
}
|
||||
|
||||
static inline dma_ptr dma_queue_pop_nowait(dma_queue * q) {
|
||||
dma_ring * r = q->ring;
|
||||
dma_ptr dptr = { NULL };
|
||||
|
||||
if (r->push_idx == r->pop_idx) {
|
||||
return dptr;
|
||||
}
|
||||
|
||||
dptr = r->dptr[r->pop_idx];
|
||||
|
||||
r->pop_idx = (r->pop_idx + 1) & r->idx_mask;
|
||||
return dptr;
|
||||
}
|
||||
|
||||
static inline bool dma_queue_empty(dma_queue * q) {
|
||||
return q->ring->push_idx == q->ring->pop_idx;
|
||||
}
|
||||
|
||||
static inline uint32_t dma_queue_depth(dma_queue * q) {
|
||||
return (q->ring->push_idx - q->ring->pop_idx) & q->ring->idx_mask;
|
||||
}
|
||||
|
||||
static inline uint32_t dma_queue_capacity(dma_queue * q) {
|
||||
return q->ring->capacity;
|
||||
}
|
||||
|
||||
#if __HVX_ARCH__ < 75
|
||||
|
||||
// Overflow-safe DMA push: all 2d descriptor fields (row_size, nrows, src_stride, dst_stride) are 16-bit, max 65535.
|
||||
// This version transparently handles values that exceed the 16-bit limit and submits chained DMA transtions.
|
||||
|
||||
#define DMA_MAX_FIELD_VAL 65535u
|
||||
|
||||
static inline bool dma_queue_push(dma_queue *q, dma_ptr dptr, size_t dst_stride, size_t src_stride, size_t row_size, size_t nrows) {
|
||||
// Fast path: everything fits in 16 bits
|
||||
if (nrows == 0 || __builtin_expect(
|
||||
row_size <= DMA_MAX_FIELD_VAL &&
|
||||
nrows <= DMA_MAX_FIELD_VAL &&
|
||||
src_stride <= DMA_MAX_FIELD_VAL &&
|
||||
dst_stride <= DMA_MAX_FIELD_VAL, 1)) {
|
||||
return dma_queue_push_single_2d(q, dptr, dst_stride, src_stride, row_size, nrows);
|
||||
}
|
||||
|
||||
// Contiguous block
|
||||
// Use 1d DMA mode which supports sizes up to 24-bits (16MB)
|
||||
if (nrows == 1 || (row_size == src_stride && row_size == dst_stride)) {
|
||||
size_t total = row_size * nrows;
|
||||
return dma_queue_push_single_1d(q, dptr, total);
|
||||
}
|
||||
|
||||
// Stride overflow - fall back to row-by-row.
|
||||
{
|
||||
const uint8_t *src = (const uint8_t *) dptr.src;
|
||||
uint8_t *dst = (uint8_t *) dptr.dst;
|
||||
for (size_t r = 0; r < nrows; ++r) {
|
||||
dma_ptr p = dma_make_ptr(dst + r * dst_stride, src + r * src_stride);
|
||||
if (!dma_queue_push_single_1d(q, p, row_size))
|
||||
return false;
|
||||
if (r + 1 < nrows)
|
||||
dma_queue_pop(q);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#else // HVX_ARCH >= 75
|
||||
|
||||
static inline bool dma_queue_push(dma_queue *q, dma_ptr dptr, size_t dst_stride, size_t src_stride, size_t row_size, size_t nrows) {
|
||||
// On v75 and up we always use 2d 24-bit mode
|
||||
return dma_queue_push_single_2d(q, dptr, dst_stride, src_stride, row_size, nrows);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool dma_queue_push_ddr_to_vtcm(dma_queue * q, dma_ptr dptr, size_t dst_row_size, size_t src_row_size, size_t nrows) {
|
||||
return dma_queue_push(q, dptr, dst_row_size, src_row_size, src_row_size, nrows);
|
||||
}
|
||||
|
||||
static inline bool dma_queue_push_vtcm_to_ddr(dma_queue * q, dma_ptr dptr, size_t dst_row_size, size_t src_row_size, size_t nrows) {
|
||||
return dma_queue_push(q, dptr, dst_row_size, src_row_size, dst_row_size, nrows);
|
||||
}
|
||||
|
||||
#define DMA_CACHE_MAX_SIZE 256U
|
||||
|
||||
typedef struct {
|
||||
uint8_t *base;
|
||||
uint32_t line_size;
|
||||
uint32_t capacity;
|
||||
uint32_t src[DMA_CACHE_MAX_SIZE];
|
||||
uint16_t age[DMA_CACHE_MAX_SIZE];
|
||||
} dma_cache;
|
||||
|
||||
static inline void dma_cache_init(dma_cache *c, uint8_t *base, uint32_t line_size, uint32_t capacity)
|
||||
{
|
||||
c->capacity = (capacity > DMA_CACHE_MAX_SIZE) ? DMA_CACHE_MAX_SIZE : capacity;
|
||||
c->base = base;
|
||||
c->line_size = line_size;
|
||||
|
||||
for (unsigned i=0; i < c->capacity; i++) {
|
||||
c->src[i] = 0;
|
||||
c->age[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool dma_cache_push(dma_queue *q, dma_cache *c, const uint8_t * src, uint32_t dst_stride, uint32_t src_stride, uint32_t row_size, uint32_t nrows)
|
||||
{
|
||||
uint32_t o_idx = 0;
|
||||
uint16_t o_age = 0;
|
||||
uint8_t * dst = 0;
|
||||
|
||||
for (unsigned i=0; i < c->capacity; i++) {
|
||||
if (c->src[i] == (uint32_t) src) {
|
||||
c->age[i] = 0;
|
||||
dst = c->base + (i * c->line_size); nrows = 0; // dummy dma
|
||||
} else {
|
||||
c->age[i]++;
|
||||
if (c->age[i] > o_age) { o_age = c->age[i]; o_idx = i; }
|
||||
}
|
||||
}
|
||||
if (!dst) {
|
||||
c->age[o_idx] = 0;
|
||||
c->src[o_idx] = (uint32_t) src;
|
||||
dst = c->base + o_idx * c->line_size; // normal nrows dma
|
||||
return dma_queue_push(q, dma_make_ptr(dst, src), dst_stride, src_stride, row_size, nrows);
|
||||
}
|
||||
|
||||
return dma_queue_push_single_1d(q, dma_make_ptr(dst, src), 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* HTP_DMA_H */
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "hvx-reduce.h"
|
||||
#include "hvx-flash-attn.h"
|
||||
#include "htp-vtcm.h"
|
||||
#include "worker-pool.h"
|
||||
#include "work-queue.h"
|
||||
|
||||
#define GGML_COMMON_DECL_C
|
||||
#include "ggml-common.h"
|
||||
@@ -204,7 +204,7 @@ static void flash_attn_ext_f16_thread(unsigned int nth, unsigned int ith, void *
|
||||
|
||||
if (ir0 >= ir1) return;
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
dma_queue * dma = octx->ctx->dma[ith];
|
||||
|
||||
@@ -486,7 +486,7 @@ static void fa_k_interleave_thread(unsigned int n, unsigned int i, void * data)
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = factx->octx->ctx ? &factx->octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &factx->octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_FA_K_PREP, (uint16_t) (args->kv_start + start));
|
||||
hmx_interleave_rows_to_tiles(factx->vtcm_k_tiles, (const __fp16 *) args->curr_k, total_rows, factx->DK,
|
||||
args->src_stride, start, end);
|
||||
@@ -494,7 +494,7 @@ static void fa_k_interleave_thread(unsigned int n, unsigned int i, void * data)
|
||||
}
|
||||
|
||||
static void fa_phase_k_interleave(struct hmx_fa_context * factx, uint32_t kv_rows, size_t src_stride, void * curr_k, uint32_t kv_start) {
|
||||
worker_pool_context_t wp = factx->octx->ctx->worker_pool;
|
||||
work_queue_t wp = factx->octx->ctx->work_queue;
|
||||
uint32_t n = 1;
|
||||
if (factx->n_threads > 1 && kv_rows >= factx->n_threads * 2) {
|
||||
n = factx->n_threads;
|
||||
@@ -502,7 +502,7 @@ static void fa_phase_k_interleave(struct hmx_fa_context * factx, uint32_t kv_row
|
||||
uint32_t rows_per_t = hex_align_up(hmx_ceil_div(kv_rows, n), 2);
|
||||
fa_k_int_args_t args = { factx, kv_rows, src_stride, curr_k, kv_start, rows_per_t };
|
||||
if (n > 1) {
|
||||
worker_pool_run_func(wp, fa_k_interleave_thread, &args, n);
|
||||
work_queue_run(wp, fa_k_interleave_thread, &args, n);
|
||||
} else {
|
||||
fa_k_interleave_thread(1, 0, &args);
|
||||
}
|
||||
@@ -534,7 +534,7 @@ static void fa_v_interleave_thread(unsigned int n, unsigned int i, void * data)
|
||||
|
||||
__fp16 * v_tiles_dst = (__fp16 *) args->v_tiles_dst;
|
||||
|
||||
struct htp_thread_trace * tr = factx->octx->ctx ? &factx->octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &factx->octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_FA_V_PREP, (uint16_t) (args->kv_start + start));
|
||||
hmx_interleave_cols_to_tiles(v_tiles_dst, (const __fp16 *) args->v_src, total_rows, factx->DV,
|
||||
args->src_stride, (uint32_t) args->n_col_tiles, start, end);
|
||||
@@ -548,7 +548,7 @@ static void fa_phase_v_interleave(struct hmx_fa_context * factx,
|
||||
void * v_tiles_dst,
|
||||
size_t n_col_tiles,
|
||||
uint32_t kv_start) {
|
||||
worker_pool_context_t wp = factx->octx->ctx->worker_pool;
|
||||
work_queue_t wp = factx->octx->ctx->work_queue;
|
||||
uint32_t n = 1;
|
||||
if (factx->n_threads > 1 && kv_rows >= factx->n_threads * 2) {
|
||||
n = factx->n_threads;
|
||||
@@ -556,7 +556,7 @@ static void fa_phase_v_interleave(struct hmx_fa_context * factx,
|
||||
uint32_t rows_per_t = hex_align_up(hmx_ceil_div(kv_rows, n), 2);
|
||||
fa_v_int_args_t args = { factx, kv_rows, src_stride, v_src, v_tiles_dst, n_col_tiles, kv_start, rows_per_t };
|
||||
if (n > 1) {
|
||||
worker_pool_run_func(wp, fa_v_interleave_thread, &args, n);
|
||||
work_queue_run(wp, fa_v_interleave_thread, &args, n);
|
||||
} else {
|
||||
fa_v_interleave_thread(1, 0, &args);
|
||||
}
|
||||
@@ -589,7 +589,7 @@ static void fa_q_load_thread(unsigned int n, unsigned int i, void * data) {
|
||||
const size_t start = (size_t) i * rows_per_t;
|
||||
const size_t end = hex_smin(start + rows_per_t, factx->g_br);
|
||||
|
||||
struct htp_thread_trace * tr = factx->octx->ctx ? &factx->octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &factx->octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_FA_Q_PREP, (uint16_t) (args->q_start * G + start));
|
||||
|
||||
// Parallel initialization of per-block state
|
||||
@@ -720,7 +720,7 @@ static void fa_phase_q_load(struct hmx_fa_context * factx,
|
||||
uint32_t kv_head,
|
||||
uint32_t ib3,
|
||||
size_t n_rows_g) {
|
||||
worker_pool_context_t wp = factx->octx->ctx->worker_pool;
|
||||
work_queue_t wp = factx->octx->ctx->work_queue;
|
||||
uint32_t n = 1;
|
||||
if (factx->n_threads > 1 && n_rows_g >= (size_t) (factx->n_threads * 2)) {
|
||||
n = factx->n_threads;
|
||||
@@ -739,7 +739,7 @@ static void fa_phase_q_load(struct hmx_fa_context * factx,
|
||||
args.q_transposed = q->nb[1] < q->nb[2];
|
||||
atomic_init(&args.barrier, n);
|
||||
if (n > 1) {
|
||||
worker_pool_run_func(wp, fa_q_load_thread, &args, n);
|
||||
work_queue_run(wp, fa_q_load_thread, &args, n);
|
||||
} else {
|
||||
fa_q_load_thread(1, 0, &args);
|
||||
}
|
||||
@@ -772,7 +772,7 @@ static void fa_o_store_thread_f32(unsigned int n, unsigned int i, void * data) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = factx->octx->ctx ? &factx->octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &factx->octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_O_PROC, (uint16_t) (args->q_start * G + start));
|
||||
|
||||
const struct htp_tensor * dst = args->dst;
|
||||
@@ -820,7 +820,7 @@ static void fa_o_store_thread_f16(unsigned int n, unsigned int i, void * data) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = factx->octx->ctx ? &factx->octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &factx->octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_O_PROC, (uint16_t) (args->q_start * G + start));
|
||||
|
||||
const struct htp_tensor * dst = args->dst;
|
||||
@@ -862,7 +862,7 @@ static void fa_phase_o_store(struct hmx_fa_context * factx,
|
||||
uint32_t kv_head,
|
||||
uint32_t ib3,
|
||||
size_t n_rows_g) {
|
||||
worker_pool_context_t wp = factx->octx->ctx->worker_pool;
|
||||
work_queue_t wp = factx->octx->ctx->work_queue;
|
||||
uint32_t n = 1;
|
||||
if (factx->n_threads > 1 && n_rows_g >= (size_t) (factx->n_threads * 2)) {
|
||||
n = factx->n_threads;
|
||||
@@ -871,7 +871,7 @@ static void fa_phase_o_store(struct hmx_fa_context * factx,
|
||||
fa_o_store_args_t args = { factx, dst, o_tile_src, q_start, kv_head, ib3, n_rows_g, rows_per_t };
|
||||
worker_callback_t store_fn = factx->is_dst_fp32 ? fa_o_store_thread_f32 : fa_o_store_thread_f16;
|
||||
if (n > 1) {
|
||||
worker_pool_run_func(wp, store_fn, &args, n);
|
||||
work_queue_run(wp, store_fn, &args, n);
|
||||
} else {
|
||||
store_fn(1, 0, &args);
|
||||
}
|
||||
@@ -930,7 +930,7 @@ static inline void fa_softmax_impl(
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = factx->octx->ctx ? &factx->octx->ctx->trace[i] : NULL;
|
||||
struct htp_thread_trace * tr = &factx->octx->ctx->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_FA_SFM, (uint16_t) (args->q_start * G + vec_start * 64));
|
||||
|
||||
// Per-thread row scratch: thread i uses bufs at offset i * 2 * stride
|
||||
@@ -1290,7 +1290,7 @@ static void fa_phase_softmax_and_build_d(struct hmx_fa_context * factx,
|
||||
fa_softmax_args_t * sargs,
|
||||
size_t n_row_tiles,
|
||||
size_t n_row_tiles_g_br) {
|
||||
worker_pool_context_t wp = factx->octx->ctx->worker_pool;
|
||||
work_queue_t wp = factx->octx->ctx->work_queue;
|
||||
const size_t n_row_vec_cnt = hmx_ceil_div(sargs->n_rows_g, 64);
|
||||
|
||||
worker_callback_t softmax_fn = fa_softmax_thread;
|
||||
@@ -1307,7 +1307,7 @@ static void fa_phase_softmax_and_build_d(struct hmx_fa_context * factx,
|
||||
if (factx->n_threads > 1 && n_row_vec_cnt >= 2) {
|
||||
uint32_t n_use = (uint32_t) hex_smin((size_t) factx->n_threads, n_row_vec_cnt);
|
||||
sargs->thread_div = init_fastdiv_values(n_use);
|
||||
worker_pool_run_func(wp, softmax_fn, sargs, n_use);
|
||||
work_queue_run(wp, softmax_fn, sargs, n_use);
|
||||
} else {
|
||||
softmax_fn(1, 0, sargs);
|
||||
}
|
||||
@@ -1519,8 +1519,8 @@ static void fa_pop_mask_dma_gqa(dma_queue * dma, uint32_t G) {
|
||||
// ============================================================================
|
||||
|
||||
int hmx_flash_attn_ext(struct htp_ops_context * octx) {
|
||||
struct htp_thread_trace * tr_hvx = octx->ctx ? &octx->ctx->trace[0] : NULL;
|
||||
struct htp_thread_trace * tr_hmx = octx->ctx ? &octx->ctx->trace[HTP_MAX_NTHREADS] : NULL;
|
||||
struct htp_thread_trace * tr_hvx = &octx->ctx->trace[0];
|
||||
struct htp_thread_trace * tr_hmx = &octx->ctx->trace[HTP_MAX_NTHREADS];
|
||||
const struct htp_tensor * q = octx->src[0];
|
||||
const struct htp_tensor * k = octx->src[1];
|
||||
const struct htp_tensor * v = octx->src[2];
|
||||
@@ -1735,7 +1735,7 @@ int hmx_flash_attn_ext(struct htp_ops_context * octx) {
|
||||
const size_t k_src_stride = size_k_row_padded / sizeof(__fp16);
|
||||
const size_t v_src_stride = size_v_row_padded / sizeof(__fp16);
|
||||
|
||||
struct hmx_queue * hmx_q = ctx->hmx_queue;
|
||||
hmx_queue_t hmx_q = ctx->hmx_queue;
|
||||
|
||||
if (factx.pipeline) {
|
||||
// Pipeline path
|
||||
@@ -2084,7 +2084,7 @@ int op_flash_attn_ext(struct htp_ops_context * octx) {
|
||||
}
|
||||
|
||||
if (!(octx->flags & HTP_OPFLAGS_SKIP_COMPUTE)) {
|
||||
worker_pool_run_func(octx->ctx->worker_pool, flash_attn_ext_f16_thread, &factx, octx->n_threads);
|
||||
work_queue_run(octx->ctx->work_queue, flash_attn_ext_f16_thread, &factx, octx->n_threads);
|
||||
}
|
||||
|
||||
return HTP_STATUS_OK;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef HEX_BITMAP_H
|
||||
#define HEX_BITMAP_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static inline void bitmap_set(uint32_t * bitmap, uint32_t idx) {
|
||||
bitmap[idx / 32] |= (1U << (idx % 32));
|
||||
}
|
||||
|
||||
static inline void bitmap_clear(uint32_t * bitmap, uint32_t idx) {
|
||||
bitmap[idx / 32] &= ~(1U << (idx % 32));
|
||||
}
|
||||
|
||||
static inline bool bitmap_test(const uint32_t * bitmap, uint32_t idx) {
|
||||
return (bitmap[idx / 32] & (1U << (idx % 32))) != 0;
|
||||
}
|
||||
|
||||
static inline void bitmap_reset(uint32_t * bitmap, size_t size_in_bits) {
|
||||
memset(bitmap, 0, ((size_in_bits + 31) / 32) * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
#endif // HEX_BITMAP_H
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "hex-dma.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#pragma clang diagnostic ignored "-Wunused-function"
|
||||
|
||||
static inline uint32_t pow2_ceil(uint32_t x) {
|
||||
if (x <= 1) {
|
||||
return 1;
|
||||
}
|
||||
int p = 2;
|
||||
x--;
|
||||
while (x >>= 1) {
|
||||
p <<= 1;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
dma_queue * dma_queue_create(size_t capacity) {
|
||||
dma_queue * q = (dma_queue *) memalign(32, sizeof(dma_queue));
|
||||
if (q == NULL) {
|
||||
FARF(ERROR, "%s: failed to allocate DMA queue\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
capacity = pow2_ceil(capacity);
|
||||
|
||||
memset(q, 0, sizeof(dma_queue));
|
||||
q->capacity = capacity;
|
||||
q->idx_mask = capacity - 1;
|
||||
|
||||
q->desc = (dma_descriptor_2d *) memalign(64, capacity * sizeof(dma_descriptor_2d));
|
||||
memset(q->desc, 0, capacity * sizeof(dma_descriptor_2d));
|
||||
|
||||
q->dptr = (dma_ptr *) memalign(4, capacity * sizeof(dma_ptr));
|
||||
memset(q->dptr, 0, capacity * sizeof(dma_ptr));
|
||||
|
||||
q->tail = &q->desc[capacity - 1];
|
||||
|
||||
if (!q->desc && !q->dptr) {
|
||||
FARF(ERROR, "%s: failed to allocate DMA queue items\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FARF(HIGH, "dma-queue: capacity %u\n", capacity);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void dma_queue_delete(dma_queue * q) {
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
free(q->desc);
|
||||
free(q->dptr);
|
||||
free(q);
|
||||
}
|
||||
|
||||
void dma_queue_flush(dma_queue * q) {
|
||||
while (dma_queue_pop(q).dst != NULL) ;
|
||||
}
|
||||
@@ -1,375 +1,2 @@
|
||||
#ifndef HTP_DMA_H
|
||||
#define HTP_DMA_H
|
||||
|
||||
#include <HAP_farf.h>
|
||||
#include <hexagon_types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "hex-utils.h"
|
||||
|
||||
#include "hex-profile.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Define the HW descriptor structs here since the ones in HexSDK are a bit out of date
|
||||
typedef struct dma_descriptor_1d_s {
|
||||
void * next;
|
||||
uint32_t size:24;
|
||||
uint32_t desc_size:2;
|
||||
uint32_t dst_comp:1;
|
||||
uint32_t src_comp:1;
|
||||
uint32_t dst_bypass:1;
|
||||
uint32_t src_bypass:1;
|
||||
uint32_t order:1;
|
||||
uint32_t done:1;
|
||||
void * src;
|
||||
void * dst;
|
||||
} dma_descriptor_1d;
|
||||
|
||||
#if __HVX_ARCH__ < 75
|
||||
|
||||
typedef struct dma_descriptor_2d_s {
|
||||
void * next;
|
||||
uint32_t reserved0:24;
|
||||
uint32_t desc_size:2;
|
||||
uint32_t dst_comp:1;
|
||||
uint32_t src_comp:1;
|
||||
uint32_t dst_bypass:1;
|
||||
uint32_t src_bypass:1;
|
||||
uint32_t order:1;
|
||||
uint32_t done:1;
|
||||
void * src;
|
||||
void * dst;
|
||||
uint32_t desc_type:8;
|
||||
uint32_t reserved1:24;
|
||||
uint32_t row_size:16;
|
||||
uint32_t nrows:16;
|
||||
uint32_t src_stride:16;
|
||||
uint32_t dst_stride:16;
|
||||
uint32_t src_offset:16;
|
||||
uint32_t dst_offset:16;
|
||||
} dma_descriptor_2d;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct dma_descriptor_2d_s {
|
||||
void * next;
|
||||
uint32_t dst_stride:24;
|
||||
uint32_t desc_size:2;
|
||||
uint32_t dst_comp:1;
|
||||
uint32_t src_comp:1;
|
||||
uint32_t dst_bypass:1;
|
||||
uint32_t src_bypass:1;
|
||||
uint32_t order:1;
|
||||
uint32_t done:1;
|
||||
void * src;
|
||||
void * dst;
|
||||
uint32_t desc_type:8;
|
||||
uint32_t reserved0:24;
|
||||
uint32_t row_size:24;
|
||||
uint32_t nrows_lo:8;
|
||||
uint32_t nrows_hi:8;
|
||||
uint32_t src_stride:24;
|
||||
uint32_t offset:24;
|
||||
uint32_t reserved1:8;
|
||||
} dma_descriptor_2d;
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
void *dst;
|
||||
const void *src;
|
||||
} dma_ptr;
|
||||
|
||||
typedef struct {
|
||||
dma_descriptor_2d * desc; // descriptor pointers
|
||||
dma_descriptor_2d * tail; // tail pointer
|
||||
dma_ptr * dptr; // dst/src pointers
|
||||
uint32_t push_idx;
|
||||
uint32_t pop_idx;
|
||||
uint32_t capacity;
|
||||
uint32_t idx_mask;
|
||||
struct htp_thread_trace * trace;
|
||||
} dma_queue;
|
||||
|
||||
dma_queue * dma_queue_create(size_t capacity);
|
||||
void dma_queue_delete(dma_queue * q);
|
||||
void dma_queue_flush(dma_queue * q);
|
||||
|
||||
// TODO: technically we don't need these and could use Q6_dmstart/wait/etc instead
|
||||
// but those do not seem to always compiler properly.
|
||||
static inline void dmstart(void * next) {
|
||||
asm volatile(" release(%0):at" : : "r"(next));
|
||||
asm volatile(" dmstart(%0)" : : "r"(next));
|
||||
}
|
||||
|
||||
static inline void dmlink(void * cur, void * next) {
|
||||
asm volatile(" release(%0):at" : : "r"(next));
|
||||
asm volatile(" dmlink(%0, %1)" : : "r"(cur), "r"(next));
|
||||
}
|
||||
|
||||
static inline unsigned int dmpoll(void) {
|
||||
unsigned int ret = 0;
|
||||
asm volatile(" %0 = dmpoll" : "=r"(ret) : : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline unsigned int dmwait(void) {
|
||||
unsigned int ret = 0;
|
||||
asm volatile(" %0 = dmwait" : "=r"(ret) : : "memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline dma_ptr dma_make_ptr(void *dst, const void *src)
|
||||
{
|
||||
dma_ptr p = { dst, src };
|
||||
return p;
|
||||
}
|
||||
|
||||
static const uint32_t dma_src_l2_bypass_on = 1;
|
||||
static const uint32_t dma_dst_l2_bypass_on = 1;
|
||||
|
||||
static inline bool dma_queue_push_single_1d(dma_queue * q, dma_ptr dptr, size_t size) {
|
||||
if (((q->push_idx + 1) & q->idx_mask) == q->pop_idx) {
|
||||
FARF(HIGH, "dma-push: queue full\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dma_descriptor_1d * desc = (dma_descriptor_1d *) &q->desc[q->push_idx];
|
||||
desc->src = (void *) dptr.src;
|
||||
desc->dst = (void *) dptr.dst;
|
||||
desc->size = size;
|
||||
|
||||
q->dptr[q->push_idx] = dptr;
|
||||
|
||||
if (size) {
|
||||
desc->next = NULL;
|
||||
desc->desc_size = 0; // 1D mode
|
||||
desc->src_bypass = dma_src_l2_bypass_on;
|
||||
desc->dst_bypass = dma_dst_l2_bypass_on;
|
||||
desc->order = 0;
|
||||
desc->done = 0;
|
||||
|
||||
htp_trace_event_start(q->trace, HTP_TRACE_EVT_DMA, q->push_idx);
|
||||
dmlink(q->tail, desc);
|
||||
q->tail = (dma_descriptor_2d *) desc;
|
||||
} else {
|
||||
desc->desc_size = 0;
|
||||
desc->done = 1;
|
||||
}
|
||||
|
||||
q->push_idx = (q->push_idx + 1) & q->idx_mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool dma_queue_push_single_2d(dma_queue * q, dma_ptr dptr, size_t dst_stride, size_t src_stride, size_t row_size, size_t nrows) {
|
||||
if (((q->push_idx + 1) & q->idx_mask) == q->pop_idx) {
|
||||
FARF(HIGH, "dma-push: queue full\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
dma_descriptor_2d * desc = &q->desc[q->push_idx];
|
||||
|
||||
desc->next = NULL;
|
||||
desc->reserved0 = 0;
|
||||
desc->reserved1 = 0;
|
||||
desc->desc_size = 1; // 2d mode
|
||||
desc->src_bypass = dma_src_l2_bypass_on;
|
||||
desc->dst_bypass = dma_dst_l2_bypass_on;
|
||||
desc->src_comp = 0;
|
||||
desc->dst_comp = 0;
|
||||
desc->order = 0;
|
||||
desc->done = 0;
|
||||
desc->src_stride = src_stride;
|
||||
desc->dst_stride = dst_stride;
|
||||
desc->src = (void *) dptr.src;
|
||||
desc->dst = (void *) dptr.dst;
|
||||
desc->row_size = row_size;
|
||||
|
||||
#if __HVX_ARCH__ < 75
|
||||
desc->desc_type = 0; // 2d (16-bit) mode
|
||||
desc->nrows = nrows;
|
||||
desc->src_offset = 0;
|
||||
desc->dst_offset = 0;
|
||||
#else
|
||||
desc->desc_type = 9; // 2d (24-bit) mode
|
||||
desc->nrows_lo = (nrows & 0xff);
|
||||
desc->nrows_hi = (nrows >> 8);
|
||||
desc->offset = 0;
|
||||
#endif
|
||||
|
||||
q->dptr[q->push_idx] = dptr;
|
||||
|
||||
if (nrows) {
|
||||
htp_trace_event_start(q->trace, HTP_TRACE_EVT_DMA, q->push_idx);
|
||||
dmlink(q->tail, desc);
|
||||
q->tail = desc;
|
||||
} else {
|
||||
desc->done = 1;
|
||||
}
|
||||
|
||||
// FARF(ERROR, "dma-push: i %u row-size %u nrows %d dst %p src %p\n", q->push_idx, row_size, nrows, dptr.dst, dptr.src);
|
||||
q->push_idx = (q->push_idx + 1) & q->idx_mask;
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline dma_ptr dma_queue_pop(dma_queue * q) {
|
||||
dma_ptr dptr = { NULL };
|
||||
|
||||
if (q->push_idx == q->pop_idx) {
|
||||
return dptr;
|
||||
}
|
||||
|
||||
dma_descriptor_2d * desc = &q->desc[q->pop_idx];
|
||||
|
||||
// Wait for desc to complete
|
||||
if (!desc->done) {
|
||||
while (!desc->done) {
|
||||
dmpoll();
|
||||
}
|
||||
}
|
||||
htp_trace_event_stop(q->trace, HTP_TRACE_EVT_DMA, q->pop_idx);
|
||||
|
||||
dptr = q->dptr[q->pop_idx];
|
||||
|
||||
// FARF(ERROR, "dma-pop: i %u dst %p src %p\n", q->pop_idx, dptr.dst, dptr.src);
|
||||
q->pop_idx = (q->pop_idx + 1) & q->idx_mask;
|
||||
return dptr;
|
||||
}
|
||||
|
||||
static inline dma_ptr dma_queue_pop_nowait(dma_queue * q) {
|
||||
dma_ptr dptr = { NULL };
|
||||
|
||||
if (q->push_idx == q->pop_idx) {
|
||||
return dptr;
|
||||
}
|
||||
|
||||
dptr = q->dptr[q->pop_idx];
|
||||
|
||||
// FARF(ERROR, "dma-pop-nowait: i %u dst %p src %p\n", q->pop_idx, dptr.dst, dptr.src);
|
||||
q->pop_idx = (q->pop_idx + 1) & q->idx_mask;
|
||||
return dptr;
|
||||
}
|
||||
|
||||
static inline bool dma_queue_empty(dma_queue * q) {
|
||||
return q->push_idx == q->pop_idx;
|
||||
}
|
||||
|
||||
static inline uint32_t dma_queue_depth(dma_queue * q) {
|
||||
return (q->push_idx - q->pop_idx) & q->idx_mask;
|
||||
}
|
||||
|
||||
static inline uint32_t dma_queue_capacity(dma_queue * q) {
|
||||
return q->capacity;
|
||||
}
|
||||
|
||||
#if __HVX_ARCH__ < 75
|
||||
|
||||
// Overflow-safe DMA push: all 2d descriptor fields (row_size, nrows, src_stride, dst_stride) are 16-bit, max 65535.
|
||||
// This version transparently handles values that exceed the 16-bit limit and submits chained DMA transtions.
|
||||
|
||||
#define DMA_MAX_FIELD_VAL 65535u
|
||||
|
||||
static inline bool dma_queue_push(dma_queue *q, dma_ptr dptr, size_t dst_stride, size_t src_stride, size_t row_size, size_t nrows) {
|
||||
// Fast path: everything fits in 16 bits
|
||||
if (nrows == 0 || __builtin_expect(
|
||||
row_size <= DMA_MAX_FIELD_VAL &&
|
||||
nrows <= DMA_MAX_FIELD_VAL &&
|
||||
src_stride <= DMA_MAX_FIELD_VAL &&
|
||||
dst_stride <= DMA_MAX_FIELD_VAL, 1)) {
|
||||
return dma_queue_push_single_2d(q, dptr, dst_stride, src_stride, row_size, nrows);
|
||||
}
|
||||
|
||||
// Contiguous block
|
||||
// Use 1d DMA mode which supports sizes up to 24-bits (16MB)
|
||||
if (nrows == 1 || (row_size == src_stride && row_size == dst_stride)) {
|
||||
size_t total = row_size * nrows;
|
||||
return dma_queue_push_single_1d(q, dptr, total);
|
||||
}
|
||||
|
||||
// Stride overflow — fall back to row-by-row.
|
||||
{
|
||||
const uint8_t *src = (const uint8_t *) dptr.src;
|
||||
uint8_t *dst = (uint8_t *) dptr.dst;
|
||||
for (size_t r = 0; r < nrows; ++r) {
|
||||
dma_ptr p = dma_make_ptr(dst + r * dst_stride, src + r * src_stride);
|
||||
if (!dma_queue_push_single_1d(q, p, row_size))
|
||||
return false;
|
||||
if (r + 1 < nrows)
|
||||
dma_queue_pop(q);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
#else // HVX_ARCH >= 75
|
||||
|
||||
static inline bool dma_queue_push(dma_queue *q, dma_ptr dptr, size_t dst_stride, size_t src_stride, size_t row_size, size_t nrows) {
|
||||
// On v75 and up we always use 2d 24-bit mode
|
||||
return dma_queue_push_single_2d(q, dptr, dst_stride, src_stride, row_size, nrows);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static inline bool dma_queue_push_ddr_to_vtcm(dma_queue * q, dma_ptr dptr, size_t dst_row_size, size_t src_row_size, size_t nrows) {
|
||||
return dma_queue_push(q, dptr, dst_row_size, src_row_size, src_row_size, nrows);
|
||||
}
|
||||
|
||||
static inline bool dma_queue_push_vtcm_to_ddr(dma_queue * q, dma_ptr dptr, size_t dst_row_size, size_t src_row_size, size_t nrows) {
|
||||
return dma_queue_push(q, dptr, dst_row_size, src_row_size, dst_row_size, nrows);
|
||||
}
|
||||
|
||||
#define DMA_CACHE_MAX_SIZE 256U
|
||||
|
||||
typedef struct {
|
||||
uint8_t *base;
|
||||
uint32_t line_size;
|
||||
uint32_t capacity;
|
||||
uint32_t src[DMA_CACHE_MAX_SIZE];
|
||||
uint16_t age[DMA_CACHE_MAX_SIZE];
|
||||
} dma_cache;
|
||||
|
||||
static inline void dma_cache_init(dma_cache *c, uint8_t *base, uint32_t line_size, uint32_t capacity)
|
||||
{
|
||||
c->capacity = (capacity > DMA_CACHE_MAX_SIZE) ? DMA_CACHE_MAX_SIZE : capacity;
|
||||
c->base = base;
|
||||
c->line_size = line_size;
|
||||
|
||||
for (unsigned i=0; i < c->capacity; i++) {
|
||||
c->src[i] = 0;
|
||||
c->age[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool dma_cache_push(dma_queue *q, dma_cache *c, const uint8_t * src, uint32_t dst_stride, uint32_t src_stride, uint32_t row_size, uint32_t nrows)
|
||||
{
|
||||
uint32_t o_idx = 0;
|
||||
uint16_t o_age = 0;
|
||||
uint8_t * dst = 0;
|
||||
|
||||
for (unsigned i=0; i < c->capacity; i++) {
|
||||
if (c->src[i] == (uint32_t) src) {
|
||||
c->age[i] = 0;
|
||||
dst = c->base + (i * c->line_size); nrows = 0; // dummy dma
|
||||
} else {
|
||||
c->age[i]++;
|
||||
if (c->age[i] > o_age) { o_age = c->age[i]; o_idx = i; }
|
||||
}
|
||||
}
|
||||
if (!dst) {
|
||||
c->age[o_idx] = 0;
|
||||
c->src[o_idx] = (uint32_t) src;
|
||||
dst = c->base + o_idx * c->line_size; // normal nrows dma
|
||||
return dma_queue_push(q, dma_make_ptr(dst, src), dst_stride, src_stride, row_size, nrows);
|
||||
}
|
||||
|
||||
return dma_queue_push_single_1d(q, dma_make_ptr(dst, src), 0);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#endif /* HTP_DMA_H */
|
||||
#pragma once
|
||||
#include "dma-queue.h"
|
||||
|
||||
@@ -44,11 +44,11 @@ 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 && tr->events && tr->count < tr->max_events) {
|
||||
uint32_t idx = tr->count;
|
||||
tr->events[idx].id = id;
|
||||
tr->events[idx].info = info | (type == HTP_TRACE_EVT_STOP ? 0x8000 : 0);
|
||||
tr->events[idx].cycles = (uint32_t) hex_get_cycles();
|
||||
if (tr->count < tr->max_events) {
|
||||
uint32_t i = tr->count;
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,21 +30,26 @@ static inline void hex_l2fetch(const void * p, uint32_t width, uint32_t stride,
|
||||
Q6_l2fetch_AP((void *) p, control);
|
||||
}
|
||||
|
||||
#define HEX_L2_LINE_SIZE 64
|
||||
#define HEX_L2_FLUSH_SIZE (128 * 1024)
|
||||
static inline void hex_l2fetch_block(const void * addr, size_t size) {
|
||||
if (size == 0) return;
|
||||
const uint32_t width = 16384; // 16KB rows
|
||||
const uint32_t height = (size + width - 1) / width;
|
||||
hex_l2fetch(addr, width, width, height);
|
||||
}
|
||||
|
||||
#define HEX_L2_LINE_SIZE 128
|
||||
#define HEX_L2_BLOCK_SIZE (HEX_L2_LINE_SIZE * 4) // flush granularity (lines per loop iteration)
|
||||
#define HEX_L2_FLUSH_WQ_THRESHOLD (4 * 1024)
|
||||
#define HEX_L2_FLUSH_ALL_THRESHOLD (4 * 1024 * 1024)
|
||||
|
||||
static inline void hex_l2flush(void * addr, size_t size) {
|
||||
if (size > HEX_L2_FLUSH_SIZE) {
|
||||
qurt_mem_cache_clean((qurt_addr_t) 0, 0, QURT_MEM_CACHE_FLUSH_INVALIDATE_ALL, QURT_MEM_DCACHE);
|
||||
} else {
|
||||
const uint32_t s = (uint32_t) addr;
|
||||
const uint32_t e = s + size;
|
||||
for (uint32_t i = s; i < e; i += HEX_L2_LINE_SIZE * 4) {
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 0);
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 1);
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 2);
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 3);
|
||||
}
|
||||
const uint32_t s = ((uint32_t) addr) & ~(HEX_L2_LINE_SIZE - 1);
|
||||
const uint32_t e = (((uint32_t) addr) + size + HEX_L2_LINE_SIZE - 1) & ~(HEX_L2_LINE_SIZE - 1);
|
||||
for (uint32_t i = s; i < e; i += HEX_L2_BLOCK_SIZE) {
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 0);
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 1);
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 2);
|
||||
Q6_dccleaninva_A((void *) i + HEX_L2_LINE_SIZE * 3);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1005,10 +1005,62 @@ static void transfer_activation_row_pair_fp32_to_fp16(
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_activation_row_pair_fp32_to_fp16_col_chunk(
|
||||
__fp16 *restrict vtcm_dst,
|
||||
const float *restrict row0, // offset by c_first
|
||||
const float *restrict row1, // offset by c_first
|
||||
uint32_t r,
|
||||
uint32_t k_block,
|
||||
uint32_t c_first,
|
||||
uint32_t c_len,
|
||||
uint32_t k_chunk_valid,
|
||||
bool row0_valid,
|
||||
bool row1_valid) {
|
||||
|
||||
uint32_t r0 = r / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = r % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
|
||||
uint32_t c = 0;
|
||||
for (; c + 32 <= k_chunk_valid; c += 32) {
|
||||
HVX_Vector v0 = Q6_V_vzero();
|
||||
HVX_Vector v1 = Q6_V_vzero();
|
||||
if (row0_valid) v0 = *(const HVX_Vector *)(row0 + c);
|
||||
if (row1_valid) v1 = *(const HVX_Vector *)(row1 + c);
|
||||
|
||||
HVX_Vector v_out = hvx_vec_f32_to_f16_shuff(v0, v1);
|
||||
|
||||
uint32_t c0 = (c_first + c) / HTP_MM_HMX_TILE_N_COLS; // tile column index
|
||||
uint32_t tile_idx = r0 * (k_block / HTP_MM_HMX_TILE_N_COLS) + c0;
|
||||
|
||||
HVX_Vector *tile = (HVX_Vector *) (vtcm_dst + tile_idx * HTP_MM_HMX_TILE_N_ELMS);
|
||||
tile[r1 / 2] = v_out;
|
||||
}
|
||||
if (c < c_len) {
|
||||
HVX_Vector v0 = Q6_V_vzero();
|
||||
HVX_Vector v1 = Q6_V_vzero();
|
||||
if (row0_valid) v0 = *(const HVX_Vector *)(row0 + c);
|
||||
if (row1_valid) v1 = *(const HVX_Vector *)(row1 + c);
|
||||
|
||||
uint32_t rem = (k_chunk_valid > c) ? (k_chunk_valid - c) : 0;
|
||||
HVX_VectorPred mask = Q6_Q_vsetq2_R(rem > 0 ? rem * sizeof(float) : 0);
|
||||
v0 = Q6_V_vmux_QVV(mask, v0, Q6_V_vzero());
|
||||
v1 = Q6_V_vmux_QVV(mask, v1, Q6_V_vzero());
|
||||
|
||||
HVX_Vector v_out = hvx_vec_f32_to_f16_shuff(v0, v1);
|
||||
|
||||
uint32_t c0 = (c_first + c) / HTP_MM_HMX_TILE_N_COLS; // tile column index
|
||||
uint32_t tile_idx = r0 * (k_block / HTP_MM_HMX_TILE_N_COLS) + c0;
|
||||
|
||||
HVX_Vector *tile = (HVX_Vector *) (vtcm_dst + tile_idx * HTP_MM_HMX_TILE_N_ELMS);
|
||||
tile[r1 / 2] = v_out;
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_activation_chunk_fp32_to_fp16_gathered(
|
||||
__fp16 *restrict vtcm_dst,
|
||||
const float *restrict src,
|
||||
uint32_t start_row,
|
||||
uint32_t vtcm_start_row,
|
||||
uint32_t n_rows,
|
||||
uint32_t k_block,
|
||||
const struct mmid_row_mapping *matrix_rows,
|
||||
@@ -1029,8 +1081,9 @@ static void transfer_activation_chunk_fp32_to_fp16_gathered(
|
||||
for (r = 0; r < n_rows_tiled; r += 2) {
|
||||
uint32_t r_idx0 = start_row + r + 0;
|
||||
uint32_t r_idx1 = start_row + r + 1;
|
||||
uint32_t r0 = r_idx0 / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = r_idx0 % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
uint32_t lr = vtcm_start_row + r; // vtcm-local row
|
||||
uint32_t r0 = lr / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = lr % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
|
||||
struct mmid_row_mapping mapping0 = matrix_rows[cur_a * mapping_stride + r_idx0];
|
||||
struct mmid_row_mapping mapping1 = matrix_rows[cur_a * mapping_stride + r_idx1];
|
||||
@@ -1073,9 +1126,9 @@ static void transfer_activation_chunk_fp32_to_fp16_gathered(
|
||||
}
|
||||
|
||||
for (; r < n_rows_padded; r += 2) {
|
||||
uint32_t r_idx0 = start_row + r;
|
||||
uint32_t r0 = r_idx0 / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = r_idx0 % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
uint32_t lr = vtcm_start_row + r; // vtcm-local row
|
||||
uint32_t r0 = lr / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = lr % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
|
||||
const bool row0_valid = (start_row + r + 0) < cne1;
|
||||
const bool row1_valid = (start_row + r + 1) < cne1;
|
||||
@@ -1135,6 +1188,7 @@ static void transfer_activation_chunk_fp32_to_fp16_gathered_flat(
|
||||
__fp16 *restrict vtcm_dst,
|
||||
const float *restrict src,
|
||||
uint32_t start_row,
|
||||
uint32_t vtcm_start_row,
|
||||
uint32_t n_rows,
|
||||
uint32_t k_block,
|
||||
const struct mmid_row_mapping *matrix_rows,
|
||||
@@ -1152,8 +1206,9 @@ static void transfer_activation_chunk_fp32_to_fp16_gathered_flat(
|
||||
for (r = 0; r < n_rows_tiled; r += 2) {
|
||||
uint32_t r_idx0 = start_row + r + 0;
|
||||
uint32_t r_idx1 = start_row + r + 1;
|
||||
uint32_t r0 = r_idx0 / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = r_idx0 % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
uint32_t lr = vtcm_start_row + r; // vtcm-local row
|
||||
uint32_t r0 = lr / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = lr % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
|
||||
struct mmid_row_mapping mapping0 = matrix_rows[cur_a * mapping_stride + r_idx0];
|
||||
struct mmid_row_mapping mapping1 = matrix_rows[cur_a * mapping_stride + r_idx1];
|
||||
@@ -1193,9 +1248,9 @@ static void transfer_activation_chunk_fp32_to_fp16_gathered_flat(
|
||||
}
|
||||
|
||||
for (; r < n_rows_padded; r += 2) {
|
||||
uint32_t r_idx0 = start_row + r;
|
||||
uint32_t r0 = r_idx0 / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = r_idx0 % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
uint32_t lr = vtcm_start_row + r; // vtcm-local row
|
||||
uint32_t r0 = lr / HTP_MM_HMX_TILE_N_ROWS; // tile row index
|
||||
uint32_t r1 = lr % HTP_MM_HMX_TILE_N_ROWS; // intra-tile row idx
|
||||
|
||||
const bool row0_valid = (start_row + r + 0) < cne1;
|
||||
const bool row1_valid = (start_row + r + 1) < cne1;
|
||||
@@ -1253,6 +1308,7 @@ static void transfer_output_chunk_fp16_to_fp32_scattered(
|
||||
float *restrict dst,
|
||||
const __fp16 *restrict vtcm_src,
|
||||
uint32_t start_row,
|
||||
uint32_t vtcm_start_row,
|
||||
uint32_t n_rows,
|
||||
uint32_t n_cols,
|
||||
const struct mmid_row_mapping *matrix_rows,
|
||||
@@ -1269,8 +1325,9 @@ static void transfer_output_chunk_fp16_to_fp32_scattered(
|
||||
for (size_t r = 0; r < n_rows; r += 2) {
|
||||
uint32_t r_idx0 = start_row + r + 0;
|
||||
uint32_t r_idx1 = start_row + r + 1;
|
||||
const size_t r0 = r_idx0 / HTP_MM_HMX_TILE_N_ROWS;
|
||||
const size_t r1 = (r_idx0 % HTP_MM_HMX_TILE_N_ROWS) / 2; // index of the row pair within the tile
|
||||
uint32_t lr = vtcm_start_row + r; // vtcm-local row
|
||||
const size_t r0 = (lr / HTP_MM_HMX_TILE_N_ROWS);
|
||||
const size_t r1 = (lr % HTP_MM_HMX_TILE_N_ROWS) / 2; // index of the row pair within the tile
|
||||
const __fp16 *row_base = vtcm_src + r0 * tile_row_stride;
|
||||
|
||||
if (r_idx0 >= cne1) break;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
#define QURT_LOWEST_PRIO (254)
|
||||
|
||||
static inline void hmx_lock(struct hmx_queue *q)
|
||||
static inline void hmx_lock(hmx_queue_t q)
|
||||
{
|
||||
if (!q->hmx_locked) {
|
||||
HAP_compute_res_hmx_lock(q->hap_rctx);
|
||||
@@ -22,7 +22,7 @@ static inline void hmx_lock(struct hmx_queue *q)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hmx_unlock(struct hmx_queue *q)
|
||||
static inline void hmx_unlock(hmx_queue_t q)
|
||||
{
|
||||
if (q->hmx_locked) {
|
||||
HAP_compute_res_hmx_unlock(q->hap_rctx);
|
||||
@@ -30,7 +30,7 @@ static inline void hmx_unlock(struct hmx_queue *q)
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hmx_queue_process(struct hmx_queue *q, bool* killed) {
|
||||
static inline void hmx_queue_process(hmx_queue_t q, bool* killed) {
|
||||
unsigned int ir = atomic_load(&q->idx_read);
|
||||
|
||||
while (ir != atomic_load(&q->idx_write)) {
|
||||
@@ -61,7 +61,7 @@ static inline void hmx_queue_process(struct hmx_queue *q, bool* killed) {
|
||||
}
|
||||
|
||||
static void hmx_queue_thread(void * arg) {
|
||||
struct hmx_queue * q = (struct hmx_queue *) arg;
|
||||
hmx_queue_t q = (hmx_queue_t) arg;
|
||||
|
||||
FARF(HIGH, "hmx-queue-thread: started");
|
||||
|
||||
@@ -93,34 +93,41 @@ static void hmx_queue_thread(void * arg) {
|
||||
FARF(HIGH, "hmx-queue-thread: stopped");
|
||||
}
|
||||
|
||||
struct hmx_queue * hmx_queue_create(size_t capacity, uint32_t hap_rctx) {
|
||||
size_t hmx_queue_sizeof(size_t capacity, uint32_t stack_size) {
|
||||
capacity = hex_ceil_pow2(capacity);
|
||||
size_t size_q = hex_align_up(sizeof(struct hmx_queue_s), HEX_L2_LINE_SIZE);
|
||||
size_t size_desc = hex_align_up(capacity * sizeof(struct hmx_queue_desc), HEX_L2_LINE_SIZE);
|
||||
size_t size_stack = stack_size;
|
||||
return size_q + size_desc + size_stack;
|
||||
}
|
||||
|
||||
size_t hmx_queue_alignof(void) {
|
||||
return HEX_L2_LINE_SIZE;
|
||||
}
|
||||
|
||||
hmx_queue_t hmx_queue_init(void * ptr, size_t capacity, uint32_t stack_size, uint32_t hap_rctx, struct htp_thread_trace * trace) {
|
||||
capacity = hex_ceil_pow2(capacity);
|
||||
size_t size_q = hex_align_up(sizeof(struct hmx_queue_s), HEX_L2_LINE_SIZE);
|
||||
size_t size_desc = hex_align_up(capacity * sizeof(struct hmx_queue_desc), HEX_L2_LINE_SIZE);
|
||||
|
||||
uint8_t * block = (uint8_t *) ptr;
|
||||
|
||||
hmx_queue_t q = (hmx_queue_t) block; block += size_q;
|
||||
memset(q, 0, sizeof(struct hmx_queue_s));
|
||||
|
||||
struct hmx_queue * q = (struct hmx_queue *) memalign(32, sizeof(struct hmx_queue));
|
||||
if (q == NULL) {
|
||||
FARF(ERROR, "%s: failed to allocate DMA queue\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
memset(q, 0, sizeof(struct hmx_queue));
|
||||
q->capacity = capacity;
|
||||
q->idx_mask = capacity - 1;
|
||||
q->hap_rctx = hap_rctx;
|
||||
q->external_mem = true;
|
||||
|
||||
q->desc = (struct hmx_queue_desc *) memalign(64, capacity * sizeof(struct hmx_queue_desc));
|
||||
if (!q->desc) {
|
||||
FARF(ERROR, "hmx-queue: failed to allocate HMX queue descriptors\n");
|
||||
return NULL;
|
||||
}
|
||||
q->desc = (struct hmx_queue_desc *) block; block += size_desc;
|
||||
memset(q->desc, 0, capacity * sizeof(struct hmx_queue_desc));
|
||||
|
||||
const size_t stack_size = HMX_QUEUE_THREAD_STACK_SIZE;
|
||||
q->stack = (unsigned char *) memalign(64, stack_size);
|
||||
if (!q->stack) {
|
||||
FARF(ERROR, "hmx-queue: thread stack allocation failed (%zu bytes)", stack_size);
|
||||
return NULL;
|
||||
}
|
||||
q->stack = block;
|
||||
memset(q->stack, 0, stack_size);
|
||||
|
||||
q->trace = trace;
|
||||
|
||||
// Match caller thread priority (same pattern as worker-pool.c).
|
||||
int prio = qurt_thread_get_priority(qurt_thread_get_id());
|
||||
if (prio < 1) {
|
||||
@@ -148,7 +155,7 @@ struct hmx_queue * hmx_queue_create(size_t capacity, uint32_t hap_rctx) {
|
||||
return q;
|
||||
}
|
||||
|
||||
void hmx_queue_delete(struct hmx_queue * q) {
|
||||
void hmx_queue_free(hmx_queue_t q) {
|
||||
if (!q) {
|
||||
return;
|
||||
}
|
||||
@@ -160,8 +167,4 @@ void hmx_queue_delete(struct hmx_queue * q) {
|
||||
|
||||
int status;
|
||||
qurt_thread_join(q->thread, &status);
|
||||
|
||||
free(q->desc);
|
||||
free(q->stack);
|
||||
free(q);
|
||||
}
|
||||
|
||||
@@ -17,8 +17,6 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HMX_QUEUE_THREAD_STACK_SIZE (16 * 1024)
|
||||
|
||||
#if __HVX_ARCH__ > 79
|
||||
#define HMX_QUEUE_POLL_COUNT 2000
|
||||
#else
|
||||
@@ -41,7 +39,7 @@ struct hmx_queue_desc {
|
||||
atomic_uint done;
|
||||
};
|
||||
|
||||
struct hmx_queue {
|
||||
struct hmx_queue_s {
|
||||
struct hmx_queue_desc * desc;
|
||||
atomic_uint idx_write; // updated by producer (push)
|
||||
atomic_uint idx_read; // updated by consumer (process)
|
||||
@@ -55,19 +53,24 @@ struct hmx_queue {
|
||||
uint32_t hap_rctx;
|
||||
bool hmx_locked;
|
||||
struct htp_thread_trace * trace;
|
||||
bool external_mem; // memory owned externally
|
||||
};
|
||||
|
||||
struct hmx_queue * hmx_queue_create(size_t capacity, uint32_t hap_rctx);
|
||||
void hmx_queue_delete(struct hmx_queue * q);
|
||||
typedef struct hmx_queue_s * hmx_queue_t;
|
||||
|
||||
size_t hmx_queue_sizeof(size_t capacity, uint32_t stack_size);
|
||||
size_t hmx_queue_alignof(void);
|
||||
hmx_queue_t hmx_queue_init(void * ptr, size_t capacity, uint32_t stack_size, uint32_t hap_rctx, struct htp_thread_trace * trace);
|
||||
void hmx_queue_free(hmx_queue_t q);
|
||||
|
||||
static inline struct hmx_queue_desc hmx_queue_make_desc(hmx_queue_func func, void * data) {
|
||||
struct hmx_queue_desc d = { func, data };
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline bool hmx_queue_push(struct hmx_queue * q, struct hmx_queue_desc d) {
|
||||
static inline bool hmx_queue_push(hmx_queue_t q, struct hmx_queue_desc d) {
|
||||
unsigned int ir = atomic_load(&q->idx_read);
|
||||
unsigned int iw = q->idx_write;
|
||||
unsigned int iw = atomic_load(&q->idx_write);
|
||||
|
||||
if (((iw + 1) & q->idx_mask) == ir) {
|
||||
FARF(HIGH, "hmx-queue-push: queue is full\n");
|
||||
@@ -87,25 +90,25 @@ static inline bool hmx_queue_push(struct hmx_queue * q, struct hmx_queue_desc d)
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool hmx_queue_signal(struct hmx_queue *q, enum hmx_queue_signal sig) {
|
||||
static inline bool hmx_queue_signal(hmx_queue_t q, enum hmx_queue_signal sig) {
|
||||
return hmx_queue_push(q, hmx_queue_make_desc((hmx_queue_func) sig, NULL));
|
||||
}
|
||||
|
||||
static inline bool hmx_queue_empty(struct hmx_queue * q) {
|
||||
return q->idx_pop == q->idx_write;
|
||||
static inline bool hmx_queue_empty(hmx_queue_t q) {
|
||||
return q->idx_pop == atomic_load(&q->idx_write);
|
||||
}
|
||||
|
||||
static inline uint32_t hmx_queue_depth(struct hmx_queue * q) {
|
||||
return (q->idx_read - q->idx_read) & q->idx_mask;
|
||||
static inline uint32_t hmx_queue_depth(hmx_queue_t q) {
|
||||
return (atomic_load(&q->idx_write) - atomic_load(&q->idx_read)) & q->idx_mask;
|
||||
}
|
||||
|
||||
static inline uint32_t hmx_queue_capacity(struct hmx_queue * q) {
|
||||
static inline uint32_t hmx_queue_capacity(hmx_queue_t q) {
|
||||
return q->capacity;
|
||||
}
|
||||
|
||||
static inline struct hmx_queue_desc hmx_queue_pop_one(struct hmx_queue * q) {
|
||||
static inline struct hmx_queue_desc hmx_queue_pop_one(hmx_queue_t q) {
|
||||
unsigned int ip = q->idx_pop;
|
||||
unsigned int iw = q->idx_write;
|
||||
unsigned int iw = atomic_load(&q->idx_write);
|
||||
|
||||
struct hmx_queue_desc rd = { NULL, NULL };
|
||||
if (ip == iw) {
|
||||
@@ -126,7 +129,7 @@ static inline struct hmx_queue_desc hmx_queue_pop_one(struct hmx_queue * q) {
|
||||
return rd;
|
||||
}
|
||||
|
||||
static inline struct hmx_queue_desc hmx_queue_pop(struct hmx_queue * q) {
|
||||
static inline struct hmx_queue_desc hmx_queue_pop(hmx_queue_t q) {
|
||||
while (1) {
|
||||
struct hmx_queue_desc d = hmx_queue_pop_one(q);
|
||||
|
||||
@@ -138,15 +141,15 @@ static inline struct hmx_queue_desc hmx_queue_pop(struct hmx_queue * q) {
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hmx_queue_flush(struct hmx_queue * q) {
|
||||
static inline void hmx_queue_flush(hmx_queue_t q) {
|
||||
while (hmx_queue_pop_one(q).func != NULL) ;
|
||||
}
|
||||
|
||||
static inline void hmx_queue_wakeup(struct hmx_queue * q) {
|
||||
static inline void hmx_queue_wakeup(hmx_queue_t q) {
|
||||
hmx_queue_signal(q, HMX_QUEUE_WAKEUP);
|
||||
}
|
||||
|
||||
static inline void hmx_queue_suspend(struct hmx_queue *q) {
|
||||
static inline void hmx_queue_suspend(hmx_queue_t q) {
|
||||
hmx_queue_signal(q, HMX_QUEUE_SUSPEND);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
#include "hmx-queue.h"
|
||||
#include "htp-ops.h"
|
||||
#include "hex-profile.h"
|
||||
#include "worker-pool.h"
|
||||
#include "work-queue.h"
|
||||
#include "hex-fastdiv.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dspqueue.h>
|
||||
@@ -52,6 +53,9 @@ struct htp_ops_context {
|
||||
const struct htp_tensor * dsts[HTP_OP_MAX_OUTPUTS];
|
||||
};
|
||||
|
||||
dma_queue ** src_dma[HTP_OP_MAX_INPUTS];
|
||||
dma_queue ** dst_dma[HTP_OP_MAX_OUTPUTS];
|
||||
|
||||
// TODO convert these to an array
|
||||
struct htp_spad src0_spad;
|
||||
struct htp_spad src1_spad;
|
||||
@@ -65,11 +69,16 @@ struct htp_ops_context {
|
||||
|
||||
// Main context for htp DSP backend
|
||||
struct htp_context {
|
||||
dspqueue_t queue;
|
||||
dma_queue * dma[HTP_MAX_NTHREADS];
|
||||
dspqueue_t dsp_queue;
|
||||
|
||||
struct htp_mmap mmap[HTP_MAX_MMAPS];
|
||||
worker_pool_context_t worker_pool;
|
||||
dma_queue_t dma[HTP_MAX_NTHREADS];
|
||||
dma_queue_t dma_cached[HTP_MAX_NTHREADS];
|
||||
work_queue_t work_queue;
|
||||
hmx_queue_t hmx_queue;
|
||||
|
||||
uint32_t n_threads;
|
||||
struct fastdiv_values n_threads_div;
|
||||
|
||||
int thread_id;
|
||||
int thread_prio;
|
||||
@@ -86,6 +95,7 @@ struct htp_context {
|
||||
atomic_bool vtcm_needs_release;
|
||||
|
||||
uint64_t max_vmem;
|
||||
uint32_t dirty_map[HTP_OP_MAX_TENSORS / 32];
|
||||
|
||||
// Persistent DDR scratchpad for MUL_MAT_ID mappings
|
||||
void * ddr_spad_base;
|
||||
@@ -93,7 +103,10 @@ struct htp_context {
|
||||
|
||||
struct htp_ops_context octx;
|
||||
|
||||
struct hmx_queue * hmx_queue; // Async HMX queue for pipeline overlap
|
||||
qurt_thread_t main_thread;
|
||||
void * main_stack;
|
||||
atomic_bool killed;
|
||||
size_t footprint;
|
||||
};
|
||||
|
||||
int op_matmul(struct htp_ops_context * octx);
|
||||
|
||||
@@ -97,6 +97,7 @@ enum htp_op_code {
|
||||
HTP_OP_PAD,
|
||||
HTP_OP_NORM,
|
||||
HTP_OP_CONCAT,
|
||||
HTP_OP_CLAMP,
|
||||
|
||||
HTP_OP_INVALID
|
||||
};
|
||||
@@ -108,8 +109,7 @@ enum htp_op_code {
|
||||
#define HTP_OP_MAX_KERN_PARAMS 32
|
||||
|
||||
#define HTP_OP_MAX_BUFS 16
|
||||
#define HTP_OP_MAX_REQS 256
|
||||
#define HTP_OP_MAX_TENSORS (HTP_OP_MAX_REQS * HTP_OP_MAX_INPUTS + HTP_OP_MAX_REQS)
|
||||
#define HTP_OP_MAX_TENSORS 8192 // must stay under 64K (uint16)
|
||||
|
||||
#define HTP_OP_MAX_VMEM_DEFAULT (3355443200u)
|
||||
|
||||
@@ -117,16 +117,18 @@ enum htp_op_code {
|
||||
|
||||
enum htp_tensor_flags {
|
||||
HTP_TENSOR_COMPUTE = (1U << 0), // Tensor buffer temporal compute data (not weights)
|
||||
HTP_TENSOR_FLUSHED = (1U << 1) // Tensor buffer has been flushed (set by the NPU)
|
||||
HTP_TENSOR_DIRTY = (1U << 1) // Tensor buffer is dirty and needs to be flushed
|
||||
};
|
||||
|
||||
// Tensor descriptor
|
||||
struct htp_tensor {
|
||||
uint32_t data; // Buffer offset in the messages, and data pointer on the NPU
|
||||
uint32_t alias; // Index of the canonical tensor for this memory buffer
|
||||
uint32_t size; // Data size in bytes
|
||||
uint32_t flags; // Buffer / tensor flags
|
||||
uint16_t type; // Data type
|
||||
uint32_t type; // Data type
|
||||
uint16_t bi; // Buffer index
|
||||
uint16_t ti; // Tensor index
|
||||
uint32_t ne[HTP_OP_MAX_DIMS]; // Number of elements
|
||||
uint32_t nb[HTP_OP_MAX_DIMS]; // Stride in bytes (see ggml.h ggml_tensor)
|
||||
};
|
||||
@@ -169,6 +171,8 @@ enum htp_profiler_mode {
|
||||
|
||||
enum htp_trace_event_id {
|
||||
HTP_TRACE_EVT_DMA = 0,
|
||||
HTP_TRACE_EVT_L2FLUSH = 1,
|
||||
HTP_TRACE_EVT_INIT = 2,
|
||||
|
||||
HTP_TRACE_EVT_HVX_COMP = 20,
|
||||
HTP_TRACE_EVT_HVX_A_QUANT = 21,
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
#include "htp-tensor.h"
|
||||
|
||||
#include <qurt.h>
|
||||
#include <qurt_memory.h>
|
||||
|
||||
#include "hex-common.h"
|
||||
#include "hex-utils.h"
|
||||
#include "hex-fastdiv.h"
|
||||
#include "hex-profile.h"
|
||||
#include "htp-ctx.h"
|
||||
#include "work-queue.h"
|
||||
|
||||
struct l2flush_task {
|
||||
struct htp_thread_trace * trace;
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
uint32_t chunk_size;
|
||||
uint32_t ti;
|
||||
};
|
||||
|
||||
static void l2flush_thread_worker(unsigned int n, unsigned int i, void * data) {
|
||||
struct l2flush_task * task = (struct l2flush_task *) data;
|
||||
const uint32_t start = task->start;
|
||||
const uint32_t end = task->end;
|
||||
const uint32_t ti = task->ti;
|
||||
const uint32_t chunk_size = task->chunk_size;
|
||||
|
||||
const uint32_t thread_s = start + i * chunk_size;
|
||||
if (thread_s >= end) {
|
||||
return;
|
||||
}
|
||||
uint32_t thread_e = thread_s + chunk_size;
|
||||
if (thread_e > end) {
|
||||
thread_e = end;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = &task->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_L2FLUSH, ti);
|
||||
hex_l2flush((void *) (uintptr_t) thread_s, thread_e - thread_s);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_L2FLUSH, ti);
|
||||
}
|
||||
|
||||
static void flush_all_dcache(struct htp_context * ctx) {
|
||||
struct htp_thread_trace * tr = &ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_L2FLUSH, 0);
|
||||
qurt_mem_cache_clean((qurt_addr_t) 0, 0, QURT_MEM_CACHE_FLUSH_INVALIDATE_ALL, QURT_MEM_DCACHE);
|
||||
hex_l2fetch_block(ctx, ctx->footprint);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_L2FLUSH, 0);
|
||||
bitmap_reset(ctx->dirty_map, HTP_OP_MAX_TENSORS);
|
||||
}
|
||||
|
||||
static void flush_tensor_range(struct htp_context * ctx, const struct htp_tensor * t) {
|
||||
struct htp_thread_trace * tr = &ctx->trace[0];
|
||||
|
||||
if (t->size > HEX_L2_FLUSH_WQ_THRESHOLD && ctx->n_threads > 1) {
|
||||
struct l2flush_task task;
|
||||
task.start = hex_align_down((size_t) t->data, HEX_L2_LINE_SIZE);
|
||||
task.end = hex_align_up((size_t) t->data + t->size, HEX_L2_LINE_SIZE);
|
||||
task.ti = t->ti;
|
||||
task.trace = ctx->trace;
|
||||
|
||||
const uint32_t total_size = task.end - task.start;
|
||||
const uint32_t n_blocks = (total_size + HEX_L2_BLOCK_SIZE - 1) / HEX_L2_BLOCK_SIZE;
|
||||
const uint32_t blocks_per_thread = fastdiv(n_blocks + ctx->n_threads - 1, &ctx->n_threads_div);
|
||||
task.chunk_size = blocks_per_thread * HEX_L2_BLOCK_SIZE;
|
||||
|
||||
work_queue_run(ctx->work_queue, l2flush_thread_worker, &task, ctx->n_threads);
|
||||
} else {
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_L2FLUSH, t->ti);
|
||||
hex_l2flush((void *) t->data, t->size);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_L2FLUSH, t->ti);
|
||||
}
|
||||
|
||||
htp_tensor_make_clean(t, ctx->dirty_map);
|
||||
}
|
||||
|
||||
void htp_tensor_flush(struct htp_context * ctx, const struct htp_tensor * t) {
|
||||
if (!bitmap_test(ctx->dirty_map, t->ti)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (t->size > HEX_L2_FLUSH_ALL_THRESHOLD) {
|
||||
flush_all_dcache(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
flush_tensor_range(ctx, t);
|
||||
}
|
||||
|
||||
// One dirty tensor's line-aligned range, placed in the flattened global block space.
|
||||
struct l2flush_range {
|
||||
uint32_t start; // line-aligned start address
|
||||
uint32_t end; // line-aligned end address
|
||||
uint32_t block_first; // global block index of this range's first block
|
||||
uint32_t n_blocks; // number of HEX_L2_BLOCK_SIZE chunks (last may be partial)
|
||||
};
|
||||
|
||||
struct l2flush_multi_task {
|
||||
struct htp_thread_trace * trace;
|
||||
struct l2flush_range ranges[HTP_OP_MAX_INPUTS];
|
||||
uint32_t n_ranges;
|
||||
uint32_t total_blocks;
|
||||
uint32_t blocks_per_thread;
|
||||
};
|
||||
|
||||
static void l2flush_multi_worker(unsigned int n, unsigned int i, void * data) {
|
||||
(void) n;
|
||||
struct l2flush_multi_task * task = (struct l2flush_multi_task *) data;
|
||||
|
||||
const uint32_t gb_first = i * task->blocks_per_thread;
|
||||
uint32_t gb_last = gb_first + task->blocks_per_thread;
|
||||
if (gb_last > task->total_blocks) {
|
||||
gb_last = task->total_blocks;
|
||||
}
|
||||
if (gb_first >= gb_last) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = &task->trace[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_L2FLUSH, gb_first);
|
||||
|
||||
for (uint32_t r = 0; r < task->n_ranges; r++) {
|
||||
const struct l2flush_range * rg = &task->ranges[r];
|
||||
const uint32_t rb_first = rg->block_first;
|
||||
const uint32_t rb_last = rg->block_first + rg->n_blocks;
|
||||
|
||||
const uint32_t lo = gb_first > rb_first ? gb_first : rb_first;
|
||||
const uint32_t hi = gb_last < rb_last ? gb_last : rb_last;
|
||||
if (lo >= hi) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint32_t s = rg->start + (lo - rb_first) * HEX_L2_BLOCK_SIZE;
|
||||
uint32_t e = rg->start + (hi - rb_first) * HEX_L2_BLOCK_SIZE;
|
||||
if (e > rg->end) {
|
||||
e = rg->end;
|
||||
}
|
||||
hex_l2flush((void *) (uintptr_t) s, e - s);
|
||||
}
|
||||
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_L2FLUSH, gb_first);
|
||||
}
|
||||
|
||||
void htp_tensor_flush_all(struct htp_context * ctx, const struct htp_tensor * const * tensors, uint32_t n) {
|
||||
uint64_t total_dirty = 0;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
const struct htp_tensor * t = tensors[i];
|
||||
if (t && bitmap_test(ctx->dirty_map, t->ti)) {
|
||||
total_dirty += t->size;
|
||||
}
|
||||
}
|
||||
|
||||
if (total_dirty == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (total_dirty > HEX_L2_FLUSH_ALL_THRESHOLD) {
|
||||
flush_all_dcache(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
// Aggregate is small enough to walk. Thread it across all dirty ranges at once
|
||||
// when it is worth the dispatch, otherwise flush sequentially.
|
||||
if (total_dirty > HEX_L2_FLUSH_WQ_THRESHOLD && ctx->n_threads > 1) {
|
||||
struct l2flush_multi_task task;
|
||||
task.trace = ctx->trace;
|
||||
task.n_ranges = 0;
|
||||
|
||||
uint32_t block_acc = 0;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
const struct htp_tensor * t = tensors[i];
|
||||
if (!t || !bitmap_test(ctx->dirty_map, t->ti)) {
|
||||
continue;
|
||||
}
|
||||
// Clear as we go: dedups a tensor passed as multiple srcs (e.g. mul(x,x)).
|
||||
htp_tensor_make_clean(t, ctx->dirty_map);
|
||||
|
||||
struct l2flush_range * rg = &task.ranges[task.n_ranges++];
|
||||
rg->start = hex_align_down((size_t) t->data, HEX_L2_LINE_SIZE);
|
||||
rg->end = hex_align_up((size_t) t->data + t->size, HEX_L2_LINE_SIZE);
|
||||
rg->block_first = block_acc;
|
||||
rg->n_blocks = (rg->end - rg->start + HEX_L2_BLOCK_SIZE - 1) / HEX_L2_BLOCK_SIZE;
|
||||
block_acc += rg->n_blocks;
|
||||
}
|
||||
|
||||
task.total_blocks = block_acc;
|
||||
task.blocks_per_thread = fastdiv(block_acc + ctx->n_threads - 1, &ctx->n_threads_div);
|
||||
|
||||
work_queue_run(ctx->work_queue, l2flush_multi_worker, &task, ctx->n_threads);
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = &ctx->trace[0];
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
const struct htp_tensor * t = tensors[i];
|
||||
if (!t || !bitmap_test(ctx->dirty_map, t->ti)) {
|
||||
continue;
|
||||
}
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_L2FLUSH, t->ti);
|
||||
hex_l2flush((void *) t->data, t->size);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_L2FLUSH, t->ti);
|
||||
htp_tensor_make_clean(t, ctx->dirty_map);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#ifndef HTP_TENSOR_H
|
||||
#define HTP_TENSOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "htp-ops.h"
|
||||
#include "hex-bitmap.h"
|
||||
|
||||
static inline struct htp_tensor * htp_tensor_alias(const struct htp_tensor * t) {
|
||||
return (struct htp_tensor *) (uintptr_t) t->alias;
|
||||
}
|
||||
|
||||
static inline void * htp_tensor_data(const struct htp_tensor * t) {
|
||||
return (void *) (uintptr_t) t->data;
|
||||
}
|
||||
|
||||
static inline uint32_t * htp_tensor_flags(const struct htp_tensor * t) {
|
||||
return (uint32_t *) &t->flags;
|
||||
}
|
||||
|
||||
static inline void htp_tensor_make_dirty(const struct htp_tensor * t, uint32_t * dirty_map) {
|
||||
struct htp_tensor * curr = (struct htp_tensor *) t;
|
||||
do {
|
||||
bitmap_set(dirty_map, curr->ti);
|
||||
curr = htp_tensor_alias(curr);
|
||||
} while (curr != t);
|
||||
}
|
||||
|
||||
static inline void htp_tensor_make_clean(const struct htp_tensor * t, uint32_t * dirty_map) {
|
||||
bitmap_clear(dirty_map, t->ti);
|
||||
}
|
||||
|
||||
struct htp_context;
|
||||
void htp_tensor_flush(struct htp_context * ctx, const struct htp_tensor * t);
|
||||
void htp_tensor_flush_all(struct htp_context * ctx, const struct htp_tensor * const * tensors, uint32_t n);
|
||||
|
||||
#endif // HTP_TENSOR_H
|
||||
+485
-327
File diff suppressed because it is too large
Load Diff
@@ -92,10 +92,10 @@ struct htp_mm_context {
|
||||
// Per thread quant tasks
|
||||
// Precomputed block-parallel quantization values
|
||||
worker_callback_t quant_task_func;
|
||||
uint32_t quant_ib_first[MAX_NUM_WORKERS];
|
||||
uint32_t quant_ib_last[MAX_NUM_WORKERS];
|
||||
uint32_t quant_r[MAX_NUM_WORKERS];
|
||||
uint32_t quant_c[MAX_NUM_WORKERS];
|
||||
uint32_t quant_ib_first[WORK_QUEUE_MAX_N_THREADS];
|
||||
uint32_t quant_ib_last[WORK_QUEUE_MAX_N_THREADS];
|
||||
uint32_t quant_r[WORK_QUEUE_MAX_N_THREADS];
|
||||
uint32_t quant_c[WORK_QUEUE_MAX_N_THREADS];
|
||||
uint32_t n_quant_tasks;
|
||||
uint32_t n_quant_rows_per_thread;
|
||||
atomic_uint quant_barrier;
|
||||
@@ -254,7 +254,7 @@ static void hvx_mm_4d(unsigned int nth, unsigned int ith, void * data) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_COMP, ir0_start);
|
||||
|
||||
const uint32_t blck_0 = 64;
|
||||
@@ -309,7 +309,7 @@ static void hvx_mm_2d_repacked_##SUFFIX(unsigned int nth, unsigned int ith, void
|
||||
const uint32_t src0_start_row = src0_nrows_per_thread * ith; \
|
||||
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, src0_nrows); \
|
||||
\
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
\
|
||||
const struct htp_mm_kernel_params * kparams = (const struct htp_mm_kernel_params *) octx->kernel_params; \
|
||||
const uint32_t n_prefetch = kparams->n_prefetch; \
|
||||
@@ -410,7 +410,7 @@ static void hvx_mv_2d_repacked_##SUFFIX(unsigned int nth, unsigned int ith, void
|
||||
const uint32_t src0_start_row = src0_nrows_per_thread * ith; \
|
||||
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, src0_nrows); \
|
||||
\
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
\
|
||||
const struct htp_mm_kernel_params * kparams = (const struct htp_mm_kernel_params *) octx->kernel_params; \
|
||||
const uint32_t n_prefetch = kparams->n_prefetch; \
|
||||
@@ -523,7 +523,7 @@ static void hvx_mm_qkv_2d_repacked_##SUFFIX(unsigned int nth, unsigned int ith,
|
||||
uint8_t * restrict vtcm_src3_ptr = mmctx->vtcm_src3 + mmctx->vtcm_src3_size_per_thread * ith; \
|
||||
uint8_t * restrict src1_data = mmctx->vtcm_src1; \
|
||||
\
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
\
|
||||
const struct htp_mm_kernel_params * kparams = (const struct htp_mm_kernel_params *) octx->kernel_params; \
|
||||
const uint32_t n_prefetch = kparams->n_prefetch; \
|
||||
@@ -699,7 +699,7 @@ static void hvx_mm_ffn_2d_repacked_##SUFFIX(unsigned int nth, unsigned int ith,
|
||||
uint8_t * restrict vtcm_src2_ptr = mmctx->vtcm_src2 + mmctx->vtcm_src2_size_per_thread * ith; \
|
||||
uint8_t * restrict src1_data = mmctx->vtcm_src1; \
|
||||
\
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
\
|
||||
const uint8_t * restrict src0_row = (const uint8_t *) src0->data; \
|
||||
const uint8_t * restrict src2_row = (const uint8_t *) src2->data; \
|
||||
@@ -820,7 +820,7 @@ static void name(unsigned int nth, unsigned int ith, void * data) {
|
||||
return; \
|
||||
} \
|
||||
\
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_QUANT, ir_first); \
|
||||
\
|
||||
uint8_t * restrict dst = mmctx->vtcm_src1; \
|
||||
@@ -846,7 +846,7 @@ QUANTIZE_IMPL(quantize_f16_f16_flat, "quantize-f16-f16", quantize_f16_f
|
||||
static void quantize_f32_q8_0_tiled_block(unsigned int nth, unsigned int ith, void * data) {
|
||||
struct htp_mm_context * mmctx = data;
|
||||
struct htp_ops_context * octx = mmctx->octx;
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_QUANT, mmctx->quant_ib_first[ith]);
|
||||
|
||||
const struct htp_tensor * src = octx->src[1];
|
||||
@@ -870,7 +870,7 @@ static void quantize_f32_q8_0_tiled_block(unsigned int nth, unsigned int ith, vo
|
||||
static void quantize_f32_q8_1_tiled_block(unsigned int nth, unsigned int ith, void * data) {
|
||||
struct htp_mm_context * mmctx = data;
|
||||
struct htp_ops_context * octx = mmctx->octx;
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_QUANT, mmctx->quant_ib_first[ith]);
|
||||
|
||||
const struct htp_tensor * src = octx->src[1];
|
||||
@@ -944,7 +944,7 @@ static void hvx_mm_2d(unsigned int nth, unsigned int ith, void * data) {
|
||||
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, src0_nrows);
|
||||
const uint32_t src0_end_row_x2 = src0_start_row + ((src0_end_row - src0_start_row) & ~1U);
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
const size_t dst_row_size = nb1;
|
||||
const size_t src0_row_size = nb01;
|
||||
@@ -1040,7 +1040,7 @@ static void hvx_mv_2d(unsigned int nth, unsigned int ith, void * data) {
|
||||
const uint32_t src0_start_row = src0_nrows_per_thread * ith;
|
||||
const uint32_t src0_end_row = MIN(src0_start_row + src0_nrows_per_thread, src0_nrows);
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
const size_t dst_row_size = nb1;
|
||||
const size_t src0_row_size = nb01;
|
||||
@@ -1155,7 +1155,7 @@ static void hvx_mm_id(unsigned int nth, unsigned int ith, void * data) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
const struct htp_mm_kernel_params * kparams = (const struct htp_mm_kernel_params *) octx->kernel_params;
|
||||
const uint32_t n_prefetch = kparams->n_prefetch;
|
||||
@@ -1244,7 +1244,7 @@ static void hvx_mv_id(unsigned int nth, unsigned int ith, void * data) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL;
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith];
|
||||
|
||||
const struct htp_mm_kernel_params * kparams = (const struct htp_mm_kernel_params *) octx->kernel_params;
|
||||
const uint32_t n_prefetch = kparams->n_prefetch;
|
||||
@@ -1338,6 +1338,9 @@ static int hvx_mm_init_vec_dot(struct htp_mm_context * mmctx, enum htp_data_type
|
||||
static int hvx_mm_matmul(struct htp_ops_context * octx) {
|
||||
htp_matmul_tensors_preamble;
|
||||
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
struct htp_mm_context mmctx_struct = {0};
|
||||
struct htp_mm_context * mmctx = &mmctx_struct;
|
||||
mmctx->octx = octx;
|
||||
@@ -1557,9 +1560,6 @@ static int hvx_mm_matmul(struct htp_ops_context * octx) {
|
||||
mmctx->vtcm_src0_stride = src0_row_size_padded;
|
||||
mmctx->vtcm_src1_stride = src1_row_size;
|
||||
|
||||
if (octx->flags & HTP_OPFLAGS_SKIP_COMPUTE)
|
||||
return HTP_STATUS_OK;
|
||||
|
||||
if (need_quant) {
|
||||
mmctx->n_quant_rows_per_thread = (src1_nrows + n_quant_tasks - 1) / n_quant_tasks;
|
||||
mmctx->quant_task_func = quant_task_func;
|
||||
@@ -1570,8 +1570,9 @@ static int hvx_mm_matmul(struct htp_ops_context * octx) {
|
||||
mmctx->n_quant_tasks = 0;
|
||||
}
|
||||
|
||||
const uint32_t n_matmul_jobs = octx->n_threads;
|
||||
worker_pool_run_func(octx->ctx->worker_pool, matmul_job_func, mmctx, n_matmul_jobs);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
worker_pool_run_func(octx->ctx->worker_pool, matmul_job_func, mmctx, octx->n_threads);
|
||||
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
@@ -1874,7 +1875,7 @@ static void hvx_mm_ffn_2d(unsigned int nth, unsigned int ith, void * data) {
|
||||
#define DEQUANTIZE_WORKER_LOOP_IMPL(SUFFIX) \
|
||||
static void dequantize_tiled_worker_loop_##SUFFIX(unsigned int n, unsigned int i, void *data) { \
|
||||
tiled_dequantize_state_t *state = (tiled_dequantize_state_t *)data; \
|
||||
struct htp_thread_trace * tr = state->traces ? &state->traces[i] : NULL; \
|
||||
struct htp_thread_trace * tr = &state->traces[i]; \
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_W_DEQUANT, i); \
|
||||
for (unsigned int task_id = i; task_id < (unsigned int)state->n_tasks; task_id += n) { \
|
||||
int start = task_id * state->n_tiles_per_task; \
|
||||
@@ -1892,7 +1893,7 @@ DEQUANTIZE_WORKER_LOOP_IMPL(q8_0)
|
||||
|
||||
static void convert_f16_worker_loop(unsigned int n, unsigned int i, void *data) {
|
||||
tiled_dequantize_state_t *state = (tiled_dequantize_state_t *)data;
|
||||
struct htp_thread_trace * tr = state->traces ? &state->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &state->traces[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_W_DEQUANT, i);
|
||||
for (unsigned int task_id = i; task_id < (unsigned int)state->n_tasks; task_id += n) {
|
||||
int start = task_id * state->n_tiles_per_task;
|
||||
@@ -1905,7 +1906,7 @@ static void convert_f16_worker_loop(unsigned int n, unsigned int i, void *data)
|
||||
static void quantize_f32_worker_loop(unsigned int n, unsigned int i, void *data) {
|
||||
tiled_dequantize_state_t *state = (tiled_dequantize_state_t *)data;
|
||||
|
||||
struct htp_thread_trace * tr = state->traces ? &state->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &state->traces[i];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_QUANT, i);
|
||||
|
||||
for (unsigned int task_id = i; task_id < (unsigned int)state->n_tasks; task_id += n) {
|
||||
@@ -1920,7 +1921,7 @@ static void quantize_f32_worker_loop(unsigned int n, unsigned int i, void *data)
|
||||
static void transfer_output_chunk_worker_fn(unsigned int n, unsigned int i, void *data) {
|
||||
output_transfer_task_state_t *st = (output_transfer_task_state_t *) data;
|
||||
|
||||
struct htp_thread_trace * tr = st->traces ? &st->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &st->traces[i];
|
||||
|
||||
int start_chunk_idx = i * st->n_chunks_per_task;
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_O_PROC, start_chunk_idx);
|
||||
@@ -1955,6 +1956,170 @@ typedef struct {
|
||||
uint32_t dma_step_rows_shift;
|
||||
} activation_transfer_task_state_t;
|
||||
|
||||
typedef struct {
|
||||
__fp16 *dst;
|
||||
const float *src;
|
||||
uint32_t n_rows;
|
||||
uint32_t k_block;
|
||||
uint32_t k_stride;
|
||||
uint32_t k_valid;
|
||||
uint32_t n_col_chunks;
|
||||
struct fastdiv_values n_threads_div;
|
||||
float *vtcm_f32_act;
|
||||
size_t vtcm_f32_act_bytes;
|
||||
struct htp_thread_trace *traces;
|
||||
struct htp_context *ctx;
|
||||
uint32_t dma_step_rows;
|
||||
uint32_t dma_step_rows_shift;
|
||||
} activation_transfer_col_chunk_state_t;
|
||||
|
||||
static void transfer_activation_chunk_fp32_to_fp16_dma_pipelined_col_chunk(
|
||||
dma_queue *dma_q,
|
||||
__fp16 *restrict vtcm_dst,
|
||||
const float *restrict src,
|
||||
uint32_t n_rows,
|
||||
uint32_t k_block,
|
||||
uint32_t k_stride,
|
||||
uint32_t k_chunk_valid,
|
||||
uint32_t c_first,
|
||||
uint32_t c_len,
|
||||
float *thread_f32_act,
|
||||
struct htp_thread_trace *tr,
|
||||
uint32_t dma_step_rows,
|
||||
uint32_t dma_step_rows_shift) {
|
||||
|
||||
const uint32_t R = dma_step_rows;
|
||||
const uint32_t n_rows_padded = hex_align_up(n_rows, HTP_MM_HMX_TILE_N_ROWS);
|
||||
|
||||
const uint32_t n_steps = n_rows_padded >> dma_step_rows_shift;
|
||||
|
||||
// Push step 0
|
||||
if (n_steps > 0 && n_rows > 0) {
|
||||
uint32_t nrows_to_fetch = hex_smin(n_rows, R);
|
||||
dma_queue_push(dma_q, dma_make_ptr(thread_f32_act, src + c_first),
|
||||
c_len * sizeof(float), k_stride * sizeof(float), k_chunk_valid * sizeof(float), nrows_to_fetch);
|
||||
}
|
||||
// Push step 1
|
||||
if (n_steps > 1) {
|
||||
uint32_t next_r = R * 1;
|
||||
if (next_r < n_rows) {
|
||||
uint32_t nrows_to_fetch = hex_smin(n_rows - next_r, R);
|
||||
const float *next_src = src + next_r * k_stride + c_first;
|
||||
float *next_buf = thread_f32_act + 1 * R * c_len;
|
||||
dma_queue_push(dma_q, dma_make_ptr(next_buf, next_src),
|
||||
c_len * sizeof(float), k_stride * sizeof(float), k_chunk_valid * sizeof(float), nrows_to_fetch);
|
||||
}
|
||||
}
|
||||
for (uint32_t s = 0; s < n_steps; ++s) {
|
||||
uint32_t r = s << dma_step_rows_shift;
|
||||
float *curr_buf = thread_f32_act;
|
||||
|
||||
if (r < n_rows) {
|
||||
curr_buf = (float *) dma_queue_pop(dma_q).dst;
|
||||
}
|
||||
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_PREP, r);
|
||||
for (uint32_t p = 0; p < (R >> 1); ++p) {
|
||||
uint32_t row_idx = r + (p << 1);
|
||||
float *pair_buf = curr_buf + (p << 1) * c_len;
|
||||
bool r0_valid = ((row_idx + 0) < n_rows);
|
||||
bool r1_valid = ((row_idx + 1) < n_rows);
|
||||
|
||||
transfer_activation_row_pair_fp32_to_fp16_col_chunk(
|
||||
vtcm_dst, pair_buf, pair_buf + c_len, row_idx, k_block, c_first, c_len, k_chunk_valid, r0_valid, r1_valid
|
||||
);
|
||||
}
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_A_PREP, r);
|
||||
|
||||
// Push step s + 2
|
||||
uint32_t next_s = s + 2;
|
||||
uint32_t next_r = next_s << dma_step_rows_shift;
|
||||
if (next_r < n_rows) {
|
||||
uint32_t nrows_to_fetch = hex_smin(n_rows - next_r, R);
|
||||
const float *next_src = src + next_r * k_stride + c_first;
|
||||
dma_queue_push(dma_q, dma_make_ptr(curr_buf, next_src),
|
||||
c_len * sizeof(float), k_stride * sizeof(float), k_chunk_valid * sizeof(float), nrows_to_fetch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_activation_chunk_fp32_to_fp16_col_chunk(
|
||||
__fp16 *restrict vtcm_dst,
|
||||
const float *restrict src,
|
||||
uint32_t n_rows,
|
||||
uint32_t k_block,
|
||||
uint32_t k_stride,
|
||||
uint32_t c_first,
|
||||
uint32_t c_len,
|
||||
uint32_t k_chunk_valid) {
|
||||
const uint32_t n_rows_padded = hex_align_up(n_rows, HTP_MM_HMX_TILE_N_ROWS);
|
||||
const uint32_t n_rows_tiled = (n_rows / HTP_MM_HMX_TILE_N_ROWS) * HTP_MM_HMX_TILE_N_ROWS;
|
||||
|
||||
uint32_t r = 0;
|
||||
|
||||
#pragma unroll(2)
|
||||
for (r = 0; r < n_rows_tiled; r += 2) {
|
||||
const float *ptr_in0 = src + (r + 0) * k_stride + c_first;
|
||||
const float *ptr_in1 = src + (r + 1) * k_stride + c_first;
|
||||
|
||||
transfer_activation_row_pair_fp32_to_fp16_col_chunk(
|
||||
vtcm_dst, ptr_in0, ptr_in1, r, k_block, c_first, c_len, k_chunk_valid, true, true
|
||||
);
|
||||
}
|
||||
|
||||
for (; r < n_rows_padded; r += 2) {
|
||||
const bool row0_valid = r < n_rows;
|
||||
const bool row1_valid = (r + 1) < n_rows;
|
||||
|
||||
const float *ptr_in0 = row0_valid ? (src + (r + 0) * k_stride + c_first) : NULL;
|
||||
const float *ptr_in1 = row1_valid ? (src + (r + 1) * k_stride + c_first) : NULL;
|
||||
|
||||
transfer_activation_row_pair_fp32_to_fp16_col_chunk(
|
||||
vtcm_dst, ptr_in0, ptr_in1, r, k_block, c_first, c_len, k_chunk_valid, row0_valid, row1_valid
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_activation_chunk_col_chunk_worker_fn(unsigned int n, unsigned int i, void *data) {
|
||||
activation_transfer_col_chunk_state_t *st = (activation_transfer_col_chunk_state_t *) data;
|
||||
struct htp_thread_trace * tr = &st->traces[i];
|
||||
|
||||
uint32_t n_blocks = st->k_block / 32;
|
||||
uint32_t b_first = fastdiv(n_blocks * i, &st->n_threads_div);
|
||||
uint32_t b_last = fastdiv(n_blocks * (i + 1), &st->n_threads_div);
|
||||
uint32_t c_first = b_first * 32;
|
||||
uint32_t c_last = b_last * 32;
|
||||
uint32_t c_len = c_last - c_first;
|
||||
|
||||
if (c_len == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t k_chunk_valid = 0;
|
||||
if (st->k_valid > c_first) {
|
||||
k_chunk_valid = hex_smin(st->k_valid, c_last) - c_first;
|
||||
}
|
||||
|
||||
__fp16 *dst = st->dst;
|
||||
const float *src = st->src;
|
||||
|
||||
if (st->vtcm_f32_act) {
|
||||
size_t thread_scratch_bytes = hex_align_down(fastdiv(st->vtcm_f32_act_bytes, &st->n_threads_div), 128);
|
||||
float *thread_f32_act = (float *)((char *)st->vtcm_f32_act + i * thread_scratch_bytes);
|
||||
|
||||
transfer_activation_chunk_fp32_to_fp16_dma_pipelined_col_chunk(
|
||||
st->ctx->dma[i], dst, src, st->n_rows, st->k_block, st->k_stride, k_chunk_valid,
|
||||
c_first, c_len, thread_f32_act, tr, st->dma_step_rows, st->dma_step_rows_shift
|
||||
);
|
||||
} else {
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_PREP, c_first);
|
||||
transfer_activation_chunk_fp32_to_fp16_col_chunk(
|
||||
dst, src, st->n_rows, st->k_block, st->k_stride, c_first, c_len, k_chunk_valid
|
||||
);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_A_PREP, c_first);
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_activation_chunk_fp32_to_fp16_dma_pipelined(
|
||||
dma_queue *dma_q,
|
||||
__fp16 *restrict vtcm_dst,
|
||||
@@ -2024,7 +2189,7 @@ static void transfer_activation_chunk_fp32_to_fp16_dma_pipelined(
|
||||
static void transfer_activation_chunk_worker_fn(unsigned int n, unsigned int i, void *data) {
|
||||
activation_transfer_task_state_t *st = (activation_transfer_task_state_t *) data;
|
||||
|
||||
struct htp_thread_trace * tr = st->traces ? &st->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &st->traces[i];
|
||||
|
||||
for (unsigned int task_id = i; task_id < (unsigned int)st->n_tasks; task_id += n) {
|
||||
int chunk_idx = task_id * st->n_chunks_per_task;
|
||||
@@ -2085,15 +2250,16 @@ typedef struct {
|
||||
|
||||
static void transfer_activation_chunk_gathered_worker_fn(unsigned int n, unsigned int i, void *data) {
|
||||
activation_transfer_gathered_task_state_t *st = data;
|
||||
struct htp_thread_trace * tr = st->traces ? &st->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &st->traces[i];
|
||||
int chunk_idx = i;
|
||||
int chunk_size = st->n_chunks_per_task;
|
||||
int start_row = st->start_row + chunk_idx * chunk_size;
|
||||
int vtcm_start_row = chunk_idx * chunk_size;
|
||||
int start_row = st->start_row + vtcm_start_row;
|
||||
int n_rows = hex_smin(st->cne1 - start_row, chunk_size);
|
||||
if (n_rows > 0) {
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_PREP, chunk_idx);
|
||||
transfer_activation_chunk_fp32_to_fp16_gathered(
|
||||
st->dst, st->src, start_row, n_rows, st->k_block,
|
||||
st->dst, st->src, start_row, vtcm_start_row, n_rows, st->k_block,
|
||||
st->matrix_rows, st->cur_a, st->mapping_stride,
|
||||
st->ne11, &st->ne11_div, st->nb11, st->nb12, st->cne1, st->k_valid);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_A_PREP, chunk_idx);
|
||||
@@ -2102,15 +2268,16 @@ static void transfer_activation_chunk_gathered_worker_fn(unsigned int n, unsigne
|
||||
|
||||
static void transfer_activation_chunk_gathered_worker_flat_fn(unsigned int n, unsigned int i, void *data) {
|
||||
activation_transfer_gathered_task_state_t *st = data;
|
||||
struct htp_thread_trace * tr = st->traces ? &st->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &st->traces[i];
|
||||
int chunk_idx = i;
|
||||
int chunk_size = st->n_chunks_per_task;
|
||||
int start_row = st->start_row + chunk_idx * chunk_size;
|
||||
int vtcm_start_row = chunk_idx * chunk_size;
|
||||
int start_row = st->start_row + vtcm_start_row;
|
||||
int n_rows = hex_smin(st->cne1 - start_row, chunk_size);
|
||||
if (n_rows > 0) {
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_A_PREP, chunk_idx);
|
||||
transfer_activation_chunk_fp32_to_fp16_gathered_flat(
|
||||
st->dst, st->src, start_row, n_rows, st->k_block,
|
||||
st->dst, st->src, start_row, vtcm_start_row, n_rows, st->k_block,
|
||||
st->matrix_rows, st->cur_a, st->mapping_stride,
|
||||
st->nb12, st->cne1, st->k_valid);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_A_PREP, chunk_idx);
|
||||
@@ -2119,15 +2286,16 @@ static void transfer_activation_chunk_gathered_worker_flat_fn(unsigned int n, un
|
||||
|
||||
static void transfer_output_chunk_scattered_worker_fn(unsigned int n, unsigned int i, void *data) {
|
||||
output_transfer_scattered_task_state_t *st = data;
|
||||
struct htp_thread_trace * tr = st->traces ? &st->traces[i] : NULL;
|
||||
struct htp_thread_trace * tr = &st->traces[i];
|
||||
int chunk_idx = i;
|
||||
int chunk_size = st->n_chunks_per_task;
|
||||
int start_row = st->start_row + chunk_idx * chunk_size;
|
||||
int vtcm_start_row = chunk_idx * chunk_size;
|
||||
int start_row = st->start_row + vtcm_start_row;
|
||||
int n_rows = hex_smin(st->cne1 - start_row, chunk_size);
|
||||
if (n_rows > 0) {
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_HVX_O_PROC, chunk_idx);
|
||||
transfer_output_chunk_fp16_to_fp32_scattered(
|
||||
st->dst, st->vtcm_src, start_row, n_rows, st->n_cols,
|
||||
st->dst, st->vtcm_src, start_row, vtcm_start_row, n_rows, st->n_cols,
|
||||
st->matrix_rows, st->cur_a, st->mapping_stride,
|
||||
st->dst_nb1, st->dst_nb2, st->cne1);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_HVX_O_PROC, chunk_idx);
|
||||
@@ -2210,42 +2378,81 @@ static void transfer_output_chunk_threaded(struct htp_context *ctx, float *dst,
|
||||
}
|
||||
}
|
||||
|
||||
static void transfer_activation_chunk_threaded(
|
||||
struct htp_context *ctx,
|
||||
__fp16 *dst,
|
||||
const float *src,
|
||||
int n_rows,
|
||||
int k_block,
|
||||
int k_stride,
|
||||
int n_threads,
|
||||
int k_valid,
|
||||
float *vtcm_f32_act,
|
||||
size_t vtcm_f32_act_bytes) {
|
||||
struct activation_transfer_params {
|
||||
struct htp_context * ctx;
|
||||
__fp16 * dst;
|
||||
const float * src;
|
||||
int n_rows;
|
||||
int k_block;
|
||||
int k_stride;
|
||||
int n_threads;
|
||||
const struct fastdiv_values * act_threads_div;
|
||||
const struct fastdiv_values * k_div;
|
||||
int k_valid;
|
||||
float * vtcm_f32_act;
|
||||
size_t vtcm_f32_act_bytes;
|
||||
};
|
||||
|
||||
static void transfer_activation_chunk_threaded(const struct activation_transfer_params * params) {
|
||||
struct htp_context * ctx = params->ctx;
|
||||
__fp16 * dst = params->dst;
|
||||
const float * src = params->src;
|
||||
int n_rows = params->n_rows;
|
||||
int k_block = params->k_block;
|
||||
int k_stride = params->k_stride;
|
||||
int n_threads = params->n_threads;
|
||||
const struct fastdiv_values * act_threads_div = params->act_threads_div;
|
||||
const struct fastdiv_values * k_div = params->k_div;
|
||||
int k_valid = params->k_valid;
|
||||
float * vtcm_f32_act = params->vtcm_f32_act;
|
||||
size_t vtcm_f32_act_bytes = params->vtcm_f32_act_bytes;
|
||||
|
||||
if (n_rows <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t n_tasks = (n_rows + 31) >> 5;
|
||||
if (n_threads > 1 && k_block > 32 && n_tasks < (size_t) n_threads) {
|
||||
// Calculate step rows parameters for column-chunked dma pipelining
|
||||
uint32_t dma_step_rows = 2;
|
||||
uint32_t dma_step_rows_shift = 1;
|
||||
if (vtcm_f32_act && vtcm_f32_act_bytes > 0 && k_block > 0) {
|
||||
size_t thread_scratch_bytes = hex_align_down(fastdiv(vtcm_f32_act_bytes, act_threads_div), 128);
|
||||
size_t thread_scratch_elements = thread_scratch_bytes / sizeof(float);
|
||||
size_t dma_step_rows_max = fastdiv(thread_scratch_elements / 2, k_div);
|
||||
if (dma_step_rows_max >= 4) {
|
||||
dma_step_rows = 4;
|
||||
dma_step_rows_shift = 2;
|
||||
}
|
||||
}
|
||||
|
||||
activation_transfer_col_chunk_state_t col_state;
|
||||
col_state.dst = dst;
|
||||
col_state.src = src;
|
||||
col_state.n_rows = n_rows;
|
||||
col_state.k_block = k_block;
|
||||
col_state.k_stride = k_stride;
|
||||
col_state.k_valid = k_valid;
|
||||
col_state.n_col_chunks = n_threads;
|
||||
col_state.n_threads_div = *act_threads_div;
|
||||
col_state.vtcm_f32_act = vtcm_f32_act;
|
||||
col_state.vtcm_f32_act_bytes = vtcm_f32_act_bytes;
|
||||
col_state.traces = ctx->trace;
|
||||
col_state.ctx = ctx;
|
||||
col_state.dma_step_rows = dma_step_rows;
|
||||
col_state.dma_step_rows_shift = dma_step_rows_shift;
|
||||
|
||||
worker_pool_run_func(ctx->worker_pool, transfer_activation_chunk_col_chunk_worker_fn, &col_state, n_threads);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(k_block % HTP_MM_HMX_TILE_N_COLS == 0 && k_stride % HTP_MM_HMX_TILE_N_COLS == 0);
|
||||
|
||||
size_t n_tot_chunks = n_rows;
|
||||
size_t n_chunks_per_task = (n_threads == 1) ? n_tot_chunks : 32; // must be multiple of 32 to ensure correct destination address
|
||||
|
||||
uint32_t dma_step_rows = 2;
|
||||
uint32_t dma_step_rows_shift = 1;
|
||||
if (vtcm_f32_act && vtcm_f32_act_bytes > 0 && k_block > 0) {
|
||||
size_t thread_scratch_elements = vtcm_f32_act_bytes / (n_threads * sizeof(float));
|
||||
size_t dma_step_rows_max = (thread_scratch_elements / 2) / k_block;
|
||||
if (dma_step_rows_max >= 4) {
|
||||
dma_step_rows = 4;
|
||||
dma_step_rows_shift = 2;
|
||||
} else {
|
||||
dma_step_rows = 2;
|
||||
dma_step_rows_shift = 1;
|
||||
}
|
||||
}
|
||||
|
||||
activation_transfer_task_state_t state;
|
||||
state.n_tasks = (n_tot_chunks + n_chunks_per_task - 1) / n_chunks_per_task;
|
||||
state.n_tasks = (n_threads == 1) ? 1 : hmx_ceil_div(n_tot_chunks, 32);
|
||||
state.n_tot_chunks = n_tot_chunks;
|
||||
state.n_chunks_per_task = n_chunks_per_task;
|
||||
state.dst = dst;
|
||||
@@ -2258,7 +2465,18 @@ static void transfer_activation_chunk_threaded(
|
||||
state.vtcm_f32_act = vtcm_f32_act;
|
||||
|
||||
int active_threads = hex_smin(n_threads, (int)state.n_tasks);
|
||||
state.vtcm_f32_act_bytes_per_thread = (vtcm_f32_act_bytes / active_threads) & ~127u;
|
||||
state.vtcm_f32_act_bytes_per_thread = hex_align_down(vtcm_f32_act_bytes / active_threads, 128);
|
||||
|
||||
uint32_t dma_step_rows = 2;
|
||||
uint32_t dma_step_rows_shift = 1;
|
||||
if (vtcm_f32_act && state.vtcm_f32_act_bytes_per_thread > 0 && k_block > 0) {
|
||||
size_t thread_scratch_elements = state.vtcm_f32_act_bytes_per_thread / sizeof(float);
|
||||
size_t dma_step_rows_max = fastdiv(thread_scratch_elements / 2, k_div);
|
||||
if (dma_step_rows_max >= 4) {
|
||||
dma_step_rows = 4;
|
||||
dma_step_rows_shift = 2;
|
||||
}
|
||||
}
|
||||
state.dma_step_rows = dma_step_rows;
|
||||
state.dma_step_rows_shift = dma_step_rows_shift;
|
||||
|
||||
@@ -2321,9 +2539,14 @@ static int hmx_mm_2d_f32(struct htp_context *ctx,
|
||||
int pipeline,
|
||||
int n_threads,
|
||||
int act_threads,
|
||||
const struct fastdiv_values * act_threads_div,
|
||||
const struct fastdiv_values * k_div,
|
||||
int tile_size,
|
||||
int aligned_tile_size,
|
||||
int vtcm_size) {
|
||||
struct htp_thread_trace * tr = &ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
if (k % 32 != 0 || n % 32 != 0) { return -1; }
|
||||
if (!hex_is_aligned(dst, VLEN) || !hex_is_aligned(activation, VLEN)) { return -1; }
|
||||
|
||||
@@ -2393,6 +2616,8 @@ static int hmx_mm_2d_f32(struct htp_context *ctx,
|
||||
|
||||
int n_chunk_cnt = hmx_ceil_div(n, n_chunk_n_cols);
|
||||
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
if (pipeline) {
|
||||
// --- Asynchronous Pipelined Loop ---
|
||||
hmx_matmul_job_t job_slots[2]; // persistent double-buffered job descriptors
|
||||
@@ -2403,7 +2628,21 @@ static int hmx_mm_2d_f32(struct htp_context *ctx,
|
||||
void *vtcm_weight_bufs[2] = { vtcm_scratch0, vtcm_scratch1 };
|
||||
void *vtcm_output_bufs[2] = { vtcm_output, vtcm_scratch2 };
|
||||
|
||||
transfer_activation_chunk_threaded(ctx, vtcm_f16_act, activation + mr * act_stride, n_rows, k, act_stride, act_threads, k_valid, vtcm_f32_act, L.act_f32_bytes);
|
||||
struct activation_transfer_params act_params = {
|
||||
.ctx = ctx,
|
||||
.dst = vtcm_f16_act,
|
||||
.src = activation + mr * act_stride,
|
||||
.n_rows = (int) n_rows,
|
||||
.k_block = k,
|
||||
.k_stride = act_stride,
|
||||
.n_threads = act_threads,
|
||||
.act_threads_div = act_threads_div,
|
||||
.k_div = k_div,
|
||||
.k_valid = k_valid,
|
||||
.vtcm_f32_act = vtcm_f32_act,
|
||||
.vtcm_f32_act_bytes = L.act_f32_bytes,
|
||||
};
|
||||
transfer_activation_chunk_threaded(&act_params);
|
||||
|
||||
// Prologue: push A0 and optionally A1 (if n_chunk_cnt > 1)
|
||||
const size_t n_cols_A0 = hex_smin(n - 0 * n_chunk_n_cols, n_chunk_n_cols);
|
||||
@@ -2480,7 +2719,21 @@ static int hmx_mm_2d_f32(struct htp_context *ctx,
|
||||
for (size_t mr = 0; mr < m; mr += m_chunk_n_rows) {
|
||||
const size_t n_rows = hex_smin(m - mr, m_chunk_n_rows);
|
||||
|
||||
transfer_activation_chunk_threaded(ctx, vtcm_f16_act, activation + mr * act_stride, n_rows, k, act_stride, act_threads, k_valid, vtcm_f32_act, L.act_f32_bytes);
|
||||
struct activation_transfer_params act_params = {
|
||||
.ctx = ctx,
|
||||
.dst = vtcm_f16_act,
|
||||
.src = activation + mr * act_stride,
|
||||
.n_rows = (int) n_rows,
|
||||
.k_block = k,
|
||||
.k_stride = act_stride,
|
||||
.n_threads = act_threads,
|
||||
.act_threads_div = act_threads_div,
|
||||
.k_div = k_div,
|
||||
.k_valid = k_valid,
|
||||
.vtcm_f32_act = vtcm_f32_act,
|
||||
.vtcm_f32_act_bytes = L.act_f32_bytes,
|
||||
};
|
||||
transfer_activation_chunk_threaded(&act_params);
|
||||
|
||||
// A0: Pre-fetch the first weight chunk (nc = 0)
|
||||
if (n > 0) {
|
||||
@@ -2570,7 +2823,8 @@ static inline const float *hmx_mm_src2_batch_ptr(const hmx_mm_f16_f32_batched_pa
|
||||
|
||||
static int hmx_mm_f16_f32_batched_simple(struct htp_context *ctx,
|
||||
const hmx_mm_f16_f32_batched_params_t *params,
|
||||
int m_chunk, int n_chunk, int pipeline, int n_threads, int act_threads, int vtcm_size) {
|
||||
int m_chunk, int n_chunk, int pipeline, int n_threads, int act_threads, int vtcm_size,
|
||||
const struct fastdiv_values * act_threads_div, const struct fastdiv_values * k_div) {
|
||||
int ret = 0;
|
||||
for (int b3 = 0; b3 < params->ne13 && ret == 0; ++b3) {
|
||||
for (int b2 = 0; b2 < params->ne12 && ret == 0; ++b2) {
|
||||
@@ -2582,14 +2836,17 @@ static int hmx_mm_f16_f32_batched_simple(struct htp_context *ctx,
|
||||
params->act_stride, params->weight_stride * (int)sizeof(__fp16),
|
||||
HTP_TYPE_F16, params->k, params->dst_stride, params->src2_stride, params->n,
|
||||
m_chunk, n_chunk, pipeline, n_threads, act_threads,
|
||||
0, 0, vtcm_size);
|
||||
act_threads_div, k_div, 0, 0, vtcm_size);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int hmx_mm_f16_f32_batched(struct htp_context *ctx, const hmx_mm_f16_f32_batched_params_t *params,
|
||||
int m_chunk, int n_chunk, int pipeline, int n_threads, int act_threads, int vtcm_size) {
|
||||
int m_chunk, int n_chunk, int pipeline, int n_threads, int act_threads,
|
||||
const struct fastdiv_values * act_threads_div,
|
||||
const struct fastdiv_values * k_div,
|
||||
int vtcm_size) {
|
||||
if (params->act_stride < params->k || params->weight_stride < params->k || params->dst_stride < params->n) { return -1; }
|
||||
if (params->ne02 <= 0 || params->ne03 <= 0 || params->ne12 <= 0 || params->ne13 <= 0) { return -1; }
|
||||
if (params->ne12 % params->ne02 != 0 || params->ne13 % params->ne03 != 0) { return -1; }
|
||||
@@ -2604,9 +2861,12 @@ static int hmx_mm_f16_f32_batched(struct htp_context *ctx, const hmx_mm_f16_f32_
|
||||
// Grouped path is only valid if group_size > 1 and it fits within VTCM budget.
|
||||
bool run_grouped = (group_size > 1 && (size_t)vtcm_size <= vtcm_budget);
|
||||
if (!run_grouped) {
|
||||
return hmx_mm_f16_f32_batched_simple(ctx, params, m_chunk, n_chunk, pipeline, n_threads, act_threads, vtcm_size);
|
||||
return hmx_mm_f16_f32_batched_simple(ctx, params, m_chunk, n_chunk, pipeline, n_threads, act_threads, vtcm_size, act_threads_div, k_div);
|
||||
}
|
||||
|
||||
struct htp_thread_trace * tr = &ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
const size_t vec_dot_size = params->k * sizeof(__fp16);
|
||||
|
||||
const bool use_dma_activation = (params->act_stride > params->k);
|
||||
@@ -2622,7 +2882,8 @@ static int hmx_mm_f16_f32_batched(struct htp_context *ctx, const hmx_mm_f16_f32_
|
||||
|
||||
if (L.total_bytes > vtcm_budget) {
|
||||
FARF(HIGH, "%s: grouped layout overflowed VTCM, falling back to simple batched loop", __func__);
|
||||
return hmx_mm_f16_f32_batched_simple(ctx, params, m_chunk, n_chunk, pipeline, n_threads, act_threads, vtcm_size);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
return hmx_mm_f16_f32_batched_simple(ctx, params, m_chunk, n_chunk, pipeline, n_threads, act_threads, vtcm_size, act_threads_div, k_div);
|
||||
}
|
||||
|
||||
uint8_t * const base = (uint8_t *) ctx->vtcm_base;
|
||||
@@ -2644,6 +2905,8 @@ static int hmx_mm_f16_f32_batched(struct htp_context *ctx, const hmx_mm_f16_f32_
|
||||
const size_t fp16_row_bytes = (size_t) params->k * sizeof(__fp16);
|
||||
const size_t weight_row_bytes = (size_t) params->weight_stride * sizeof(__fp16);
|
||||
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
hmx_matmul_job_t job;
|
||||
|
||||
for (int b3 = 0; b3 < params->ne13; ++b3) {
|
||||
@@ -2662,9 +2925,21 @@ static int hmx_mm_f16_f32_batched(struct htp_context *ctx, const hmx_mm_f16_f32_
|
||||
for (int g = 0; g < group_size; ++g) {
|
||||
const float *activation_chunk = hmx_mm_activation_batch_ptr(params, b2_base + g, b3) + mr * params->act_stride;
|
||||
__fp16 *vtcm_act_g = vtcm_f16_act + (size_t) g * L.act_head_stride;
|
||||
transfer_activation_chunk_threaded(ctx, vtcm_act_g,
|
||||
activation_chunk, (int) n_rows,
|
||||
params->k, params->act_stride, act_threads, params->k, vtcm_f32_act, L.act_f32_bytes);
|
||||
struct activation_transfer_params act_params = {
|
||||
.ctx = ctx,
|
||||
.dst = vtcm_act_g,
|
||||
.src = activation_chunk,
|
||||
.n_rows = (int) n_rows,
|
||||
.k_block = params->k,
|
||||
.k_stride = params->act_stride,
|
||||
.n_threads = act_threads,
|
||||
.act_threads_div = act_threads_div,
|
||||
.k_div = k_div,
|
||||
.k_valid = params->k,
|
||||
.vtcm_f32_act = vtcm_f32_act,
|
||||
.vtcm_f32_act_bytes = L.act_f32_bytes,
|
||||
};
|
||||
transfer_activation_chunk_threaded(&act_params);
|
||||
}
|
||||
|
||||
// Prologue: Push A0 and A1 (if exists)
|
||||
@@ -2835,6 +3110,9 @@ static int hmx_mm_id_2d_f32(struct htp_context *ctx,
|
||||
const struct mmid_row_mapping *matrix_rows,
|
||||
int cur_a,
|
||||
int mapping_stride) {
|
||||
struct htp_thread_trace * tr = &ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
const int cne1 = m;
|
||||
const int m_padded = hex_align_up(m, 32);
|
||||
|
||||
@@ -2913,6 +3191,8 @@ static int hmx_mm_id_2d_f32(struct htp_context *ctx,
|
||||
|
||||
hmx_init_column_scales(vtcm_scales, Q6_V_vsplat_R(0x3c00));
|
||||
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
hmx_matmul_job_t job;
|
||||
|
||||
for (size_t mr = 0; mr < (size_t) m_padded; mr += m_chunk_n_rows) {
|
||||
@@ -2980,10 +3260,6 @@ static int hmx_mm_op_matmul(struct htp_ops_context * octx, const struct htp_mm_k
|
||||
const int act_stride = (int)(src1->nb[1] / sizeof(float));
|
||||
const int wgt_stride = (int)(src0->nb[1] / sizeof(__fp16));
|
||||
|
||||
if (octx->flags & HTP_OPFLAGS_SKIP_COMPUTE) {
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
|
||||
const float * src2_ptr = NULL;
|
||||
uint32_t src2_stride = 0;
|
||||
size_t src2_nb2 = 0;
|
||||
@@ -3027,6 +3303,8 @@ static int hmx_mm_op_matmul(struct htp_ops_context * octx, const struct htp_mm_k
|
||||
kparams->m_chunk, kparams->n_chunk,
|
||||
kparams->pipeline, n_threads,
|
||||
kparams->n_act_threads,
|
||||
&kparams->div_n_act_threads,
|
||||
&kparams->div_ne00_padded,
|
||||
kparams->vtcm_size);
|
||||
} else {
|
||||
ret = hmx_mm_2d_f32(
|
||||
@@ -3035,6 +3313,8 @@ static int hmx_mm_op_matmul(struct htp_ops_context * octx, const struct htp_mm_k
|
||||
(int)(dst->nb[1] / sizeof(float)), src2_stride, (int)dst->ne[0],
|
||||
kparams->m_chunk, kparams->n_chunk, kparams->pipeline, n_threads,
|
||||
kparams->n_act_threads,
|
||||
&kparams->div_n_act_threads,
|
||||
&kparams->div_ne00_padded,
|
||||
kparams->tile_size, kparams->aligned_tile_size, kparams->vtcm_size
|
||||
);
|
||||
}
|
||||
@@ -3103,6 +3383,10 @@ static int hvx_mm_matmul_id(
|
||||
bool must_free_mapping
|
||||
) {
|
||||
htp_matmul_tensors_preamble;
|
||||
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
const struct htp_mm_kernel_params * kparams = (const struct htp_mm_kernel_params *) octx->kernel_params;
|
||||
const struct htp_tensor * restrict ids = octx->src[2];
|
||||
const size_t src0_row_size = nb01;
|
||||
@@ -3175,8 +3459,9 @@ static int hvx_mm_matmul_id(
|
||||
mmctx->n_quant_tasks = n_quant_tasks;
|
||||
atomic_init(&mmctx->quant_barrier, n_quant_tasks);
|
||||
|
||||
const uint32_t n_matmul_jobs = octx->n_threads;
|
||||
worker_pool_run_func(octx->ctx->worker_pool, matmul_id_job_func, mmctx, n_matmul_jobs);
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
worker_pool_run_func(octx->ctx->worker_pool, matmul_id_job_func, mmctx, octx->n_threads);
|
||||
|
||||
if (must_free_mapping) free(mapping_buf);
|
||||
return HTP_STATUS_OK;
|
||||
@@ -3185,6 +3470,9 @@ static int hvx_mm_matmul_id(
|
||||
int op_matmul_id(struct htp_ops_context * octx) {
|
||||
htp_matmul_tensors_preamble;
|
||||
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
struct htp_mm_context mmctx_struct = {0};
|
||||
struct htp_mm_context * mmctx = &mmctx_struct;
|
||||
mmctx->octx = octx;
|
||||
@@ -3262,10 +3550,7 @@ int op_matmul_id(struct htp_ops_context * octx) {
|
||||
}
|
||||
}
|
||||
|
||||
if (octx->flags & HTP_OPFLAGS_SKIP_COMPUTE) {
|
||||
if (must_free_mapping) free(mapping_buf);
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
if (kparams->n_hmx) {
|
||||
return hmx_mm_op_matmul_id(octx, mmctx, matrix_row_counts, matrix_rows, mapping_buf, must_free_mapping);
|
||||
@@ -3275,6 +3560,9 @@ int op_matmul_id(struct htp_ops_context * octx) {
|
||||
}
|
||||
|
||||
int op_matmul_qkv(struct htp_ops_context * octx) {
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
const struct htp_tensor * restrict src0 = octx->src[0]; // Wk
|
||||
const struct htp_tensor * restrict src1 = octx->src[1]; // x
|
||||
const struct htp_tensor * restrict src2 = octx->src[2]; // Wv
|
||||
@@ -3379,9 +3667,6 @@ int op_matmul_qkv(struct htp_ops_context * octx) {
|
||||
mmctx->vtcm_src3_size_per_thread = L.src3_bytes / octx->n_threads;
|
||||
mmctx->vtcm_dst_size_per_thread = L.dst_bytes / octx->n_threads;
|
||||
|
||||
if (octx->flags & HTP_OPFLAGS_SKIP_COMPUTE)
|
||||
return HTP_STATUS_OK;
|
||||
|
||||
mmctx->n_quant_rows_per_thread = (src1_nrows + n_quant_tasks - 1) / n_quant_tasks;
|
||||
mmctx->quant_task_func = quant_task_func;
|
||||
mmctx->n_quant_tasks = n_quant_tasks;
|
||||
@@ -3413,12 +3698,18 @@ int op_matmul_qkv(struct htp_ops_context * octx) {
|
||||
} else {
|
||||
matmul_job_func = hvx_mm_qkv_2d;
|
||||
}
|
||||
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
worker_pool_run_func(octx->ctx->worker_pool, matmul_job_func, mmctx, n_matmul_jobs);
|
||||
|
||||
return HTP_STATUS_OK;
|
||||
}
|
||||
|
||||
int op_matmul_ffn(struct htp_ops_context * octx) {
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[0];
|
||||
htp_trace_event_start(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
const struct htp_tensor * restrict src0 = octx->src[0]; // Wgate
|
||||
const struct htp_tensor * restrict src1 = octx->src[1]; // y
|
||||
const struct htp_tensor * restrict src2 = octx->src[2]; // Wup
|
||||
@@ -3516,9 +3807,6 @@ int op_matmul_ffn(struct htp_ops_context * octx) {
|
||||
mmctx->vtcm_src2_size_per_thread = L.src2_bytes / octx->n_threads;
|
||||
mmctx->vtcm_dst_size_per_thread = L.dst_bytes / octx->n_threads;
|
||||
|
||||
if (octx->flags & HTP_OPFLAGS_SKIP_COMPUTE)
|
||||
return HTP_STATUS_OK;
|
||||
|
||||
mmctx->n_quant_rows_per_thread = (src1_nrows + n_quant_tasks - 1) / n_quant_tasks;
|
||||
mmctx->quant_task_func = quant_task_func;
|
||||
mmctx->n_quant_tasks = n_quant_tasks;
|
||||
@@ -3550,6 +3838,9 @@ int op_matmul_ffn(struct htp_ops_context * octx) {
|
||||
} else {
|
||||
matmul_job_func = hvx_mm_ffn_2d;
|
||||
}
|
||||
|
||||
htp_trace_event_stop(tr, HTP_TRACE_EVT_INIT, 0);
|
||||
|
||||
worker_pool_run_func(octx->ctx->worker_pool, matmul_job_func, mmctx, n_matmul_jobs);
|
||||
|
||||
return HTP_STATUS_OK;
|
||||
|
||||
@@ -95,6 +95,8 @@ struct htp_mm_kernel_params {
|
||||
struct fastdiv_values div_r2;
|
||||
struct fastdiv_values div_r3;
|
||||
struct fastdiv_values div_ne11;
|
||||
struct fastdiv_values div_n_act_threads;
|
||||
struct fastdiv_values div_ne00_padded;
|
||||
};
|
||||
|
||||
#if defined(__cplusplus)
|
||||
@@ -643,6 +645,136 @@ static inline size_t htp_mm_hmx_get_batched_vtcm_size(
|
||||
return L.total_bytes;
|
||||
}
|
||||
|
||||
static inline bool htp_mm_hmx_solve_batched_params(
|
||||
int wtype,
|
||||
uint32_t k,
|
||||
uint32_t ne01_padded,
|
||||
uint32_t ne11,
|
||||
uint32_t group_size,
|
||||
bool use_dma_activation,
|
||||
int n_threads,
|
||||
bool pipeline,
|
||||
size_t vtcm_budget,
|
||||
size_t * m_chunk_out,
|
||||
size_t * n_chunk_out,
|
||||
int * act_threads_out,
|
||||
size_t * vtcm_size_out
|
||||
) {
|
||||
size_t best_mblocks = SIZE_MAX;
|
||||
int best_act_threads = 0;
|
||||
size_t best_m_chunk = 0;
|
||||
size_t best_n_chunk = 0;
|
||||
size_t best_vtcm_size = 0;
|
||||
|
||||
int act_threads = n_threads;
|
||||
while (act_threads >= 1) {
|
||||
size_t group_overhead = 256;
|
||||
size_t group_size_per_n, group_size_per_m, group_size_per_mn;
|
||||
htp_mm_hmx_get_batched_chunk_costs(k, group_size, &group_size_per_n, &group_size_per_m, &group_size_per_mn);
|
||||
|
||||
size_t m_chunk_candidate = 0;
|
||||
size_t n_chunk_candidate = 0;
|
||||
size_t vtcm_size_candidate = 0;
|
||||
|
||||
if (htp_mm_hmx_compute_chunks(vtcm_budget, group_overhead, group_size_per_n, group_size_per_m, group_size_per_mn, hex_align_up(ne11, 32), ne01_padded,
|
||||
(size_t) ne01_padded * HTP_MM_HMX_COST_W_DEQUANT, (size_t) ne11 * HTP_MM_HMX_COST_A_CONVERT,
|
||||
&m_chunk_candidate, &n_chunk_candidate, &vtcm_size_candidate) == 0) {
|
||||
size_t exact_size = htp_mm_hmx_get_batched_vtcm_size(wtype, k, m_chunk_candidate, n_chunk_candidate, group_size, use_dma_activation, pipeline, act_threads);
|
||||
if (exact_size <= vtcm_budget) {
|
||||
size_t mblocks = ((size_t) ne11 + m_chunk_candidate - 1) / m_chunk_candidate;
|
||||
if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads)) {
|
||||
best_mblocks = mblocks;
|
||||
best_act_threads = act_threads;
|
||||
best_m_chunk = m_chunk_candidate;
|
||||
best_n_chunk = n_chunk_candidate;
|
||||
best_vtcm_size = exact_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (act_threads == 1) {
|
||||
act_threads = 0;
|
||||
} else {
|
||||
act_threads /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_act_threads > 0) {
|
||||
*m_chunk_out = best_m_chunk;
|
||||
*n_chunk_out = best_n_chunk;
|
||||
*vtcm_size_out = best_vtcm_size;
|
||||
*act_threads_out = best_act_threads;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool htp_mm_hmx_solve_2d_params(
|
||||
int wtype,
|
||||
uint32_t k,
|
||||
uint32_t m_id_rows,
|
||||
uint32_t ne01_padded,
|
||||
uint32_t ne11_padded,
|
||||
uint32_t m_for_cost,
|
||||
int n_threads,
|
||||
bool pipeline,
|
||||
bool is_matmul_id,
|
||||
uint32_t aligned_tile_size,
|
||||
size_t vtcm_budget,
|
||||
size_t * m_chunk_out,
|
||||
size_t * n_chunk_out,
|
||||
int * act_threads_out,
|
||||
size_t * vtcm_size_out
|
||||
) {
|
||||
size_t best_mblocks = SIZE_MAX;
|
||||
int best_act_threads = 0;
|
||||
size_t best_m_chunk = 0;
|
||||
size_t best_n_chunk = 0;
|
||||
size_t best_vtcm_size = 0;
|
||||
|
||||
const int m_for_chunks = is_matmul_id ? hex_align_up(m_id_rows, 32) : ne11_padded;
|
||||
|
||||
int act_threads = n_threads;
|
||||
while (act_threads >= 1) {
|
||||
size_t simple_2d_overhead = 256;
|
||||
size_t simple_2d_size_per_n, simple_2d_size_per_m, simple_2d_size_per_mn;
|
||||
htp_mm_hmx_get_2d_chunk_costs(wtype, k, pipeline, aligned_tile_size, &simple_2d_size_per_n, &simple_2d_size_per_m, &simple_2d_size_per_mn);
|
||||
|
||||
size_t m_chunk_candidate = 0;
|
||||
size_t n_chunk_candidate = 0;
|
||||
size_t vtcm_size_candidate = 0;
|
||||
|
||||
if (htp_mm_hmx_compute_chunks(vtcm_budget, simple_2d_overhead, simple_2d_size_per_n, simple_2d_size_per_m, simple_2d_size_per_mn, m_for_chunks, ne01_padded,
|
||||
(size_t) ne01_padded * HTP_MM_HMX_COST_W_DEQUANT, (size_t) m_for_cost * HTP_MM_HMX_COST_A_CONVERT,
|
||||
&m_chunk_candidate, &n_chunk_candidate, &vtcm_size_candidate) == 0) {
|
||||
size_t exact_size = htp_mm_hmx_get_2d_vtcm_size(wtype, k, m_chunk_candidate, n_chunk_candidate, pipeline, is_matmul_id ? 0 : act_threads, aligned_tile_size);
|
||||
if (exact_size <= vtcm_budget) {
|
||||
size_t mblocks = ((size_t) m_for_cost + m_chunk_candidate - 1) / m_chunk_candidate;
|
||||
if (mblocks < best_mblocks || (mblocks == best_mblocks && act_threads > best_act_threads)) {
|
||||
best_mblocks = mblocks;
|
||||
best_act_threads = act_threads;
|
||||
best_m_chunk = m_chunk_candidate;
|
||||
best_n_chunk = n_chunk_candidate;
|
||||
best_vtcm_size = exact_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (act_threads == 1) {
|
||||
act_threads = 0;
|
||||
} else {
|
||||
act_threads /= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_act_threads > 0) {
|
||||
*m_chunk_out = best_m_chunk;
|
||||
*n_chunk_out = best_n_chunk;
|
||||
*vtcm_size_out = best_vtcm_size;
|
||||
*act_threads_out = best_act_threads;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "htp-ctx.h"
|
||||
#include "htp-ops.h"
|
||||
#include "htp-ops.h"
|
||||
#include "htp-tensor.h"
|
||||
|
||||
// Redefined the rope type constants as we can't include ggml.h
|
||||
#define HTP_ROPE_TYPE_NORMAL 0
|
||||
@@ -712,17 +713,11 @@ static int execute_op_rope_f32(struct htp_ops_context * octx) {
|
||||
}
|
||||
|
||||
int op_rope(struct htp_ops_context * octx) {
|
||||
int err = HTP_STATUS_OK;
|
||||
|
||||
switch (octx->src[0]->type) {
|
||||
case HTP_TYPE_F32:
|
||||
err = execute_op_rope_f32(octx);
|
||||
break;
|
||||
return execute_op_rope_f32(octx);
|
||||
|
||||
default:
|
||||
err = HTP_STATUS_NO_SUPPORT;
|
||||
break;
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ggml-common.h"
|
||||
#include "htp-ctx.h"
|
||||
#include "htp-ops.h"
|
||||
#include "htp-tensor.h"
|
||||
#include "htp-vtcm.h"
|
||||
#include "hex-profile.h"
|
||||
|
||||
@@ -137,6 +138,24 @@ static void scale_f32(const float * restrict src,
|
||||
}
|
||||
}
|
||||
|
||||
static void clamp_f32(const float * restrict src,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_unary_context * uctx) {
|
||||
htp_unary_op_preamble;
|
||||
float min = 0.f;
|
||||
float max = 0.f;
|
||||
memcpy(&min, &op_params[0], sizeof(float));
|
||||
memcpy(&max, &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_clamp_scalar_f32(dst_local, src_local, min, max, ne0);
|
||||
}
|
||||
}
|
||||
|
||||
static void rms_norm_f32(const float * restrict src,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
@@ -257,6 +276,39 @@ static void sigmoid_f32(const float * restrict src,
|
||||
}
|
||||
}
|
||||
|
||||
// silu(x) = x * sigmoid(x)
|
||||
static void silu_f32(const float * restrict src,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_unary_context * uctx) {
|
||||
htp_unary_op_preamble;
|
||||
|
||||
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_sigmoid_f32_aa(dst_local, src_local, ne0);
|
||||
hvx_mul_f32_aaa(dst_local, src_local, dst_local, ne0);
|
||||
}
|
||||
}
|
||||
|
||||
// gelu(x) = x * sigmoid(1.702 * x) (quick/sigmoid approximation, matches CPU GELU_QUICK reference)
|
||||
static void gelu_f32(const float * restrict src,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
const struct htp_unary_context * uctx) {
|
||||
htp_unary_op_preamble;
|
||||
|
||||
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_mul_scalar_f32(dst_local, src_local, 1.702f, ne0);
|
||||
hvx_sigmoid_f32_aa(dst_local, dst_local, ne0);
|
||||
hvx_mul_f32_aaa(dst_local, src_local, dst_local, ne0);
|
||||
}
|
||||
}
|
||||
|
||||
static void tri_f32(const float * restrict src,
|
||||
float * restrict dst,
|
||||
const uint32_t num_rows,
|
||||
@@ -397,7 +449,7 @@ static void unary_task_f32_##NAME(unsigned int nth, unsigned int ith, void * dat
|
||||
struct htp_ops_context * octx = uctx->octx; \
|
||||
const struct htp_tensor * src = octx->src[0]; \
|
||||
const struct htp_tensor * dst = octx->dst; \
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
\
|
||||
htp_unary_preamble; \
|
||||
\
|
||||
@@ -541,11 +593,14 @@ DEFINE_UNARY_TASK(norm, false, false, norm_f32(src0_vtcm, dst_vtcm, bl
|
||||
DEFINE_UNARY_TASK(rms_norm, false, false, rms_norm_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(rms_norm_mul, true, false, rms_norm_mul_f32(src0_vtcm, uctx->broadcast_weight ? (const float *) src1_vtcm_data : src1_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(scale, false, false, scale_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(clamp, false, false, clamp_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(sqr, false, false, sqr_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(sqrt, false, false, sqrt_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_neg, false, false, neg_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_exp, false, false, exp_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_sigmoid, false, false, sigmoid_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_silu, false, false, silu_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_gelu, false, false, gelu_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_softplus, false, false, softplus_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(unary_tanh, false, false, tanh_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
DEFINE_UNARY_TASK(l2_norm, false, false, l2_norm_f32(src0_vtcm, dst_vtcm, block_size, uctx))
|
||||
@@ -558,7 +613,7 @@ static void unary_task_f32_tiled_##NAME(unsigned int nth, unsigned int ith, void
|
||||
struct htp_ops_context * octx = uctx->octx; \
|
||||
const struct htp_tensor * src = octx->src[0]; \
|
||||
const struct htp_tensor * dst = octx->dst; \
|
||||
struct htp_thread_trace * tr = octx->ctx ? &octx->ctx->trace[ith] : NULL; \
|
||||
struct htp_thread_trace * tr = &octx->ctx->trace[ith]; \
|
||||
\
|
||||
htp_unary_preamble; \
|
||||
\
|
||||
@@ -680,6 +735,14 @@ static inline void tile_scale_f32(uint8_t * dst_vtcm, const uint8_t * src_vtcm,
|
||||
hvx_scale_offset_f32_aa(dst_vtcm, src_vtcm, tw, scale, bias);
|
||||
}
|
||||
|
||||
static inline void tile_clamp_f32(uint8_t * dst_vtcm, const uint8_t * src_vtcm, uint32_t tw, const int32_t * op_params) {
|
||||
float min = 0.f;
|
||||
float max = 0.f;
|
||||
memcpy(&min, &op_params[0], sizeof(float));
|
||||
memcpy(&max, &op_params[1], sizeof(float));
|
||||
hvx_clamp_scalar_f32(dst_vtcm, src_vtcm, min, max, tw);
|
||||
}
|
||||
|
||||
static inline void tile_unary_softplus_f32(uint8_t * dst_vtcm, const uint8_t * src_vtcm, uint32_t tw) {
|
||||
const float * restrict sf = (const float *) src_vtcm;
|
||||
float * restrict df = (float *) dst_vtcm;
|
||||
@@ -689,6 +752,19 @@ static inline void tile_unary_softplus_f32(uint8_t * dst_vtcm, const uint8_t * s
|
||||
}
|
||||
}
|
||||
|
||||
// silu(x) = x * sigmoid(x)
|
||||
static inline void tile_silu_f32(uint8_t * dst_vtcm, const uint8_t * src_vtcm, uint32_t tw) {
|
||||
hvx_sigmoid_f32_aa(dst_vtcm, src_vtcm, tw);
|
||||
hvx_mul_f32_aaa(dst_vtcm, src_vtcm, dst_vtcm, tw);
|
||||
}
|
||||
|
||||
// gelu(x) = x * sigmoid(1.702 * x) (quick/sigmoid approximation, matches CPU GELU_QUICK reference)
|
||||
static inline void tile_gelu_f32(uint8_t * dst_vtcm, const uint8_t * src_vtcm, uint32_t tw) {
|
||||
hvx_mul_scalar_f32(dst_vtcm, src_vtcm, 1.702f, tw);
|
||||
hvx_sigmoid_f32_aa(dst_vtcm, dst_vtcm, tw);
|
||||
hvx_mul_f32_aaa(dst_vtcm, src_vtcm, dst_vtcm, tw);
|
||||
}
|
||||
|
||||
// Triangular mask applied to one column tile. Boundary is an absolute column index, so
|
||||
// each vector compares against its absolute column position (col_start + i*VLEN_FP32).
|
||||
static inline void tri_apply_tile_f32(const uint8_t * restrict src, uint8_t * restrict dst,
|
||||
@@ -764,11 +840,14 @@ static inline void tri_apply_tile_f32(const uint8_t * restrict src, uint8_t * re
|
||||
}
|
||||
|
||||
DEFINE_UNARY_TILED_TASK(scale, false, tile_scale_f32(dst_vtcm, src_vtcm, tw, op_params))
|
||||
DEFINE_UNARY_TILED_TASK(clamp, false, tile_clamp_f32(dst_vtcm, src_vtcm, tw, op_params))
|
||||
DEFINE_UNARY_TILED_TASK(sqr, false, hvx_sqr_f32_aa(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(sqrt, false, hvx_sqrt_f32_aa(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(unary_neg, false, hvx_scale_f32_aa(dst_vtcm, src_vtcm, tw, -1.0f))
|
||||
DEFINE_UNARY_TILED_TASK(unary_exp, false, hvx_exp_f32(dst_vtcm, src_vtcm, tw, false))
|
||||
DEFINE_UNARY_TILED_TASK(unary_sigmoid, false, hvx_sigmoid_f32_aa(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(unary_silu, false, tile_silu_f32(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(unary_gelu, false, tile_gelu_f32(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(unary_softplus, false, tile_unary_softplus_f32(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(unary_tanh, false, hvx_tanh_f32_aa(dst_vtcm, src_vtcm, tw))
|
||||
DEFINE_UNARY_TILED_TASK(tri, true, tri_apply_tile_f32(src_vtcm, dst_vtcm, tw, col, i01, ne0, tri_ttype))
|
||||
@@ -786,11 +865,14 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
|
||||
case HTP_OP_RMS_NORM: op_type = "rmsnorm-f32"; break;
|
||||
case HTP_OP_RMS_NORM_MUL: op_type = "rmsnorm-mul-f32"; break;
|
||||
case HTP_OP_SCALE: op_type = "scale-f32"; break;
|
||||
case HTP_OP_CLAMP: op_type = "clamp-f32"; break;
|
||||
case HTP_OP_SQR: op_type = "sqr-f32"; break;
|
||||
case HTP_OP_SQRT: op_type = "sqrt-f32"; break;
|
||||
case HTP_OP_UNARY_NEG: op_type = "neg-f32"; break;
|
||||
case HTP_OP_UNARY_EXP: op_type = "exp-f32"; break;
|
||||
case HTP_OP_UNARY_SIGMOID: op_type = "sigmoid-f32"; break;
|
||||
case HTP_OP_UNARY_SILU: op_type = "silu-f32"; break;
|
||||
case HTP_OP_UNARY_GELU: op_type = "gelu-f32"; break;
|
||||
case HTP_OP_UNARY_SOFTPLUS: op_type = "softplus-f32"; break;
|
||||
case HTP_OP_UNARY_TANH: op_type = "tanh-f32"; break;
|
||||
case HTP_OP_L2_NORM: op_type = "l2norm-f32"; break;
|
||||
@@ -881,11 +963,14 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
|
||||
if (col_tile) {
|
||||
switch (octx->op) {
|
||||
case HTP_OP_SCALE: task_func = unary_task_f32_tiled_scale; break;
|
||||
case HTP_OP_CLAMP: task_func = unary_task_f32_tiled_clamp; break;
|
||||
case HTP_OP_SQR: task_func = unary_task_f32_tiled_sqr; break;
|
||||
case HTP_OP_SQRT: task_func = unary_task_f32_tiled_sqrt; break;
|
||||
case HTP_OP_UNARY_NEG: task_func = unary_task_f32_tiled_unary_neg; break;
|
||||
case HTP_OP_UNARY_EXP: task_func = unary_task_f32_tiled_unary_exp; break;
|
||||
case HTP_OP_UNARY_SIGMOID: task_func = unary_task_f32_tiled_unary_sigmoid; break;
|
||||
case HTP_OP_UNARY_SILU: task_func = unary_task_f32_tiled_unary_silu; break;
|
||||
case HTP_OP_UNARY_GELU: task_func = unary_task_f32_tiled_unary_gelu; break;
|
||||
case HTP_OP_UNARY_SOFTPLUS: task_func = unary_task_f32_tiled_unary_softplus; break;
|
||||
case HTP_OP_UNARY_TANH: task_func = unary_task_f32_tiled_unary_tanh; break;
|
||||
case HTP_OP_TRI: task_func = unary_task_f32_tiled_tri; break;
|
||||
@@ -897,11 +982,14 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
|
||||
case HTP_OP_RMS_NORM: task_func = unary_task_f32_rms_norm; break;
|
||||
case HTP_OP_RMS_NORM_MUL: task_func = unary_task_f32_rms_norm_mul; break;
|
||||
case HTP_OP_SCALE: task_func = unary_task_f32_scale; break;
|
||||
case HTP_OP_CLAMP: task_func = unary_task_f32_clamp; break;
|
||||
case HTP_OP_SQR: task_func = unary_task_f32_sqr; break;
|
||||
case HTP_OP_SQRT: task_func = unary_task_f32_sqrt; break;
|
||||
case HTP_OP_UNARY_NEG: task_func = unary_task_f32_unary_neg; break;
|
||||
case HTP_OP_UNARY_EXP: task_func = unary_task_f32_unary_exp; break;
|
||||
case HTP_OP_UNARY_SIGMOID: task_func = unary_task_f32_unary_sigmoid; break;
|
||||
case HTP_OP_UNARY_SILU: task_func = unary_task_f32_unary_silu; break;
|
||||
case HTP_OP_UNARY_GELU: task_func = unary_task_f32_unary_gelu; break;
|
||||
case HTP_OP_UNARY_SOFTPLUS: task_func = unary_task_f32_unary_softplus; break;
|
||||
case HTP_OP_UNARY_TANH: task_func = unary_task_f32_unary_tanh; break;
|
||||
case HTP_OP_L2_NORM: task_func = unary_task_f32_l2_norm; break;
|
||||
@@ -922,17 +1010,11 @@ static int execute_op_unary_f32(struct htp_ops_context * octx) {
|
||||
}
|
||||
|
||||
int op_unary(struct htp_ops_context * octx) {
|
||||
int err = HTP_STATUS_OK;
|
||||
|
||||
switch (octx->src[0]->type) {
|
||||
case HTP_TYPE_F32:
|
||||
err = execute_op_unary_f32(octx);
|
||||
break;
|
||||
return execute_op_unary_f32(octx);
|
||||
|
||||
default:
|
||||
err = HTP_STATUS_NO_SUPPORT;
|
||||
break;
|
||||
return HTP_STATUS_NO_SUPPORT;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ _Static_assert(sizeof(struct htp_unary_kernel_params) <= 128, "htp_unary_kernel_
|
||||
|
||||
static inline bool htp_op_is_unary(uint32_t opcode) {
|
||||
switch (opcode) {
|
||||
case HTP_OP_CLAMP:
|
||||
case HTP_OP_NORM:
|
||||
case HTP_OP_RMS_NORM:
|
||||
case HTP_OP_RMS_NORM_MUL:
|
||||
@@ -50,6 +51,8 @@ static inline bool htp_op_is_unary(uint32_t opcode) {
|
||||
case HTP_OP_UNARY_NEG:
|
||||
case HTP_OP_UNARY_EXP:
|
||||
case HTP_OP_UNARY_SIGMOID:
|
||||
case HTP_OP_UNARY_SILU:
|
||||
case HTP_OP_UNARY_GELU:
|
||||
case HTP_OP_UNARY_SOFTPLUS:
|
||||
case HTP_OP_UNARY_TANH:
|
||||
case HTP_OP_L2_NORM:
|
||||
|
||||
@@ -0,0 +1,244 @@
|
||||
#include "work-queue.h"
|
||||
#include "hex-utils.h"
|
||||
|
||||
#include <qurt.h>
|
||||
#include <qurt_hvx.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "HAP_farf.h"
|
||||
|
||||
#define LOWEST_USABLE_QURT_PRIO (254)
|
||||
|
||||
// internal structure kept in thread-local storage per instance of work queue
|
||||
typedef struct {
|
||||
work_queue_t queue;
|
||||
unsigned int id;
|
||||
} worker_context_t;
|
||||
|
||||
struct work_queue_task_s {
|
||||
work_queue_func_t func;
|
||||
void * data;
|
||||
unsigned int n_threads;
|
||||
atomic_uint barrier;
|
||||
};
|
||||
|
||||
// internal structure kept in thread-local storage per instance of work queue
|
||||
struct work_queue_s {
|
||||
atomic_uint seqn; // seqno used to detect new jobs
|
||||
atomic_uint idx_read; // Updated by producer (pop/reclaim)
|
||||
unsigned int idx_write; // Updated by producer (push)
|
||||
uint32_t idx_mask;
|
||||
uint32_t capacity;
|
||||
|
||||
qurt_thread_t thread[WORK_QUEUE_MAX_N_THREADS]; // thread ID's of the workers
|
||||
worker_context_t context[WORK_QUEUE_MAX_N_THREADS]; // worker contexts
|
||||
void * stack[WORK_QUEUE_MAX_N_THREADS]; // thread stack pointers
|
||||
unsigned int n_threads; // total threads (workers + main)
|
||||
unsigned int n_workers; // number of active threads (just workers)
|
||||
|
||||
atomic_bool active; // workers are polling/active
|
||||
atomic_bool killed; // threads need to exit
|
||||
bool external_mem; // memory owned externally
|
||||
|
||||
struct work_queue_task_s queue[] __attribute__((aligned(HEX_L2_LINE_SIZE)));
|
||||
};
|
||||
|
||||
static void work_queue_thread(void * context) {
|
||||
worker_context_t * me = (worker_context_t *) context;
|
||||
work_queue_t q = me->queue;
|
||||
|
||||
FARF(HIGH, "work-queue: thread %u started", me->id);
|
||||
|
||||
unsigned int prev_seqn = 0;
|
||||
|
||||
while (!atomic_load_explicit(&q->killed, memory_order_relaxed)) {
|
||||
unsigned int seqn = atomic_load_explicit(&q->seqn, memory_order_acquire);
|
||||
if (seqn == prev_seqn) {
|
||||
if (atomic_load_explicit(&q->active, memory_order_relaxed)) {
|
||||
hex_pause();
|
||||
} else {
|
||||
qurt_futex_wait(&q->seqn, prev_seqn);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_seqn = seqn;
|
||||
|
||||
// Process all active tasks in the queue
|
||||
unsigned int ir = atomic_load_explicit(&q->idx_read, memory_order_relaxed);
|
||||
unsigned int iw = q->idx_write;
|
||||
|
||||
while (ir != iw) {
|
||||
struct work_queue_task_s * task = &q->queue[ir];
|
||||
|
||||
unsigned int n = task->n_threads;
|
||||
unsigned int i = me->id;
|
||||
if (i < n) {
|
||||
task->func(n, i, task->data);
|
||||
|
||||
atomic_fetch_sub_explicit(&task->barrier, 1, memory_order_release);
|
||||
} else {
|
||||
while (atomic_load_explicit(&task->barrier, memory_order_relaxed) > 0) {
|
||||
hex_pause();
|
||||
}
|
||||
}
|
||||
|
||||
ir = (ir + 1) & q->idx_mask;
|
||||
}
|
||||
}
|
||||
|
||||
FARF(HIGH, "work-queue: thread %u stopped", me->id);
|
||||
}
|
||||
|
||||
bool work_queue_run_async(work_queue_t q, work_queue_func_t func, void * data, unsigned int n) {
|
||||
if (n > q->n_threads) {
|
||||
FARF(ERROR, "work-queue: invalid number of jobs %u for n-threads %u", n, q->n_threads);
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int ir = atomic_load_explicit(&q->idx_read, memory_order_relaxed);
|
||||
unsigned int iw = q->idx_write;
|
||||
|
||||
if (((iw + 1) & q->idx_mask) == ir) {
|
||||
FARF(ERROR, "work-queue-push: queue is full\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
struct work_queue_task_s * task = &q->queue[iw];
|
||||
task->func = func;
|
||||
task->data = data;
|
||||
task->n_threads = n;
|
||||
atomic_store_explicit(&task->barrier, n, memory_order_relaxed);
|
||||
|
||||
q->idx_write = (iw + 1) & q->idx_mask;
|
||||
|
||||
// publish job to workers (already awake and polling)
|
||||
atomic_fetch_add_explicit(&q->seqn, 1, memory_order_release);
|
||||
|
||||
// main thread runs job #0
|
||||
func(n, 0, data);
|
||||
|
||||
atomic_fetch_sub_explicit(&task->barrier, 1, memory_order_release);
|
||||
|
||||
while (atomic_load_explicit(&task->barrier, memory_order_relaxed) > 0) {
|
||||
hex_pause();
|
||||
}
|
||||
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
|
||||
atomic_store_explicit(&q->idx_read, (ir + 1) & q->idx_mask, memory_order_relaxed);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t work_queue_sizeof(uint32_t n_threads, uint32_t capacity, uint32_t stack_size) {
|
||||
capacity = hex_ceil_pow2(capacity);
|
||||
uint32_t n_workers = n_threads > 1 ? n_threads - 1 : 0;
|
||||
size_t size_stacks = stack_size * n_workers;
|
||||
size_t size_q = hex_align_up(sizeof(struct work_queue_s) + capacity * sizeof(struct work_queue_task_s), HEX_L2_LINE_SIZE);
|
||||
return size_stacks + size_q;
|
||||
}
|
||||
|
||||
size_t work_queue_alignof(void) {
|
||||
return 4096;
|
||||
}
|
||||
|
||||
work_queue_t work_queue_init(void * ptr, uint32_t n_threads, uint32_t capacity, uint32_t stack_size) {
|
||||
capacity = hex_ceil_pow2(capacity);
|
||||
uint32_t n_workers = n_threads > 1 ? n_threads - 1 : 0;
|
||||
unsigned char * mem_blob = (unsigned char *) ptr;
|
||||
|
||||
work_queue_t q = (work_queue_t) (mem_blob + stack_size * n_workers);
|
||||
memset(q, 0, sizeof(struct work_queue_s) + capacity * sizeof(struct work_queue_task_s));
|
||||
|
||||
q->n_threads = n_threads;
|
||||
q->n_workers = n_workers;
|
||||
q->external_mem = true;
|
||||
q->capacity = capacity;
|
||||
|
||||
for (unsigned int i = 0; i < n_workers; i++) {
|
||||
q->stack[i] = mem_blob; mem_blob += stack_size;
|
||||
q->thread[i] = 0;
|
||||
q->context[i].id = i + 1;
|
||||
q->context[i].queue = q;
|
||||
}
|
||||
|
||||
atomic_init(&q->idx_read, 0);
|
||||
atomic_init(&q->seqn, 0);
|
||||
atomic_init(&q->active, false);
|
||||
q->idx_write = 0;
|
||||
q->idx_mask = capacity - 1;
|
||||
q->killed = 0;
|
||||
for (int i = 0; i < (int) capacity; i++) {
|
||||
atomic_init(&q->queue[i].barrier, 0);
|
||||
q->queue[i].func = NULL;
|
||||
q->queue[i].data = NULL;
|
||||
q->queue[i].n_threads = 0;
|
||||
}
|
||||
|
||||
// launch the workers
|
||||
qurt_thread_attr_t attr;
|
||||
qurt_thread_attr_init(&attr);
|
||||
|
||||
for (unsigned int i = 0; i < n_workers; i++) {
|
||||
qurt_thread_attr_set_stack_addr(&attr, q->stack[i]);
|
||||
qurt_thread_attr_set_stack_size(&attr, stack_size);
|
||||
|
||||
char thread_name[32];
|
||||
snprintf(thread_name, sizeof(thread_name), "work-queue:%u", i);
|
||||
qurt_thread_attr_set_name(&attr, thread_name);
|
||||
|
||||
// set up priority - by default, match the creating thread's prio
|
||||
int prio = qurt_thread_get_priority(qurt_thread_get_id());
|
||||
if (prio < 1) {
|
||||
prio = 1;
|
||||
}
|
||||
if (prio > LOWEST_USABLE_QURT_PRIO) {
|
||||
prio = LOWEST_USABLE_QURT_PRIO;
|
||||
}
|
||||
|
||||
qurt_thread_attr_set_priority(&attr, prio);
|
||||
|
||||
int err = qurt_thread_create(&q->thread[i], &attr, work_queue_thread, (void *) &q->context[i]);
|
||||
if (err) {
|
||||
FARF(ERROR, "Could not launch worker threads!");
|
||||
work_queue_free(q);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void work_queue_free(work_queue_t q) {
|
||||
if (!q) { return; }
|
||||
|
||||
atomic_store_explicit(&q->killed, 1, memory_order_relaxed);
|
||||
atomic_fetch_add_explicit(&q->seqn, 1, memory_order_release);
|
||||
qurt_futex_wake(&q->seqn, q->n_workers);
|
||||
|
||||
for (unsigned int i = 0; i < q->n_workers; i++) {
|
||||
if (q->thread[i]) {
|
||||
int status;
|
||||
(void) qurt_thread_join(q->thread[i], &status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void work_queue_wakeup(work_queue_t q) {
|
||||
if (!atomic_load_explicit(&q->active, memory_order_relaxed)) {
|
||||
atomic_store_explicit(&q->active, true, memory_order_release);
|
||||
// Increment seqn and wake workers to transition them out of sleep
|
||||
atomic_fetch_add_explicit(&q->seqn, 1, memory_order_release);
|
||||
qurt_futex_wake(&q->seqn, q->n_workers);
|
||||
}
|
||||
}
|
||||
|
||||
void work_queue_suspend(work_queue_t q) {
|
||||
atomic_store_explicit(&q->active, false, memory_order_release);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#ifndef HTP_WORK_QUEUE_H
|
||||
#define HTP_WORK_QUEUE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void (*work_queue_func_t)(unsigned int n, unsigned int i, void *);
|
||||
|
||||
struct work_queue_s;
|
||||
typedef struct work_queue_s * work_queue_t;
|
||||
|
||||
#define WORK_QUEUE_MAX_N_THREADS 10
|
||||
|
||||
size_t work_queue_sizeof(uint32_t n_threads, uint32_t capacity, uint32_t stack_size);
|
||||
size_t work_queue_alignof(void);
|
||||
work_queue_t work_queue_init(void * ptr, uint32_t n_threads, uint32_t capacity, uint32_t stack_size);
|
||||
void work_queue_free(work_queue_t q);
|
||||
|
||||
void work_queue_wakeup(work_queue_t q);
|
||||
void work_queue_suspend(work_queue_t q);
|
||||
|
||||
bool work_queue_run_async(work_queue_t q, work_queue_func_t func, void * data, unsigned int n);
|
||||
|
||||
static inline bool work_queue_run(work_queue_t q, work_queue_func_t func, void * data, unsigned int n) {
|
||||
if (n <= 1) {
|
||||
func(n, 0, data);
|
||||
return true;
|
||||
}
|
||||
return work_queue_run_async(q, func, data, n);
|
||||
}
|
||||
|
||||
// Legacy compatibility
|
||||
typedef work_queue_func_t worker_callback_t;
|
||||
#define worker_pool_run_func work_queue_run
|
||||
#define worker_pool work_queue
|
||||
|
||||
#endif // #ifndef HTP_WORK_QUEUE_H
|
||||
@@ -1,305 +0,0 @@
|
||||
#include "worker-pool.h"
|
||||
#include "hex-utils.h"
|
||||
|
||||
#include <qurt.h>
|
||||
#include <qurt_hvx.h>
|
||||
|
||||
#include <stdatomic.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "HAP_farf.h"
|
||||
|
||||
#define LOWEST_USABLE_QURT_PRIO (254)
|
||||
|
||||
struct worker_pool_s;
|
||||
|
||||
// internal structure kept in thread-local storage per instance of worker pool
|
||||
typedef struct {
|
||||
struct worker_pool_s * pool;
|
||||
unsigned int id;
|
||||
} worker_context_t;
|
||||
|
||||
// internal structure kept in thread-local storage per instance of worker pool
|
||||
typedef struct worker_pool_s {
|
||||
worker_pool_job_t job[MAX_NUM_WORKERS]; // list of job descriptors
|
||||
qurt_thread_t thread[MAX_NUM_WORKERS]; // thread ID's of the workers
|
||||
worker_context_t context[MAX_NUM_WORKERS]; // worker contexts
|
||||
void * stack[MAX_NUM_WORKERS]; // thread stack pointers
|
||||
unsigned int n_threads; // number of workers in this pool
|
||||
|
||||
atomic_uint seqn; // seqno used to detect new jobs
|
||||
atomic_uint next_job; // next job index
|
||||
atomic_uint n_pending; // number of pending jobs
|
||||
atomic_uint n_jobs; // number of current jobs
|
||||
atomic_bool killed; // threads need to exit
|
||||
} worker_pool_t;
|
||||
|
||||
static void worker_pool_main(void * context) {
|
||||
worker_context_t * me = (worker_context_t *) context;
|
||||
worker_pool_t * pool = me->pool;
|
||||
|
||||
FARF(HIGH, "worker-pool: thread %u started", me->id);
|
||||
|
||||
unsigned int prev_seqn = 0;
|
||||
unsigned int poll_cnt = WORKER_POOL_POLL_COUNT;
|
||||
while (!atomic_load(&pool->killed)) {
|
||||
unsigned int seqn = atomic_load(&pool->seqn);
|
||||
if (seqn == prev_seqn) {
|
||||
// drop HVX context while spinning
|
||||
if (poll_cnt > 1 && poll_cnt == WORKER_POOL_POLL_COUNT) {
|
||||
qurt_hvx_unlock();
|
||||
}
|
||||
if (--poll_cnt) {
|
||||
hex_pause();
|
||||
continue;
|
||||
}
|
||||
qurt_futex_wait(&pool->seqn, prev_seqn);
|
||||
poll_cnt = WORKER_POOL_POLL_COUNT;
|
||||
continue;
|
||||
}
|
||||
|
||||
prev_seqn = seqn;
|
||||
poll_cnt = WORKER_POOL_POLL_COUNT;
|
||||
|
||||
// New job
|
||||
unsigned int n = atomic_load(&pool->n_jobs);
|
||||
unsigned int i = atomic_fetch_add(&pool->next_job, 1);
|
||||
if (i >= n) {
|
||||
// Spurious wakeup
|
||||
continue;
|
||||
}
|
||||
|
||||
pool->job[i].func(n, i, pool->job[i].data);
|
||||
|
||||
atomic_fetch_sub(&pool->n_pending, 1);
|
||||
}
|
||||
|
||||
FARF(HIGH, "worker-pool: thread %u stopped", me->id);
|
||||
}
|
||||
|
||||
AEEResult worker_pool_init_with_stack_size(worker_pool_context_t * context, uint32_t n_threads, uint32_t stack_size) {
|
||||
int err = 0;
|
||||
|
||||
if (NULL == context) {
|
||||
FARF(ERROR, "NULL context passed to worker_pool_init().");
|
||||
return AEE_EBADPARM;
|
||||
}
|
||||
|
||||
// Allocations
|
||||
int size = (stack_size * n_threads) + (sizeof(worker_pool_t));
|
||||
|
||||
unsigned char * mem_blob = (unsigned char *) malloc(size);
|
||||
if (!mem_blob) {
|
||||
FARF(ERROR, "Could not allocate memory for worker pool!!");
|
||||
return AEE_ENOMEMORY;
|
||||
}
|
||||
|
||||
worker_pool_t * me = (worker_pool_t *) (mem_blob + stack_size * n_threads);
|
||||
|
||||
// name for the first worker, useful in debugging threads
|
||||
char name[19];
|
||||
snprintf(name, 12, "0x%8x:", (int) me);
|
||||
strcat(name, "worker0");
|
||||
me->n_threads = n_threads;
|
||||
|
||||
// initializations
|
||||
for (unsigned int i = 0; i < me->n_threads; i++) {
|
||||
me->stack[i] = NULL;
|
||||
me->thread[i] = 0;
|
||||
|
||||
me->context[i].id = i;
|
||||
me->context[i].pool = me;
|
||||
}
|
||||
|
||||
// initialize job queue
|
||||
me->n_pending = 0;
|
||||
me->n_jobs = 0;
|
||||
me->next_job = 0;
|
||||
me->seqn = 0;
|
||||
me->killed = 0;
|
||||
|
||||
// launch the workers
|
||||
qurt_thread_attr_t attr;
|
||||
qurt_thread_attr_init(&attr);
|
||||
|
||||
for (unsigned int i = 0; i < me->n_threads; i++) {
|
||||
// set up stack
|
||||
me->stack[i] = mem_blob;
|
||||
mem_blob += stack_size;
|
||||
qurt_thread_attr_set_stack_addr(&attr, me->stack[i]);
|
||||
qurt_thread_attr_set_stack_size(&attr, stack_size);
|
||||
|
||||
// set up name
|
||||
qurt_thread_attr_set_name(&attr, name);
|
||||
name[17] = (name[17] + 1);
|
||||
// name threads context:worker0, context:worker1, .. (recycle at 9, but num threads should be less than that anyway)
|
||||
if (name[17] > '9') {
|
||||
name[17] = '0';
|
||||
}
|
||||
|
||||
// set up priority - by default, match the creating thread's prio
|
||||
int prio = qurt_thread_get_priority(qurt_thread_get_id());
|
||||
|
||||
if (prio < 1) {
|
||||
prio = 1;
|
||||
}
|
||||
if (prio > LOWEST_USABLE_QURT_PRIO) {
|
||||
prio = LOWEST_USABLE_QURT_PRIO;
|
||||
}
|
||||
|
||||
qurt_thread_attr_set_priority(&attr, prio);
|
||||
|
||||
// launch
|
||||
err = qurt_thread_create(&me->thread[i], &attr, worker_pool_main, (void *) &me->context[i]);
|
||||
if (err) {
|
||||
FARF(ERROR, "Could not launch worker threads!");
|
||||
worker_pool_release((worker_pool_context_t *) &me);
|
||||
return AEE_EQURTTHREADCREATE;
|
||||
}
|
||||
}
|
||||
*context = (worker_pool_context_t *) me;
|
||||
return AEE_SUCCESS;
|
||||
}
|
||||
|
||||
AEEResult worker_pool_init(worker_pool_context_t * context, uint32_t n_threads) {
|
||||
return worker_pool_init_with_stack_size(context, n_threads, WORKER_THREAD_STACK_SZ);
|
||||
}
|
||||
|
||||
// clean up worker pool
|
||||
void worker_pool_release(worker_pool_context_t * context) {
|
||||
worker_pool_t * me = (worker_pool_t *) *context;
|
||||
|
||||
// if no worker pool exists, return error.
|
||||
if (NULL == me) {
|
||||
return;
|
||||
}
|
||||
|
||||
atomic_store(&me->killed, 1);
|
||||
atomic_fetch_add(&me->seqn, 1);
|
||||
qurt_futex_wake(&me->seqn, me->n_threads);
|
||||
|
||||
// de-initializations
|
||||
for (unsigned int i = 0; i < me->n_threads; i++) {
|
||||
if (me->thread[i]) {
|
||||
int status;
|
||||
(void) qurt_thread_join(me->thread[i], &status);
|
||||
}
|
||||
}
|
||||
|
||||
// free allocated memory (were allocated as a single buffer starting at stack[0])
|
||||
if (me->stack[0]) {
|
||||
free(me->stack[0]);
|
||||
}
|
||||
|
||||
*context = NULL;
|
||||
}
|
||||
|
||||
// run jobs
|
||||
AEEResult worker_pool_run_jobs(worker_pool_context_t context, worker_pool_job_t * job, unsigned int n) {
|
||||
worker_pool_t * me = (worker_pool_t *) context;
|
||||
if (NULL == me) {
|
||||
FARF(ERROR, "worker-pool: invalid context");
|
||||
return AEE_EBADPARM;
|
||||
}
|
||||
|
||||
if (n > me->n_threads) {
|
||||
FARF(ERROR, "worker-pool: invalid number of jobs %u for n-threads %u", n, me->n_threads);
|
||||
return AEE_EBADPARM;
|
||||
}
|
||||
|
||||
memcpy(me->job, job, sizeof(worker_pool_job_t) * n);
|
||||
|
||||
if (n > 1) {
|
||||
atomic_store(&me->next_job, 1);
|
||||
atomic_store(&me->n_jobs, n);
|
||||
atomic_store(&me->n_pending, n - 1);
|
||||
|
||||
// wake up workers
|
||||
atomic_fetch_add(&me->seqn, 1);
|
||||
qurt_futex_wake(&me->seqn, n - 1);
|
||||
}
|
||||
|
||||
// main thread runs job #0
|
||||
me->job[0].func(n, 0, me->job[0].data);
|
||||
|
||||
if (n > 1) {
|
||||
while (atomic_load(&me->n_pending))
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// run func
|
||||
AEEResult worker_pool_run_func(worker_pool_context_t context, worker_callback_t func, void * data, unsigned int n) {
|
||||
worker_pool_job_t job[n];
|
||||
|
||||
for (unsigned int i = 0; i < n; i++) {
|
||||
job[i].func = func;
|
||||
job[i].data = data;
|
||||
}
|
||||
|
||||
return worker_pool_run_jobs(context, job, n);
|
||||
}
|
||||
|
||||
AEEResult worker_pool_set_thread_priority(worker_pool_context_t context, unsigned int prio) {
|
||||
worker_pool_t * me = (worker_pool_t *) context;
|
||||
|
||||
// if no worker pool exists, return error.
|
||||
if (!me) {
|
||||
return AEE_ENOMORE;
|
||||
}
|
||||
|
||||
int result = AEE_SUCCESS;
|
||||
if (prio < 1) {
|
||||
prio = 1;
|
||||
}
|
||||
if (prio > LOWEST_USABLE_QURT_PRIO) {
|
||||
prio = LOWEST_USABLE_QURT_PRIO;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < me->n_threads; i++) {
|
||||
int res = qurt_thread_set_priority(me->thread[i], (unsigned short) prio);
|
||||
if (0 != res) {
|
||||
result = AEE_EBADPARM;
|
||||
FARF(ERROR, "QURT failed to set priority of thread %d, ERROR = %d", me->thread[i], res);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
AEEResult worker_pool_retrieve_thread_id(worker_pool_context_t context, unsigned int * tids) {
|
||||
worker_pool_t * me = (worker_pool_t *) context;
|
||||
if (!me) {
|
||||
FARF(ERROR, "worker-pool: invalid context");
|
||||
return AEE_EBADPARM;
|
||||
;
|
||||
}
|
||||
|
||||
for (int i = 0; i < me->n_threads; i++) {
|
||||
tids[i] = me->thread[i];
|
||||
}
|
||||
|
||||
return AEE_SUCCESS;
|
||||
}
|
||||
|
||||
AEEResult worker_pool_get_thread_priority(worker_pool_context_t context, unsigned int * prio) {
|
||||
worker_pool_t * me = (worker_pool_t *) context;
|
||||
if (!me) {
|
||||
FARF(ERROR, "worker-pool: invalid context");
|
||||
return AEE_EBADPARM;
|
||||
}
|
||||
|
||||
int priority = qurt_thread_get_priority(me->thread[0]);
|
||||
if (priority > 0) {
|
||||
*prio = priority;
|
||||
return 0;
|
||||
} else {
|
||||
*prio = 0;
|
||||
return AEE_EBADSTATE;
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
#ifndef HTP_WORKER_POOL_H
|
||||
#define HTP_WORKER_POOL_H
|
||||
|
||||
// MACRO enables function to be visible in shared-library case.
|
||||
#define WORKERPOOL_API __attribute__((visibility("default")))
|
||||
|
||||
#include <AEEStdDef.h>
|
||||
#include <AEEStdErr.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/// signature of callbacks to be invoked by worker threads
|
||||
typedef void (*worker_callback_t)(unsigned int n, unsigned int i, void *);
|
||||
|
||||
/// Typedef of worker_pool context
|
||||
typedef void * worker_pool_context_t;
|
||||
|
||||
/// descriptor for requested callback
|
||||
typedef struct {
|
||||
worker_callback_t func;
|
||||
void * data;
|
||||
} worker_pool_job_t;
|
||||
|
||||
#define WORKER_THREAD_STACK_SZ (2 * 16384)
|
||||
|
||||
/// Maximum supported number of worker threads.
|
||||
#define MAX_NUM_WORKERS 10
|
||||
|
||||
#if __HVX_ARCH__ > 79
|
||||
#define WORKER_POOL_POLL_COUNT 2000
|
||||
#else
|
||||
#define WORKER_POOL_POLL_COUNT 1
|
||||
#endif
|
||||
|
||||
// Initialize worker pool.
|
||||
WORKERPOOL_API AEEResult worker_pool_init(worker_pool_context_t * context, uint32_t n_threads);
|
||||
|
||||
// Initialize worker pool with custom stack size
|
||||
WORKERPOOL_API AEEResult worker_pool_init_with_stack_size(worker_pool_context_t * context,
|
||||
uint32_t n_threads,
|
||||
uint32_t stack_size);
|
||||
|
||||
// Kill worker threads and release worker pool resources
|
||||
WORKERPOOL_API void worker_pool_release(worker_pool_context_t * context);
|
||||
|
||||
// Run jobs with the worker pool.
|
||||
WORKERPOOL_API AEEResult worker_pool_run_jobs(worker_pool_context_t context, worker_pool_job_t * job, unsigned int n);
|
||||
|
||||
WORKERPOOL_API AEEResult worker_pool_run_func(worker_pool_context_t context,
|
||||
worker_callback_t func,
|
||||
void * data,
|
||||
unsigned int n);
|
||||
|
||||
WORKERPOOL_API AEEResult worker_pool_set_thread_priority(worker_pool_context_t context, unsigned int prio);
|
||||
WORKERPOOL_API AEEResult worker_pool_get_thread_priority(worker_pool_context_t context, unsigned int * prio);
|
||||
WORKERPOOL_API AEEResult worker_pool_retrieve_thread_id(worker_pool_context_t context, unsigned int * tids);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // #ifndef HTP_WORKER_POOL_H
|
||||
@@ -211,6 +211,7 @@ set(GGML_OPENCL_KERNELS
|
||||
tanh
|
||||
exp
|
||||
expm1
|
||||
abs
|
||||
softplus
|
||||
pad
|
||||
repeat
|
||||
|
||||
@@ -264,7 +264,8 @@ static ADRENO_GPU_GEN get_adreno_gpu_gen(const char *device_name) {
|
||||
return ADRENO_GPU_GEN::A7X;
|
||||
}
|
||||
|
||||
if (strstr(device_name, "830") ||
|
||||
if (strstr(device_name, "810") ||
|
||||
strstr(device_name, "830") ||
|
||||
strstr(device_name, "840") ||
|
||||
strstr(device_name, "850")) {
|
||||
return ADRENO_GPU_GEN::A8X;
|
||||
@@ -844,6 +845,8 @@ struct ggml_backend_opencl_context {
|
||||
cl_kernel kernel_exp_f16, kernel_exp_f16_4, kernel_exp_f16_nc;
|
||||
cl_kernel kernel_expm1_f32, kernel_expm1_f32_4, kernel_expm1_f32_nc;
|
||||
cl_kernel kernel_expm1_f16, kernel_expm1_f16_4, kernel_expm1_f16_nc;
|
||||
cl_kernel kernel_abs_f32, kernel_abs_f32_4, kernel_abs_f32_nc;
|
||||
cl_kernel kernel_abs_f16, kernel_abs_f16_4, kernel_abs_f16_nc;
|
||||
cl_kernel kernel_softplus_f32, kernel_softplus_f32_4, kernel_softplus_f32_nc;
|
||||
cl_kernel kernel_softplus_f16, kernel_softplus_f16_4, kernel_softplus_f16_nc;
|
||||
cl_kernel kernel_upscale;
|
||||
@@ -873,7 +876,7 @@ struct ggml_backend_opencl_context {
|
||||
cl_kernel kernel_gemm_moe_q8_1_dp4a_q5k = nullptr; // generic dp4a MoE GEMM (MOE_QT=5, q5_K), opt-in
|
||||
cl_kernel kernel_moe_expand_scale_q5_K = nullptr; // q5_K 6-bit s[] -> uniform scale[16]/min[8]
|
||||
cl_kernel kernel_gemv_moe_q5_k_f32_ns, kernel_gemm_moe_q5_k_f32_ns;
|
||||
cl_kernel kernel_gemv_moe_q6_k_f32_ns, kernel_gemm_moe_q6_k_f32_ns;
|
||||
cl_kernel kernel_gemv_moe_q6_k_f32_ns, kernel_gemm_moe_q6_k_f32_ns, kernel_gemm_moe_q6_k_f32_ns_bin;
|
||||
cl_kernel kernel_gemm_moe_q6_k_q8_1_dp4a = nullptr; // dp4a (int8) q6_K MoE prefill GEMM
|
||||
cl_kernel kernel_gemv_moe_mxfp4_f32, kernel_gemm_moe_mxfp4_f32;
|
||||
cl_kernel kernel_gemv_moe_mxfp4_f32_ns, kernel_gemm_moe_mxfp4_f32_ns, kernel_gemm_moe_mxfp4_f32_ns_bin;
|
||||
@@ -2928,6 +2931,27 @@ static void load_cl_kernels(ggml_backend_opencl_context *backend_ctx) {
|
||||
GGML_LOG_CONT(".");
|
||||
}
|
||||
|
||||
// abs
|
||||
{
|
||||
#ifdef GGML_OPENCL_EMBED_KERNELS
|
||||
const std::string kernel_src {
|
||||
#include "abs.cl.h"
|
||||
};
|
||||
#else
|
||||
const std::string kernel_src = read_file("abs.cl");
|
||||
#endif
|
||||
cl_program prog =
|
||||
build_program_from_source(backend_ctx->context, backend_ctx->device, kernel_src.c_str(), compile_opts);
|
||||
CL_CHECK((backend_ctx->kernel_abs_f32 = clCreateKernel(prog, "kernel_abs_f32", &err), err));
|
||||
CL_CHECK((backend_ctx->kernel_abs_f32_4 = clCreateKernel(prog, "kernel_abs_f32_4", &err), err));
|
||||
CL_CHECK((backend_ctx->kernel_abs_f32_nc = clCreateKernel(prog, "kernel_abs_f32_nc", &err), err));
|
||||
CL_CHECK((backend_ctx->kernel_abs_f16 = clCreateKernel(prog, "kernel_abs_f16", &err), err));
|
||||
CL_CHECK((backend_ctx->kernel_abs_f16_4 = clCreateKernel(prog, "kernel_abs_f16_4", &err), err));
|
||||
CL_CHECK((backend_ctx->kernel_abs_f16_nc = clCreateKernel(prog, "kernel_abs_f16_nc", &err), err));
|
||||
CL_CHECK(clReleaseProgram(prog));
|
||||
GGML_LOG_CONT(".");
|
||||
}
|
||||
|
||||
// softplus
|
||||
{
|
||||
#ifdef GGML_OPENCL_EMBED_KERNELS
|
||||
@@ -4286,6 +4310,24 @@ static void load_cl_kernels(ggml_backend_opencl_context *backend_ctx) {
|
||||
GGML_LOG_CONT(".");
|
||||
}
|
||||
|
||||
// gemm_moe_q6_k_f32_ns_bin
|
||||
{
|
||||
size_t bin_size = 0;
|
||||
backend_ctx->kernel_gemm_moe_q6_k_f32_ns_bin = nullptr;
|
||||
|
||||
if (use_adreno_bin_kernels(backend_ctx)) {
|
||||
const char * kernel_bin = (const char *)backend_ctx->get_adreno_bin_kernel("gemm_moe_q6_k_f32_ns_ila", &bin_size);
|
||||
if (kernel_bin && bin_size > 0) {
|
||||
cl_program prog =
|
||||
build_program_from_binary(backend_ctx->context, backend_ctx->device, kernel_bin, CL_moe_compile_opts, bin_size);
|
||||
|
||||
CL_CHECK((backend_ctx->kernel_gemm_moe_q6_k_f32_ns_bin = clCreateKernel(prog, "kernel_gemm_moe_q6_k_f32_ns_ila", &err), err));
|
||||
CL_CHECK(clReleaseProgram(prog));
|
||||
GGML_LOG_CONT(".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gemm_moe_q6_k_q8_1_dp4a (dp4a q6_K MoE prefill GEMM)
|
||||
if (backend_ctx->has_integer_dot) {
|
||||
#ifdef GGML_OPENCL_EMBED_KERNELS
|
||||
@@ -5988,7 +6030,8 @@ static void transpose_2d(
|
||||
cl_kernel kernel,
|
||||
cl_mem src, cl_mem dst, size_t size,
|
||||
cl_int stride, cl_int rows,
|
||||
bool blocking = true
|
||||
bool blocking = true,
|
||||
bool auto_local = false // let driver pick local size for non-uniform workgroups
|
||||
) {
|
||||
static ggml_cl_buffer buf;
|
||||
|
||||
@@ -6014,7 +6057,7 @@ static void transpose_2d(
|
||||
size_t local_size[3] = {64, 1, 1};
|
||||
size_t global_size[3] = {(size_t)stride, (size_t)rows, 1};;
|
||||
CL_CHECK(clEnqueueNDRangeKernel(backend_ctx->queue, kernel, 3, NULL,
|
||||
global_size, local_size, 0, NULL, NULL));
|
||||
global_size, auto_local ? NULL : local_size, 0, NULL, NULL));
|
||||
|
||||
if (blocking) {
|
||||
CL_CHECK(clEnqueueCopyBuffer(backend_ctx->queue, trans, dst, 0, 0, size, 0, NULL, &evt));
|
||||
@@ -6031,10 +6074,11 @@ static void transpose_2d_as_8b(
|
||||
ggml_backend_opencl_context * backend_ctx,
|
||||
cl_mem src, cl_mem dst, size_t size,
|
||||
cl_int stride, cl_int rows,
|
||||
bool blocking = true
|
||||
bool blocking = true,
|
||||
bool auto_local = false
|
||||
) {
|
||||
transpose_2d(backend_ctx, backend_ctx->kernel_transpose_8_buf,
|
||||
src, dst, size, stride, rows, blocking);
|
||||
src, dst, size, stride, rows, blocking, auto_local);
|
||||
}
|
||||
|
||||
static void transpose_2d_as_16b(
|
||||
@@ -7152,6 +7196,8 @@ static bool ggml_opencl_supports_op(ggml_backend_dev_t dev, const struct ggml_te
|
||||
return op->src[0]->type == GGML_TYPE_F32;
|
||||
case GGML_UNARY_OP_EXPM1:
|
||||
return op->src[0]->type == GGML_TYPE_F32;
|
||||
case GGML_UNARY_OP_ABS:
|
||||
return op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16;
|
||||
case GGML_UNARY_OP_SOFTPLUS:
|
||||
return op->src[0]->type == GGML_TYPE_F32 || op->src[0]->type == GGML_TYPE_F16;
|
||||
default:
|
||||
@@ -9028,6 +9074,9 @@ static void ggml_backend_opencl_buffer_set_tensor(ggml_backend_buffer_t buffer,
|
||||
transpose_2d_as_16b(backend_ctx, extra->q, extra->q, size_q, K/4, M);
|
||||
transpose_2d_as_16b(backend_ctx, extra->d, extra->d, size_d, K/256, M);
|
||||
transpose_2d_as_16b(backend_ctx, extra->dm, extra->dm, size_dm, K/256, M);
|
||||
|
||||
// Transpose s as uchar
|
||||
transpose_2d_as_8b(backend_ctx, extra->s, extra->s, size_s, K/256*12, M, true, true);
|
||||
}
|
||||
#endif // GGML_OPENCL_USE_ADRENO_KERNELS
|
||||
return;
|
||||
@@ -10196,23 +10245,27 @@ static void ggml_backend_opencl_buffer_get_tensor(ggml_backend_buffer_t buffer,
|
||||
size_t size_q = ggml_nelements(tensor)/ggml_blck_size(tensor->type)*ggml_blck_size(tensor->type)/2;
|
||||
size_t size_d = ggml_nelements(tensor)/ggml_blck_size(tensor->type)*sizeof(ggml_fp16_t);
|
||||
size_t size_dm = ggml_nelements(tensor)/ggml_blck_size(tensor->type)*sizeof(ggml_fp16_t);
|
||||
size_t size_s = ggml_nelements(tensor)/ggml_blck_size(tensor->type)*12;
|
||||
|
||||
static ggml_cl_buffer buf_trans_q;
|
||||
static ggml_cl_buffer buf_trans_d;
|
||||
static ggml_cl_buffer buf_trans_dm;
|
||||
static ggml_cl_buffer buf_trans_s;
|
||||
|
||||
buf_trans_q.allocate(backend_ctx->context, size_q);
|
||||
buf_trans_d.allocate(backend_ctx->context, size_d);
|
||||
buf_trans_dm.allocate(backend_ctx->context, size_dm);
|
||||
buf_trans_s.allocate(backend_ctx->context, size_s);
|
||||
|
||||
// Transpose q, d, dm back
|
||||
// Transpose q, d, dm, s back
|
||||
transpose_2d_as_16b(backend_ctx, extra->q, buf_trans_q.buffer, size_q, M, K/4);
|
||||
transpose_2d_as_16b(backend_ctx, extra->d, buf_trans_d.buffer, size_d, M, K/256);
|
||||
transpose_2d_as_16b(backend_ctx, extra->dm, buf_trans_dm.buffer, size_dm, M, K/256);
|
||||
transpose_2d_as_8b (backend_ctx, extra->s, buf_trans_s.buffer, size_s, M, K/256*12, true, true);
|
||||
|
||||
cl_kernel kernel = backend_ctx->kernel_restore_block_q4_K_noshuffle;
|
||||
CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &buf_trans_q.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), &extra->s));
|
||||
CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), &buf_trans_s.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &buf_trans_d.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_mem), &buf_trans_dm.buffer));
|
||||
CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), &data_device));
|
||||
@@ -13386,6 +13439,102 @@ static void ggml_cl_expm1(ggml_backend_t backend, const ggml_tensor * src0, cons
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_cl_abs(ggml_backend_t backend, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
|
||||
GGML_ASSERT(src0);
|
||||
GGML_ASSERT(src0->extra);
|
||||
GGML_ASSERT(dst);
|
||||
GGML_ASSERT(dst->extra);
|
||||
|
||||
UNUSED(src1);
|
||||
|
||||
ggml_backend_opencl_context *backend_ctx = (ggml_backend_opencl_context *)backend->context;
|
||||
|
||||
ggml_tensor_extra_cl * extra0 = (ggml_tensor_extra_cl *)src0->extra;
|
||||
ggml_tensor_extra_cl * extrad = (ggml_tensor_extra_cl *)dst->extra;
|
||||
|
||||
cl_ulong offset0 = extra0->offset + src0->view_offs;
|
||||
cl_ulong offsetd = extrad->offset + dst->view_offs;
|
||||
|
||||
const int ne00 = src0->ne[0];
|
||||
const int ne01 = src0->ne[1];
|
||||
const int ne02 = src0->ne[2];
|
||||
const int ne03 = src0->ne[3];
|
||||
|
||||
const cl_ulong nb00 = src0->nb[0];
|
||||
const cl_ulong nb01 = src0->nb[1];
|
||||
const cl_ulong nb02 = src0->nb[2];
|
||||
const cl_ulong nb03 = src0->nb[3];
|
||||
|
||||
const cl_ulong nb0 = dst->nb[0];
|
||||
const cl_ulong nb1 = dst->nb[1];
|
||||
const cl_ulong nb2 = dst->nb[2];
|
||||
const cl_ulong nb3 = dst->nb[3];
|
||||
|
||||
cl_kernel kernel;
|
||||
|
||||
if (ggml_is_contiguous(src0)) {
|
||||
// Handle contiguous input
|
||||
int n = ggml_nelements(dst);
|
||||
if (n % 4 == 0) {
|
||||
if (src0->type == GGML_TYPE_F32) {
|
||||
kernel = backend_ctx->kernel_abs_f32_4;
|
||||
} else {
|
||||
kernel = backend_ctx->kernel_abs_f16_4;
|
||||
}
|
||||
n /= 4;
|
||||
} else {
|
||||
if (src0->type == GGML_TYPE_F32) {
|
||||
kernel = backend_ctx->kernel_abs_f32;
|
||||
} else {
|
||||
kernel = backend_ctx->kernel_abs_f16;
|
||||
}
|
||||
}
|
||||
|
||||
CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &extra0->data_device));
|
||||
CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_ulong), &offset0));
|
||||
CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &extrad->data_device));
|
||||
CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_ulong), &offsetd));
|
||||
|
||||
size_t global_work_size[] = {(size_t)n, 1, 1};
|
||||
size_t local_work_size[] = {64, 1, 1};
|
||||
|
||||
size_t * local_work_size_ptr = local_work_size;
|
||||
if (n % 64 != 0 && !backend_ctx->non_uniform_workgroups) {
|
||||
local_work_size_ptr = nullptr;
|
||||
}
|
||||
|
||||
backend_ctx->enqueue_ndrange_kernel(kernel, 3, global_work_size, local_work_size_ptr, dst);
|
||||
} else {
|
||||
// Handle non-contiguous input
|
||||
if (src0->type == GGML_TYPE_F32) {
|
||||
kernel = backend_ctx->kernel_abs_f32_nc;
|
||||
} else {
|
||||
kernel = backend_ctx->kernel_abs_f16_nc;
|
||||
}
|
||||
|
||||
CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &extra0->data_device));
|
||||
CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_ulong), &offset0));
|
||||
CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &extrad->data_device));
|
||||
CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_ulong), &offsetd));
|
||||
CL_CHECK(clSetKernelArg(kernel, 4, sizeof(int), &ne00));
|
||||
CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_ulong), &nb00));
|
||||
CL_CHECK(clSetKernelArg(kernel, 6, sizeof(cl_ulong), &nb01));
|
||||
CL_CHECK(clSetKernelArg(kernel, 7, sizeof(cl_ulong), &nb02));
|
||||
CL_CHECK(clSetKernelArg(kernel, 8, sizeof(cl_ulong), &nb03));
|
||||
CL_CHECK(clSetKernelArg(kernel, 9, sizeof(cl_ulong), &nb0));
|
||||
CL_CHECK(clSetKernelArg(kernel, 10, sizeof(cl_ulong), &nb1));
|
||||
CL_CHECK(clSetKernelArg(kernel, 11, sizeof(cl_ulong), &nb2));
|
||||
CL_CHECK(clSetKernelArg(kernel, 12, sizeof(cl_ulong), &nb3));
|
||||
|
||||
int nth = 64;
|
||||
|
||||
size_t global_work_size[] = {(size_t)ne01*nth, (size_t)ne02, (size_t)ne03};
|
||||
size_t local_work_size[] = {(size_t)nth, 1, 1};
|
||||
|
||||
backend_ctx->enqueue_ndrange_kernel(kernel, 3, global_work_size, local_work_size, dst);
|
||||
}
|
||||
}
|
||||
|
||||
static void ggml_cl_softplus(ggml_backend_t backend, const ggml_tensor * src0, const ggml_tensor * src1, ggml_tensor * dst) {
|
||||
GGML_ASSERT(src0);
|
||||
GGML_ASSERT(src0->extra);
|
||||
@@ -16936,9 +17085,6 @@ static void ggml_cl_mul_mat_q8_0_f32_adreno(ggml_backend_t backend, const ggml_t
|
||||
cl_ulong offset1 = extra1->offset + src1->view_offs;
|
||||
cl_ulong offsetd = extrad->offset + dst->view_offs;
|
||||
|
||||
GGML_ASSERT(src1->view_offs == 0);
|
||||
GGML_ASSERT(dst->view_offs == 0);
|
||||
|
||||
const int ne00 = src0->ne[0];
|
||||
const int ne01 = src0->ne[1];
|
||||
const int ne02 = src0->ne[2];
|
||||
@@ -16999,9 +17145,9 @@ static void ggml_cl_mul_mat_q8_0_f32_adreno(ggml_backend_t backend, const ggml_t
|
||||
CL_CHECK(clSetKernelArg(kernel, 0, sizeof(cl_mem), &q_img));
|
||||
CL_CHECK(clSetKernelArg(kernel, 1, sizeof(cl_mem), &extra0_q8_0->d));
|
||||
CL_CHECK(clSetKernelArg(kernel, 2, sizeof(cl_mem), &b_img));
|
||||
CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_ulong), &extra1->offset));
|
||||
CL_CHECK(clSetKernelArg(kernel, 3, sizeof(cl_ulong), &offset1));
|
||||
CL_CHECK(clSetKernelArg(kernel, 4, sizeof(cl_mem), &extrad->data_device));
|
||||
CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_ulong), &extrad->offset));
|
||||
CL_CHECK(clSetKernelArg(kernel, 5, sizeof(cl_ulong), &offsetd));
|
||||
CL_CHECK(clSetKernelArg(kernel, 6, sizeof(int), &ne00));
|
||||
CL_CHECK(clSetKernelArg(kernel, 7, sizeof(int), &ne01));
|
||||
CL_CHECK(clSetKernelArg(kernel, 8, sizeof(int), &ne02));
|
||||
@@ -18396,6 +18542,26 @@ static void ggml_cl_mul_mat(ggml_backend_t backend, const ggml_tensor * src0, co
|
||||
|
||||
GGML_ASSERT(ne00 == ne10);
|
||||
|
||||
#ifdef GGML_OPENCL_USE_ADRENO_KERNELS
|
||||
// adreno GEMM/GEMV kernels do not support broadcast, assuming ne2 and ne3 are 1 for src1
|
||||
// so we handle broadcast here
|
||||
if ((ne12 > 1 || ne13 > 1) && ne02 == 1 && ne03 == 1 &&
|
||||
src0t != GGML_TYPE_F16 && src0t != GGML_TYPE_F32) {
|
||||
for (int i13 = 0; i13 < ne13; ++i13) {
|
||||
for (int i12 = 0; i12 < ne12; ++i12) {
|
||||
ggml_tensor s1 = *src1;
|
||||
s1.ne[2] = 1; s1.ne[3] = 1;
|
||||
s1.view_offs = src1->view_offs + (size_t)i12*nb12 + (size_t)i13*nb13;
|
||||
ggml_tensor d = *dst;
|
||||
d.ne[2] = 1; d.ne[3] = 1;
|
||||
d.view_offs = dst->view_offs + (size_t)i12*nb2 + (size_t)i13*nb3;
|
||||
ggml_cl_mul_mat(backend, src0, &s1, &d);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
int nth0 = 32;
|
||||
int nth1 = 1;
|
||||
int nrows = 1;
|
||||
@@ -22160,8 +22326,8 @@ static void ggml_cl_mul_mat_id(ggml_backend_t backend, const ggml_tensor * src0,
|
||||
bool use_moe_dp4a = q5kmdp4a_on
|
||||
&& backend_ctx->kernel_gemm_moe_q8_1_dp4a_q5k != nullptr
|
||||
&& extra0_q5_K->scale != nullptr;
|
||||
// bin kernel takes precedence
|
||||
use_moe_dp4a = use_moe_dp4a && backend_ctx->kernel_gemm_moe_q4_k_f32_ns_bin == nullptr;
|
||||
// dot prod has to be available
|
||||
use_moe_dp4a = backend_ctx->has_integer_dot && use_moe_dp4a;
|
||||
|
||||
if (use_moe_dp4a) {
|
||||
const size_t tok_slots = (size_t)max_post_router_tile * n_tile_size;
|
||||
@@ -22379,6 +22545,9 @@ static void ggml_cl_mul_mat_id(ggml_backend_t backend, const ggml_tensor * src0,
|
||||
|
||||
} else { // for gemm
|
||||
kernel = backend_ctx->kernel_gemm_moe_q6_k_f32_ns;
|
||||
if (backend_ctx->kernel_gemm_moe_q6_k_f32_ns_bin) {
|
||||
kernel = backend_ctx->kernel_gemm_moe_q6_k_f32_ns_bin;
|
||||
}
|
||||
|
||||
// Reorder router if called from test-backend-ops or when new router is generated.
|
||||
// Otherwise reuse the reordered result from previous mul_mat_id call.
|
||||
@@ -22399,6 +22568,8 @@ static void ggml_cl_mul_mat_id(ggml_backend_t backend, const ggml_tensor * src0,
|
||||
|| backend_ctx->adreno_gen == ADRENO_GPU_GEN::X1E);
|
||||
// dot prod has to be available
|
||||
use_moe_dp4a = backend_ctx->has_integer_dot && use_moe_dp4a;
|
||||
// bin kernel takes precedence
|
||||
use_moe_dp4a = use_moe_dp4a && backend_ctx->kernel_gemm_moe_q6_k_f32_ns_bin == nullptr;
|
||||
|
||||
cl_buffer_region region;
|
||||
region.origin = 0;
|
||||
@@ -22435,6 +22606,11 @@ static void ggml_cl_mul_mat_id(ggml_backend_t backend, const ggml_tensor * src0,
|
||||
CL_CHECK(status);
|
||||
cl_image_format image_format_buf_src1 = {CL_RGBA, CL_FLOAT};
|
||||
cl_image_desc image_desc_buf_src1 = {CL_MEM_OBJECT_IMAGE1D_BUFFER, static_cast<size_t>(ne00 * max_post_router_tile * n_tile_size / 4), 0,0,0,0,0,0,0, {buf_src1_reordered}};
|
||||
if (backend_ctx->kernel_gemm_moe_q6_k_f32_ns_bin) {
|
||||
// bin kernel uses slightly different image format
|
||||
image_format_buf_src1 = {CL_R, CL_FLOAT};
|
||||
image_desc_buf_src1.image_width = static_cast<size_t>(ne00 * max_post_router_tile * n_tile_size);
|
||||
}
|
||||
image_src1_reordered = clCreateImage(backend_ctx->context, CL_MEM_READ_ONLY, &image_format_buf_src1, &image_desc_buf_src1, NULL, &status);
|
||||
CL_CHECK(status);
|
||||
|
||||
@@ -24407,6 +24583,12 @@ bool ggml_cl_compute_forward(ggml_backend_t backend, struct ggml_tensor * tensor
|
||||
}
|
||||
func = ggml_cl_expm1;
|
||||
break;
|
||||
case GGML_UNARY_OP_ABS:
|
||||
if (!any_on_device) {
|
||||
return false;
|
||||
}
|
||||
func = ggml_cl_abs;
|
||||
break;
|
||||
case GGML_UNARY_OP_SOFTPLUS:
|
||||
if (!any_on_device) {
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// abs
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
kernel void kernel_abs_f32(
|
||||
global const float * src0,
|
||||
ulong offset0,
|
||||
global float * dst,
|
||||
ulong offsetd
|
||||
) {
|
||||
src0 = (global float*)((global char*)src0 + offset0);
|
||||
dst = (global float*)((global char*)dst + offsetd);
|
||||
|
||||
dst[get_global_id(0)] = fabs(src0[get_global_id(0)]);
|
||||
}
|
||||
|
||||
kernel void kernel_abs_f32_4(
|
||||
global const float4 * src0,
|
||||
ulong offset0,
|
||||
global float4 * dst,
|
||||
ulong offsetd
|
||||
) {
|
||||
src0 = (global float4*)((global char*)src0 + offset0);
|
||||
dst = (global float4*)((global char*)dst + offsetd);
|
||||
|
||||
dst[get_global_id(0)] = fabs(src0[get_global_id(0)]);
|
||||
}
|
||||
|
||||
kernel void kernel_abs_f16(
|
||||
global const half * src0,
|
||||
ulong offset0,
|
||||
global half * dst,
|
||||
ulong offsetd
|
||||
) {
|
||||
src0 = (global half*)((global char*)src0 + offset0);
|
||||
dst = (global half*)((global char*)dst + offsetd);
|
||||
|
||||
dst[get_global_id(0)] = fabs(src0[get_global_id(0)]);
|
||||
}
|
||||
|
||||
kernel void kernel_abs_f16_4(
|
||||
global const half4 * src0,
|
||||
ulong offset0,
|
||||
global half4 * dst,
|
||||
ulong offsetd
|
||||
) {
|
||||
src0 = (global half4*)((global char*)src0 + offset0);
|
||||
dst = (global half4*)((global char*)dst + offsetd);
|
||||
|
||||
dst[get_global_id(0)] = fabs(src0[get_global_id(0)]);
|
||||
}
|
||||
|
||||
kernel void kernel_abs_f32_nc(
|
||||
global const char * src0,
|
||||
ulong offset0,
|
||||
global char * dst,
|
||||
ulong offsetd,
|
||||
int ne00,
|
||||
ulong nb00,
|
||||
ulong nb01,
|
||||
ulong nb02,
|
||||
ulong nb03,
|
||||
ulong nb0,
|
||||
ulong nb1,
|
||||
ulong nb2,
|
||||
ulong nb3
|
||||
) {
|
||||
src0 = src0 + offset0;
|
||||
dst = dst + offsetd;
|
||||
|
||||
const int i3 = get_group_id(2);
|
||||
const int i2 = get_group_id(1);
|
||||
const int i1 = get_group_id(0);
|
||||
|
||||
for (int i0 = get_local_id(0); i0 < ne00; i0 += get_local_size(0)) {
|
||||
global const float * x = (global const float *)(src0 + i3*nb03 + i2*nb02 + i1*nb01 + i0*nb00);
|
||||
global float * y = (global float *)(dst + i3*nb3 + i2*nb2 + i1*nb1 + i0*nb0);
|
||||
|
||||
*y = fabs(*x);
|
||||
}
|
||||
}
|
||||
|
||||
kernel void kernel_abs_f16_nc(
|
||||
global const char * src0,
|
||||
ulong offset0,
|
||||
global char * dst,
|
||||
ulong offsetd,
|
||||
int ne00,
|
||||
ulong nb00,
|
||||
ulong nb01,
|
||||
ulong nb02,
|
||||
ulong nb03,
|
||||
ulong nb0,
|
||||
ulong nb1,
|
||||
ulong nb2,
|
||||
ulong nb3
|
||||
) {
|
||||
src0 = src0 + offset0;
|
||||
dst = dst + offsetd;
|
||||
|
||||
const int i3 = get_group_id(2);
|
||||
const int i2 = get_group_id(1);
|
||||
const int i1 = get_group_id(0);
|
||||
|
||||
for (int i0 = get_local_id(0); i0 < ne00; i0 += get_local_size(0)) {
|
||||
global const half * x = (global const half *)(src0 + i3*nb03 + i2*nb02 + i1*nb01 + i0*nb00);
|
||||
global half * y = (global half *)(dst + i3*nb3 + i2*nb2 + i1*nb1 + i0*nb0);
|
||||
|
||||
*y = fabs(*x);
|
||||
}
|
||||
}
|
||||
@@ -37,15 +37,17 @@ static inline float e8m0_to_fp32(uchar x) {
|
||||
// One token's dp4a dot (8 uints = 32 K elems) + mxfp4 block-scale epilogue.
|
||||
// blk_scale already carries the 0.5 factor (== 0.5 * 2^e).
|
||||
#define MOE_MXFP4_DP4A_T(t) do { \
|
||||
uint4 a0 = vload4(0, &sh_qa[t][0]); \
|
||||
uint4 a1 = vload4(0, &sh_qa[t][4]); \
|
||||
int raw = 0; \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[0], a0.s0, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[1], a0.s1, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[2], a0.s2, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[3], a0.s3, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[4], a1.s0, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[5], a1.s1, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[6], a1.s2, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[7], a1.s3, raw); \
|
||||
acc[t] += blk_scale * (float)sh_d[t] * (float)raw; \
|
||||
} while (0)
|
||||
|
||||
@@ -133,11 +135,13 @@ kernel void kernel_gemm_moe_mxfp4_q8_1_dp4a(
|
||||
qw[6] = mxfp4_pack((ushort)(r3)); qw[7] = mxfp4_pack((ushort)(r3 >> 16));
|
||||
|
||||
// cooperatively stage the n_real-token x 32-K int8 activations
|
||||
const uint stage_lim = (uint)n_real * 8;
|
||||
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
||||
const uint t = idx >> 3;
|
||||
const uint u = idx & 7;
|
||||
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
||||
// Stage each token's 8 activation uints as two 128-bit uint4 loads/stores.
|
||||
const uint vlim = (uint)n_real * 2;
|
||||
for (uint idx = lid; idx < vlim; idx += 64) {
|
||||
const uint t = idx >> 1;
|
||||
const uint h = (idx & 1) << 2; // 0 or 4
|
||||
uint4 v = vload4(0, &src1_qa[(col + t) * ne00_u + (step >> 2) + h]);
|
||||
vstore4(v, 0, &sh_qa[t][h]);
|
||||
}
|
||||
if (lid < (uint)n_real) {
|
||||
sh_d[lid] = src1_da[(col + lid) * num_blocks + sub];
|
||||
|
||||
@@ -17,15 +17,17 @@
|
||||
|
||||
// One token's dp4a dot (8 uints = 32 K elems) + q4_0 scale/zero-point epilogue.
|
||||
#define MOE_Q40_DP4A_T(t) do { \
|
||||
uint4 a0 = vload4(0, &sh_qa[t][0]); \
|
||||
uint4 a1 = vload4(0, &sh_qa[t][4]); \
|
||||
int raw = 0; \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[0], a0.s0, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[1], a0.s1, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[2], a0.s2, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[3], a0.s3, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[4], a1.s0, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[5], a1.s1, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[6], a1.s2, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[7], a1.s3, raw); \
|
||||
acc[t] += d_val * ((float)sh_d[t] * (float)raw - 8.0f * (float)sh_s[t]); \
|
||||
} while (0)
|
||||
|
||||
@@ -112,11 +114,13 @@ kernel void kernel_gemm_moe_q4_0_q8_1_dp4a(
|
||||
qw[6] = EXP4(r3); qw[7] = EXP4(r3 >> 16);
|
||||
|
||||
// cooperatively stage the n_real-token x 32-K int8 activations
|
||||
const uint stage_lim = (uint)n_real * 8;
|
||||
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
||||
const uint t = idx >> 3;
|
||||
const uint u = idx & 7;
|
||||
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
||||
// Stage each token's 8 activation uints as two 128-bit uint4 loads/stores.
|
||||
const uint vlim = (uint)n_real * 2;
|
||||
for (uint idx = lid; idx < vlim; idx += 64) {
|
||||
const uint t = idx >> 1;
|
||||
const uint h = (idx & 1) << 2; // 0 or 4
|
||||
uint4 v = vload4(0, &src1_qa[(col + t) * ne00_u + (step >> 2) + h]);
|
||||
vstore4(v, 0, &sh_qa[t][h]);
|
||||
}
|
||||
if (lid < (uint)n_real) {
|
||||
sh_d[lid] = src1_da[(col + lid) * num_blocks + sub];
|
||||
|
||||
@@ -37,16 +37,21 @@ inline void get_scale_min_k4(
|
||||
(((uint)((u) & 0xF000u)) << 12) )
|
||||
|
||||
// One token's dp4a dot (8 uints = 32 K elems) + q4_K scale/min epilogue into acc[t].
|
||||
// The 8 activation uints are read as two 128-bit uint4 loads staged to private (Adreno
|
||||
// wants 128-bit local reads, and a __local operand fed straight to the dp4a builtin is
|
||||
// slower and can miscompile).
|
||||
#define MOE_Q4K_DP4A_T(t) do { \
|
||||
uint4 a0 = vload4(0, &sh_qa[t][0]); \
|
||||
uint4 a1 = vload4(0, &sh_qa[t][4]); \
|
||||
int raw = 0; \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[0], sh_qa[t][0], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[1], sh_qa[t][1], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[2], sh_qa[t][2], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[3], sh_qa[t][3], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[4], sh_qa[t][4], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[5], sh_qa[t][5], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[6], sh_qa[t][6], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[7], sh_qa[t][7], raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[0], a0.s0, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[1], a0.s1, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[2], a0.s2, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[3], a0.s3, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[4], a1.s0, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[5], a1.s1, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[6], a1.s2, raw); \
|
||||
raw = dot_acc_sat_4x8packed_ss_int(qw[7], a1.s3, raw); \
|
||||
acc[t] += scale * (float)sh_d[t] * (float)raw - minv * (float)sh_s[t]; \
|
||||
} while (0)
|
||||
|
||||
@@ -145,12 +150,14 @@ kernel void kernel_gemm_moe_q4_k_q8_1_dp4a(
|
||||
qw[4] = EXP4(r2); qw[5] = EXP4(r2 >> 16);
|
||||
qw[6] = EXP4(r3); qw[7] = EXP4(r3 >> 16);
|
||||
|
||||
// --- cooperatively stage the n_real-token x 32-K int8 activations to LDS ---
|
||||
const uint stage_lim = (uint)n_real * 8;
|
||||
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
||||
const uint t = idx >> 3;
|
||||
const uint u = idx & 7;
|
||||
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
||||
// cooperatively stage the n_real-token x 32-K int8 activations to lm
|
||||
// Stage each token's 8 activation uints as two 128-bit uint4 loads/stores.
|
||||
const uint vlim = (uint)n_real * 2;
|
||||
for (uint idx = lid; idx < vlim; idx += 64) {
|
||||
const uint t = idx >> 1;
|
||||
const uint h = (idx & 1) << 2; // 0 or 4
|
||||
uint4 v = vload4(0, &src1_qa[(col + t) * ne00_u + (step >> 2) + h]);
|
||||
vstore4(v, 0, &sh_qa[t][h]);
|
||||
}
|
||||
if (lid < (uint)n_real) {
|
||||
sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
|
||||
|
||||
@@ -41,8 +41,10 @@ inline int dp4a_q6(uint qw0, uint qw1, uint qw2, uint qw3,
|
||||
|
||||
// One token's q6_K dp4a dot (two halves, per-16 scales) + epilogue into acc[t].
|
||||
#define MOE_Q6K_DP4A_T(t) do { \
|
||||
const int raw1 = dp4a_q6(qw[0], qw[1], qw[2], qw[3], sh_qa[t][0], sh_qa[t][1], sh_qa[t][2], sh_qa[t][3]); \
|
||||
const int raw2 = dp4a_q6(qw[4], qw[5], qw[6], qw[7], sh_qa[t][4], sh_qa[t][5], sh_qa[t][6], sh_qa[t][7]); \
|
||||
uint4 a0 = vload4(0, &sh_qa[t][0]); \
|
||||
uint4 a1 = vload4(0, &sh_qa[t][4]); \
|
||||
const int raw1 = dp4a_q6(qw[0], qw[1], qw[2], qw[3], a0.s0, a0.s1, a0.s2, a0.s3); \
|
||||
const int raw2 = dp4a_q6(qw[4], qw[5], qw[6], qw[7], a1.s0, a1.s1, a1.s2, a1.s3); \
|
||||
const float a_d = (float)sh_d[t]; \
|
||||
acc[t] += scale0 * a_d * (float)raw1 + scale1 * a_d * (float)raw2; \
|
||||
} while (0)
|
||||
@@ -144,11 +146,13 @@ kernel void kernel_gemm_moe_q6_k_q8_1_dp4a(
|
||||
qw[6] = SIGN6(EXP4(r3) | EXP2((qh2 >> 16) & 0xFFu));
|
||||
qw[7] = SIGN6(EXP4(r3 >> 16) | EXP2((qh2 >> 24) & 0xFFu));
|
||||
|
||||
const uint stage_lim = (uint)n_real * 8;
|
||||
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
||||
const uint t = idx >> 3;
|
||||
const uint u = idx & 7;
|
||||
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
||||
// Stage each token's 8 activation uints as two 128-bit uint4 loads/stores.
|
||||
const uint vlim = (uint)n_real * 2;
|
||||
for (uint idx = lid; idx < vlim; idx += 64) {
|
||||
const uint t = idx >> 1;
|
||||
const uint h = (idx & 1) << 2; // 0 or 4
|
||||
uint4 v = vload4(0, &src1_qa[(col + t) * ne00_u + (step >> 2) + h]);
|
||||
vstore4(v, 0, &sh_qa[t][h]);
|
||||
}
|
||||
if (lid < (uint)n_real) {
|
||||
sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
|
||||
|
||||
@@ -102,8 +102,10 @@ inline int dp4a4(uint w0,uint w1,uint w2,uint w3,uint a0,uint a1,uint a2,uint a3
|
||||
|
||||
// One token's two-half dp4a + uniform scale/min epilogue into acc[t].
|
||||
#define MOE_DP4A_T(t) do { \
|
||||
const int raw1 = dp4a4(qw[0],qw[1],qw[2],qw[3], sh_qa[t][0],sh_qa[t][1],sh_qa[t][2],sh_qa[t][3]); \
|
||||
const int raw2 = dp4a4(qw[4],qw[5],qw[6],qw[7], sh_qa[t][4],sh_qa[t][5],sh_qa[t][6],sh_qa[t][7]); \
|
||||
uint4 a0 = vload4(0, &sh_qa[t][0]); \
|
||||
uint4 a1 = vload4(0, &sh_qa[t][4]); \
|
||||
const int raw1 = dp4a4(qw[0],qw[1],qw[2],qw[3], a0.s0,a0.s1,a0.s2,a0.s3); \
|
||||
const int raw2 = dp4a4(qw[4],qw[5],qw[6],qw[7], a1.s0,a1.s1,a1.s2,a1.s3); \
|
||||
const float a_d = (float)sh_d[t]; \
|
||||
acc[t] += sc0*a_d*(float)raw1 + sc1*a_d*(float)raw2 - mn*(float)sh_s[t]; \
|
||||
} while (0)
|
||||
@@ -178,10 +180,13 @@ kernel void kernel_gemm_moe_q8_1_dp4a(
|
||||
|
||||
LOAD_QW(step, sub)
|
||||
|
||||
const uint stage_lim = (uint)n_real * 8;
|
||||
for (uint idx = lid; idx < stage_lim; idx += 64) {
|
||||
const uint t = idx >> 3, u = idx & 7;
|
||||
sh_qa[t][u] = src1_qa[(col + t) * ne00_u + (step >> 2) + u];
|
||||
// Stage each token's 8 activation uints as two 128-bit uint4 loads/stores.
|
||||
const uint vlim = (uint)n_real * 2;
|
||||
for (uint idx = lid; idx < vlim; idx += 64) {
|
||||
const uint t = idx >> 1;
|
||||
const uint h = (idx & 1) << 2; // 0 or 4
|
||||
uint4 v = vload4(0, &src1_qa[(col + t) * ne00_u + (step >> 2) + h]);
|
||||
vstore4(v, 0, &sh_qa[t][h]);
|
||||
}
|
||||
if (lid < (uint)n_real) {
|
||||
sh_d[lid] = src1_da[(col + lid) * ne00_b + sub];
|
||||
|
||||
@@ -8,9 +8,11 @@
|
||||
#define QK_K 256
|
||||
#define K_SCALE_SIZE 12
|
||||
|
||||
// scales are transposed: consecutive codes of a row are `stride` apart
|
||||
inline void get_scale_min_k4(
|
||||
int j,
|
||||
global const uchar * q,
|
||||
int stride,
|
||||
uchar * d,
|
||||
uchar * m,
|
||||
uchar mask_d6,
|
||||
@@ -18,11 +20,11 @@ inline void get_scale_min_k4(
|
||||
uchar mask_hi2
|
||||
) {
|
||||
if (j < 4) {
|
||||
*d = q[j] & mask_d6;
|
||||
*m = q[j+4] & mask_d6;
|
||||
*d = q[j*stride] & mask_d6;
|
||||
*m = q[(j+4)*stride] & mask_d6;
|
||||
} else {
|
||||
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
||||
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
||||
*d = (q[(j+4)*stride] & mask_d4) | ((q[(j-4)*stride] & mask_hi2) >> 2);
|
||||
*m = ((q[(j+4)*stride] >> 4) & mask_d4) | ((q[j*stride] & mask_hi2) >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +57,6 @@ kernel void kernel_gemm_noshuffle_q4_k_f32(
|
||||
half8 B;
|
||||
half4 dequantized_weights;
|
||||
|
||||
int num_blocks_K = k / QK_K;
|
||||
|
||||
global const ushort * weight_ptr = src0_q + gx_2;
|
||||
global const half * d_ptr = src0_d + gx_2;
|
||||
@@ -68,16 +69,16 @@ kernel void kernel_gemm_noshuffle_q4_k_f32(
|
||||
half4 d = vload4(0, d_ptr + sb_idx * m);
|
||||
half4 dm = vload4(0, dm_ptr + sb_idx * m);
|
||||
|
||||
global const uchar * sc0 = src0_s + (gx_2+0) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
||||
global const uchar * sc1 = src0_s + (gx_2+1) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
||||
global const uchar * sc2 = src0_s + (gx_2+2) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
||||
global const uchar * sc3 = src0_s + (gx_2+3) * num_blocks_K * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
||||
global const uchar * sc0 = src0_s + sb_idx * K_SCALE_SIZE * m + (gx_2+0);
|
||||
global const uchar * sc1 = sc0 + 1;
|
||||
global const uchar * sc2 = sc0 + 2;
|
||||
global const uchar * sc3 = sc0 + 3;
|
||||
|
||||
uchar sv0, mn0, sv1, mn1, sv2, mn2, sv3, mn3;
|
||||
get_scale_min_k4(sub_idx, sc0, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc1, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc2, &sv2, &mn2, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc3, &sv3, &mn3, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc0, m, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc1, m, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc2, m, &sv2, &mn2, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc3, m, &sv3, &mn3, mask_d6, mask_d4, mask_hi2);
|
||||
|
||||
half4 scale = convert_half4(convert_float4(d) * convert_float4((uchar4)(sv0, sv1, sv2, sv3)));
|
||||
half4 mval = convert_half4(convert_float4(dm) * convert_float4((uchar4)(mn0, mn1, mn2, mn3)));
|
||||
|
||||
@@ -10,9 +10,11 @@
|
||||
#define QK_K 256
|
||||
#define K_SCALE_SIZE 12
|
||||
|
||||
// scales are transposed: consecutive codes of a row are `stride` apart
|
||||
inline void get_scale_min_k4(
|
||||
int j,
|
||||
global const uchar * q,
|
||||
uint stride,
|
||||
uchar * d,
|
||||
uchar * m,
|
||||
uchar mask_d6,
|
||||
@@ -20,11 +22,11 @@ inline void get_scale_min_k4(
|
||||
uchar mask_hi2
|
||||
) {
|
||||
if (j < 4) {
|
||||
*d = q[j] & mask_d6;
|
||||
*m = q[j+4] & mask_d6;
|
||||
*d = q[j*stride] & mask_d6;
|
||||
*m = q[(j+4)*stride] & mask_d6;
|
||||
} else {
|
||||
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
||||
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
||||
*d = (q[(j+4)*stride] & mask_d4) | ((q[(j-4)*stride] & mask_hi2) >> 2);
|
||||
*m = ((q[(j+4)*stride] >> 4) & mask_d4) | ((q[j*stride] & mask_hi2) >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +81,6 @@ kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a(
|
||||
const bool row_valid = row < (uint)m;
|
||||
const uint rrow = row_valid ? row : 0; // clamp OOB rows; their writes are masked
|
||||
|
||||
const uint num_superblocks = (uint)k / QK_K;
|
||||
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
||||
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
||||
|
||||
@@ -101,9 +102,9 @@ kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a(
|
||||
// weight scale/min for this WI's row, this subblock
|
||||
const float dd = (float)src0_d [rrow + sb_idx * m];
|
||||
const float dmm = (float)src0_dm[rrow + sb_idx * m];
|
||||
global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
||||
global const uchar * sc = src0_s + sb_idx * K_SCALE_SIZE * (uint)m + rrow;
|
||||
uchar sv, mn;
|
||||
get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc, (uint)m, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
||||
const float scale = dd * (float)sv;
|
||||
const float minv = dmm * (float)mn;
|
||||
|
||||
@@ -202,7 +203,6 @@ kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a_wimg(
|
||||
|
||||
const uint k_u = (uint)k >> 2; // K in uint (int8x4) units
|
||||
const uint k_b = (uint)k >> 5; // blocks-of-32 along K
|
||||
const uint num_superblocks = (uint)k / QK_K;
|
||||
|
||||
__local uint sh_qa[TILESIZE_N][8];
|
||||
__local half sh_d[TILESIZE_N];
|
||||
@@ -220,9 +220,9 @@ kernel void kernel_gemm_noshuffle_q4_k_q8_1_dp4a_wimg(
|
||||
|
||||
const float dd = (float)src0_d [rrow + sb_idx * m];
|
||||
const float dmm = (float)src0_dm[rrow + sb_idx * m];
|
||||
global const uchar * sc = src0_s + rrow * num_superblocks * K_SCALE_SIZE + sb_idx * K_SCALE_SIZE;
|
||||
global const uchar * sc = src0_s + sb_idx * K_SCALE_SIZE * (uint)m + rrow;
|
||||
uchar sv, mn;
|
||||
get_scale_min_k4(sub_idx, sc, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(sub_idx, sc, (uint)m, &sv, &mn, mask_d6, mask_d4, mask_hi2);
|
||||
const float scale = dd * (float)sv;
|
||||
const float minv = dmm * (float)mn;
|
||||
|
||||
|
||||
@@ -11,9 +11,11 @@
|
||||
#define NSUBGROUPS 4
|
||||
#define SUBGROUP_SIZE 64
|
||||
|
||||
// scales are transposed: consecutive codes of a row are `stride` apart
|
||||
inline void get_scale_min_k4(
|
||||
int j,
|
||||
global const uchar * q,
|
||||
uint stride,
|
||||
uchar * d,
|
||||
uchar * m,
|
||||
uchar mask_d6,
|
||||
@@ -21,11 +23,11 @@ inline void get_scale_min_k4(
|
||||
uchar mask_hi2
|
||||
) {
|
||||
if (j < 4) {
|
||||
*d = q[j] & mask_d6;
|
||||
*m = q[j+4] & mask_d6;
|
||||
*d = q[j*stride] & mask_d6;
|
||||
*m = q[(j+4)*stride] & mask_d6;
|
||||
} else {
|
||||
*d = (q[j+4] & mask_d4) | ((q[j-4] & mask_hi2) >> 2);
|
||||
*m = ((q[j+4] >> 4) & mask_d4) | ((q[j] & mask_hi2) >> 2);
|
||||
*d = (q[(j+4)*stride] & mask_d4) | ((q[(j-4)*stride] & mask_hi2) >> 2);
|
||||
*m = ((q[(j+4)*stride] >> 4) & mask_d4) | ((q[j*stride] & mask_hi2) >> 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -232,7 +234,6 @@ kernel void kernel_gemv_noshuffle_q4_k_f32(
|
||||
|
||||
uint LINE_STRIDE_A = M / 2;
|
||||
uint BLOCK_STRIDE_A = NSUBGROUPS * M;
|
||||
uint scales_per_row = (K / QK_K) * 12;
|
||||
|
||||
private uint4 regA;
|
||||
private half2 regS;
|
||||
@@ -248,12 +249,12 @@ kernel void kernel_gemv_noshuffle_q4_k_f32(
|
||||
half2 d = src0_d[gid + sb * LINE_STRIDE_A];
|
||||
half2 dm = src0_m[gid + sb * LINE_STRIDE_A];
|
||||
|
||||
global const uchar * sc0 = src0_s + 2 * gid * scales_per_row + sb * 12;
|
||||
global const uchar * sc1 = src0_s + (2 * gid + 1) * scales_per_row + sb * 12;
|
||||
global const uchar * sc0 = src0_s + sb * 12 * M + 2 * gid;
|
||||
global const uchar * sc1 = sc0 + 1;
|
||||
|
||||
uchar sv0, mn0, sv1, mn1;
|
||||
get_scale_min_k4(j, sc0, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(j, sc1, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(j, sc0, M, &sv0, &mn0, mask_d6, mask_d4, mask_hi2);
|
||||
get_scale_min_k4(j, sc1, M, &sv1, &mn1, mask_d6, mask_d4, mask_hi2);
|
||||
|
||||
regS = convert_half2(convert_float2(d) * convert_float2((uchar2)(sv0, sv1)));
|
||||
regM = convert_half2(convert_float2(dm) * convert_float2((uchar2)(mn0, mn1)));
|
||||
|
||||
@@ -153,18 +153,27 @@ kernel void kernel_mul_mv_q4_K_f32_flat(
|
||||
|
||||
global ushort * q2 = q1 + 32;
|
||||
|
||||
float4 acc1 = {0.f, 0.f, 0.f, 0.f};
|
||||
float4 acc2 = {0.f, 0.f, 0.f, 0.f};
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
acc1.s0 += yl[i+0] * (q1[i/2] & 0x000F);
|
||||
acc1.s1 += yl[i+1] * (q1[i/2] & 0x0F00);
|
||||
acc1.s2 += yl[i+8] * (q1[i/2] & 0x00F0);
|
||||
acc1.s3 += yl[i+9] * (q1[i/2] & 0xF000);
|
||||
acc2.s0 += yh[i+0] * (q2[i/2] & 0x000F);
|
||||
acc2.s1 += yh[i+1] * (q2[i/2] & 0x0F00);
|
||||
acc2.s2 += yh[i+8] * (q2[i/2] & 0x00F0);
|
||||
acc2.s3 += yh[i+9] * (q2[i/2] & 0xF000);
|
||||
}
|
||||
// Load the 4 q1 / 4 q2 quant ushorts as 2 uints each. 16-bit integer ops are
|
||||
// disproportionately slow on the A7X (E031.41) compiler; keeping the dequant
|
||||
// operands in 32-bit registers avoids the ushort path. q1/q2 are 4-byte aligned
|
||||
// (ib*128 + (32*iq+8*ir) bytes; q1 += blk*128 bytes/row). Math is unchanged:
|
||||
// w & 0x0F00 on the low/high halves equals the original ushort mask value.
|
||||
global uint * q1u = (global uint *)q1;
|
||||
global uint * q2u = (global uint *)q2;
|
||||
uint a0 = q1u[0], a1 = q1u[1];
|
||||
uint b0 = q2u[0], b1 = q2u[1];
|
||||
uint w0 = a0 & 0xFFFF, w1 = a0 >> 16, w2 = a1 & 0xFFFF, w3 = a1 >> 16;
|
||||
uint v0 = b0 & 0xFFFF, v1 = b0 >> 16, v2 = b1 & 0xFFFF, v3 = b1 >> 16;
|
||||
|
||||
float4 acc1, acc2;
|
||||
acc1.s0 = yl[0]*(w0&0x000F) + yl[ 2]*(w1&0x000F) + yl[ 4]*(w2&0x000F) + yl[ 6]*(w3&0x000F);
|
||||
acc1.s1 = yl[1]*(w0&0x0F00) + yl[ 3]*(w1&0x0F00) + yl[ 5]*(w2&0x0F00) + yl[ 7]*(w3&0x0F00);
|
||||
acc1.s2 = yl[8]*(w0&0x00F0) + yl[10]*(w1&0x00F0) + yl[12]*(w2&0x00F0) + yl[14]*(w3&0x00F0);
|
||||
acc1.s3 = yl[9]*(w0&0xF000) + yl[11]*(w1&0xF000) + yl[13]*(w2&0xF000) + yl[15]*(w3&0xF000);
|
||||
acc2.s0 = yh[0]*(v0&0x000F) + yh[ 2]*(v1&0x000F) + yh[ 4]*(v2&0x000F) + yh[ 6]*(v3&0x000F);
|
||||
acc2.s1 = yh[1]*(v0&0x0F00) + yh[ 3]*(v1&0x0F00) + yh[ 5]*(v2&0x0F00) + yh[ 7]*(v3&0x0F00);
|
||||
acc2.s2 = yh[8]*(v0&0x00F0) + yh[10]*(v1&0x00F0) + yh[12]*(v2&0x00F0) + yh[14]*(v3&0x00F0);
|
||||
acc2.s3 = yh[9]*(v0&0xF000) + yh[11]*(v1&0xF000) + yh[13]*(v2&0xF000) + yh[15]*(v3&0xF000);
|
||||
|
||||
float dall = *d;
|
||||
float dmin = *dm;
|
||||
|
||||
@@ -159,18 +159,59 @@ kernel void kernel_mul_mv_q5_K_f32_flat(
|
||||
|
||||
global ushort * q2 = q1 + 32;
|
||||
|
||||
float4 acc1 = {0.f, 0.f, 0.f, 0.f};
|
||||
float4 acc2 = {0.f, 0.f, 0.f, 0.f};
|
||||
for (int i = 0; i < 8; i += 2) {
|
||||
acc1.s0 += yl[i+0] * ((q1[i/2] & 0x000F) + (qh[i+0] & u1_lo ? 16.f : 0.f));
|
||||
acc1.s1 += yl[i+1] * ((q1[i/2] & 0x0F00) + (qh[i+1] & u1_lo ? 16.f*256.f : 0.f));
|
||||
acc1.s2 += yl[i+8] * ((q1[i/2] & 0x00F0) + (qh[i+0] & u2_lo ? 16.f*16.f : 0.f));
|
||||
acc1.s3 += yl[i+9] * ((q1[i/2] & 0xF000) + (qh[i+1] & u2_lo ? 16.f*4096.f: 0.f));
|
||||
acc2.s0 += yh[i+0] * ((q2[i/2] & 0x000F) + (qh[i+0] & u1_hi ? 16.f : 0.f));
|
||||
acc2.s1 += yh[i+1] * ((q2[i/2] & 0x0F00) + (qh[i+1] & u1_hi ? 16.f*256.f : 0.f));
|
||||
acc2.s2 += yh[i+8] * ((q2[i/2] & 0x00F0) + (qh[i+0] & u2_hi ? 16.f*16.f : 0.f));
|
||||
acc2.s3 += yh[i+9] * ((q2[i/2] & 0xF000) + (qh[i+1] & u2_hi ? 16.f*4096.f: 0.f));
|
||||
}
|
||||
// Load the 4 q1 / 4 q2 quant ushorts as 2 uints each. 16-bit integer ops are
|
||||
// disproportionately slow on the A7X (E031.41) compiler; keeping the dequant
|
||||
// operands in 32-bit registers avoids the ushort path (same fix as q4_K flat).
|
||||
// q1/q2 are 4-byte aligned; w & 0x0F00 on the low/high half of a uint equals the
|
||||
// original ushort mask value, so the math is unchanged. The qh high-bit term is
|
||||
// byte-indexed (qh[0..7]) and left as-is.
|
||||
global uint * q1u = (global uint *)q1;
|
||||
global uint * q2u = (global uint *)q2;
|
||||
uint a0 = q1u[0], a1 = q1u[1], b0 = q2u[0], b1 = q2u[1];
|
||||
uint w0 = a0 & 0xFFFF, w1 = a0 >> 16, w2 = a1 & 0xFFFF, w3 = a1 >> 16;
|
||||
uint v0 = b0 & 0xFFFF, v1 = b0 >> 16, v2 = b1 & 0xFFFF, v3 = b1 >> 16;
|
||||
|
||||
float4 acc1, acc2;
|
||||
acc1.s0 =
|
||||
yl[0]*((w0&0x000F)+(qh[0]&u1_lo?16.f:0.f)) +
|
||||
yl[2]*((w1&0x000F)+(qh[2]&u1_lo?16.f:0.f)) +
|
||||
yl[4]*((w2&0x000F)+(qh[4]&u1_lo?16.f:0.f)) +
|
||||
yl[6]*((w3&0x000F)+(qh[6]&u1_lo?16.f:0.f));
|
||||
acc1.s1 =
|
||||
yl[1]*((w0&0x0F00)+(qh[1]&u1_lo?16.f*256.f:0.f)) +
|
||||
yl[3]*((w1&0x0F00)+(qh[3]&u1_lo?16.f*256.f:0.f)) +
|
||||
yl[5]*((w2&0x0F00)+(qh[5]&u1_lo?16.f*256.f:0.f)) +
|
||||
yl[7]*((w3&0x0F00)+(qh[7]&u1_lo?16.f*256.f:0.f));
|
||||
acc1.s2 =
|
||||
yl[ 8]*((w0&0x00F0)+(qh[0]&u2_lo?16.f*16.f:0.f)) +
|
||||
yl[10]*((w1&0x00F0)+(qh[2]&u2_lo?16.f*16.f:0.f)) +
|
||||
yl[12]*((w2&0x00F0)+(qh[4]&u2_lo?16.f*16.f:0.f)) +
|
||||
yl[14]*((w3&0x00F0)+(qh[6]&u2_lo?16.f*16.f:0.f));
|
||||
acc1.s3 =
|
||||
yl[ 9]*((w0&0xF000)+(qh[1]&u2_lo?16.f*4096.f:0.f)) +
|
||||
yl[11]*((w1&0xF000)+(qh[3]&u2_lo?16.f*4096.f:0.f)) +
|
||||
yl[13]*((w2&0xF000)+(qh[5]&u2_lo?16.f*4096.f:0.f)) +
|
||||
yl[15]*((w3&0xF000)+(qh[7]&u2_lo?16.f*4096.f:0.f));
|
||||
acc2.s0 =
|
||||
yh[0]*((v0&0x000F)+(qh[0]&u1_hi?16.f:0.f)) +
|
||||
yh[2]*((v1&0x000F)+(qh[2]&u1_hi?16.f:0.f)) +
|
||||
yh[4]*((v2&0x000F)+(qh[4]&u1_hi?16.f:0.f)) +
|
||||
yh[6]*((v3&0x000F)+(qh[6]&u1_hi?16.f:0.f));
|
||||
acc2.s1 =
|
||||
yh[1]*((v0&0x0F00)+(qh[1]&u1_hi?16.f*256.f:0.f)) +
|
||||
yh[3]*((v1&0x0F00)+(qh[3]&u1_hi?16.f*256.f:0.f)) +
|
||||
yh[5]*((v2&0x0F00)+(qh[5]&u1_hi?16.f*256.f:0.f)) +
|
||||
yh[7]*((v3&0x0F00)+(qh[7]&u1_hi?16.f*256.f:0.f));
|
||||
acc2.s2 =
|
||||
yh[ 8]*((v0&0x00F0)+(qh[0]&u2_hi?16.f*16.f:0.f)) +
|
||||
yh[10]*((v1&0x00F0)+(qh[2]&u2_hi?16.f*16.f:0.f)) +
|
||||
yh[12]*((v2&0x00F0)+(qh[4]&u2_hi?16.f*16.f:0.f)) +
|
||||
yh[14]*((v3&0x00F0)+(qh[6]&u2_hi?16.f*16.f:0.f));
|
||||
acc2.s3 =
|
||||
yh[ 9]*((v0&0xF000)+(qh[1]&u2_hi?16.f*4096.f:0.f)) +
|
||||
yh[11]*((v1&0xF000)+(qh[3]&u2_hi?16.f*4096.f:0.f)) +
|
||||
yh[13]*((v2&0xF000)+(qh[5]&u2_hi?16.f*4096.f:0.f)) +
|
||||
yh[15]*((v3&0xF000)+(qh[7]&u2_hi?16.f*4096.f:0.f));
|
||||
|
||||
float dall = *d;
|
||||
float dmin = *dm;
|
||||
|
||||
@@ -1378,3 +1378,5 @@ GGML_BACKEND_API ggml_backend_reg_t ggml_backend_openvino_reg(void) {
|
||||
|
||||
return ®
|
||||
}
|
||||
|
||||
GGML_BACKEND_DL_IMPL(ggml_backend_openvino_reg)
|
||||
|
||||
+71
-62
@@ -266,7 +266,7 @@ static void dequantize_mul_mat_vec_q2_k(const void *__restrict__ vx,
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
@@ -387,7 +387,7 @@ static void dequantize_mul_mat_vec_q2_k_reorder(const void *__restrict__ vx,
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
@@ -483,7 +483,7 @@ static void dequantize_mul_mat_vec_q3_k(const void *__restrict__ vx,
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
@@ -595,7 +595,7 @@ static void dequantize_mul_mat_vec_q3_k_reorder(const void *__restrict__ vx,
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
@@ -693,7 +693,7 @@ static void dequantize_mul_mat_vec_q4_k(const void *__restrict__ vx,
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
|
||||
@@ -841,7 +841,7 @@ static void dequantize_mul_mat_vec_q4_k_reorder(const void *__restrict__ vx,
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
|
||||
@@ -994,10 +994,12 @@ static void dequantize_mul_mat_vec_q4_k_reorder(const void *__restrict__ vx,
|
||||
static void dequantize_mul_mat_vec_q5_k(const void *__restrict__ vx,
|
||||
const float *__restrict__ yy,
|
||||
float *__restrict__ dst,
|
||||
const int ncols,
|
||||
const int ncols, int nrows,
|
||||
const sycl::nd_item<3> &item_ct1) {
|
||||
|
||||
const int row = item_ct1.get_group(2);
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row >= nrows) return;
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
|
||||
@@ -1126,7 +1128,9 @@ static void dequantize_mul_mat_vec_q5_k_reorder(const void *__restrict__ vx,
|
||||
const int ncols, int nrows,
|
||||
const sycl::nd_item<3> &item_ct1) {
|
||||
|
||||
const int row = item_ct1.get_group(2);
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row >= nrows) return;
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
|
||||
@@ -1148,19 +1152,13 @@ static void dequantize_mul_mat_vec_q5_k_reorder(const void *__restrict__ vx,
|
||||
const int tid = item_ct1.get_local_id(2) / 2; // 0...15
|
||||
const int ix = item_ct1.get_local_id(2) % 2;
|
||||
|
||||
const int il = tid/4; // 0...3
|
||||
const int ir = tid - 4*il;// 0...3
|
||||
const int il_base = tid/4; // 0...3
|
||||
const int ir = tid - 4*il_base;// 0...3
|
||||
const int n = 2;
|
||||
|
||||
const int im = il/2; // 0 or 1. 0 computes 0,32 + 128,160, 1 computes 64,96 + 192,224
|
||||
const int in = il%2;
|
||||
const int in = il_base%2;
|
||||
|
||||
const int l0 = n*(2*ir + in);
|
||||
const int q_offset = 32*im + l0;
|
||||
const int y_offset = 64*im + l0;
|
||||
|
||||
const uint8_t hm1 = 1 << (2*im);
|
||||
const uint8_t hm2 = hm1 << 4;
|
||||
|
||||
uint16_t aux[4];
|
||||
const uint8_t * sc = (const uint8_t *)aux;
|
||||
@@ -1171,52 +1169,60 @@ static void dequantize_mul_mat_vec_q5_k_reorder(const void *__restrict__ vx,
|
||||
for (int i = ix; i < num_blocks_per_row; i += 2) {
|
||||
const int bi = ib0 + i;
|
||||
|
||||
const uint8_t * ql1 = qs_base + bi * (QK_K / 2) + q_offset;
|
||||
const uint8_t * qh = qh_base + bi * (QK_K / 8) + l0;
|
||||
const float * y1 = yy + i*QK_K + y_offset;
|
||||
const float * y2 = y1 + 128;
|
||||
|
||||
const sycl::half2 dm_val = dm_base[bi];
|
||||
const float dall = dm_val[0];
|
||||
const float dmin = dm_val[1];
|
||||
|
||||
const uint16_t * a = (const uint16_t *)(scales_base + bi * K_SCALE_SIZE);
|
||||
aux[0] = a[im+0] & kmask1;
|
||||
aux[1] = a[im+2] & kmask1;
|
||||
aux[2] = ((a[im+4] >> 0) & kmask2) | ((a[im+0] & kmask3) >> 2);
|
||||
aux[3] = ((a[im+4] >> 4) & kmask2) | ((a[im+2] & kmask3) >> 2);
|
||||
for (int im = 0; im < 2; ++im) {
|
||||
const int q_offset = 32*im + l0;
|
||||
const int y_offset = 64*im + l0;
|
||||
|
||||
sycl::float4 sum = {0.f, 0.f, 0.f, 0.f};
|
||||
float smin = 0;
|
||||
const uint16_t * q1 = (const uint16_t *)ql1;
|
||||
const uint16_t * q2 = q1 + 32;
|
||||
q16[0] = q1[0] & 0x0f0f;
|
||||
q16[1] = q1[8] & 0x0f0f;
|
||||
q16[2] = (q1[0] >> 4) & 0x0f0f;
|
||||
q16[3] = (q1[8] >> 4) & 0x0f0f;
|
||||
q16[4] = q2[0] & 0x0f0f;
|
||||
q16[5] = q2[8] & 0x0f0f;
|
||||
q16[6] = (q2[0] >> 4) & 0x0f0f;
|
||||
q16[7] = (q2[8] >> 4) & 0x0f0f;
|
||||
for (int l = 0; l < n; ++l) {
|
||||
sum.x() +=
|
||||
y1[l + 0] * (q4[l + 0] + (qh[l + 0] & (hm1 << 0) ? 16 : 0)) +
|
||||
y1[l + 16] * (q4[l + 2] + (qh[l + 16] & (hm1 << 0) ? 16 : 0));
|
||||
sum.y() +=
|
||||
y1[l + 32] * (q4[l + 4] + (qh[l + 0] & (hm1 << 1) ? 16 : 0)) +
|
||||
y1[l + 48] * (q4[l + 6] + (qh[l + 16] & (hm1 << 1) ? 16 : 0));
|
||||
sum.z() +=
|
||||
y2[l + 0] * (q4[l + 8] + (qh[l + 0] & (hm2 << 0) ? 16 : 0)) +
|
||||
y2[l + 16] * (q4[l + 10] + (qh[l + 16] & (hm2 << 0) ? 16 : 0));
|
||||
sum.w() +=
|
||||
y2[l + 32] * (q4[l + 12] + (qh[l + 0] & (hm2 << 1) ? 16 : 0)) +
|
||||
y2[l + 48] * (q4[l + 14] + (qh[l + 16] & (hm2 << 1) ? 16 : 0));
|
||||
smin += (y1[l] + y1[l+16]) * sc[2] + (y1[l+32] + y1[l+48]) * sc[3]
|
||||
+ (y2[l] + y2[l+16]) * sc[6] + (y2[l+32] + y2[l+48]) * sc[7];
|
||||
const uint8_t hm1 = 1 << (2*im);
|
||||
const uint8_t hm2 = hm1 << 4;
|
||||
|
||||
const uint8_t * ql1 = qs_base + bi * (QK_K / 2) + q_offset;
|
||||
const float * y1 = yy + i*QK_K + y_offset;
|
||||
const float * y2 = y1 + 128;
|
||||
|
||||
const uint16_t * a = (const uint16_t *)(scales_base + bi * K_SCALE_SIZE);
|
||||
aux[0] = a[im+0] & kmask1;
|
||||
aux[1] = a[im+2] & kmask1;
|
||||
aux[2] = ((a[im+4] >> 0) & kmask2) | ((a[im+0] & kmask3) >> 2);
|
||||
aux[3] = ((a[im+4] >> 4) & kmask2) | ((a[im+2] & kmask3) >> 2);
|
||||
|
||||
sycl::float4 sum = {0.f, 0.f, 0.f, 0.f};
|
||||
float smin = 0;
|
||||
const uint16_t * q1 = (const uint16_t *)ql1;
|
||||
const uint16_t * q2 = q1 + 32;
|
||||
q16[0] = q1[0] & 0x0f0f;
|
||||
q16[1] = q1[8] & 0x0f0f;
|
||||
q16[2] = (q1[0] >> 4) & 0x0f0f;
|
||||
q16[3] = (q1[8] >> 4) & 0x0f0f;
|
||||
q16[4] = q2[0] & 0x0f0f;
|
||||
q16[5] = q2[8] & 0x0f0f;
|
||||
q16[6] = (q2[0] >> 4) & 0x0f0f;
|
||||
q16[7] = (q2[8] >> 4) & 0x0f0f;
|
||||
for (int l = 0; l < n; ++l) {
|
||||
sum.x() +=
|
||||
y1[l + 0] * (q4[l + 0] + (qh[l + 0] & (hm1 << 0) ? 16 : 0)) +
|
||||
y1[l + 16] * (q4[l + 2] + (qh[l + 16] & (hm1 << 0) ? 16 : 0));
|
||||
sum.y() +=
|
||||
y1[l + 32] * (q4[l + 4] + (qh[l + 0] & (hm1 << 1) ? 16 : 0)) +
|
||||
y1[l + 48] * (q4[l + 6] + (qh[l + 16] & (hm1 << 1) ? 16 : 0));
|
||||
sum.z() +=
|
||||
y2[l + 0] * (q4[l + 8] + (qh[l + 0] & (hm2 << 0) ? 16 : 0)) +
|
||||
y2[l + 16] * (q4[l + 10] + (qh[l + 16] & (hm2 << 0) ? 16 : 0));
|
||||
sum.w() +=
|
||||
y2[l + 32] * (q4[l + 12] + (qh[l + 0] & (hm2 << 1) ? 16 : 0)) +
|
||||
y2[l + 48] * (q4[l + 14] + (qh[l + 16] & (hm2 << 1) ? 16 : 0));
|
||||
smin += (y1[l] + y1[l+16]) * sc[2] + (y1[l+32] + y1[l+48]) * sc[3]
|
||||
+ (y2[l] + y2[l+16]) * sc[6] + (y2[l+32] + y2[l+48]) * sc[7];
|
||||
}
|
||||
tmp += dall * (sum.x() * sc[0] + sum.y() * sc[1] + sum.z() * sc[4] +
|
||||
sum.w() * sc[5]) -
|
||||
dmin * smin;
|
||||
}
|
||||
tmp += dall * (sum.x() * sc[0] + sum.y() * sc[1] + sum.z() * sc[4] +
|
||||
sum.w() * sc[5]) -
|
||||
dmin * smin;
|
||||
}
|
||||
#else
|
||||
// The reordered Q5_K layout is only produced for QK_K == 256.
|
||||
@@ -1241,7 +1247,7 @@ static void dequantize_mul_mat_vec_q6_k(const void * __restrict__ vx, const floa
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
@@ -1358,7 +1364,7 @@ static void dequantize_mul_mat_vec_q6_k_reorder(const void * __restrict__ vx, co
|
||||
|
||||
const int row = item_ct1.get_group(2) * item_ct1.get_local_range(1) +
|
||||
item_ct1.get_local_id(1);
|
||||
if (row > nrows) return;
|
||||
if (row >= nrows) return;
|
||||
|
||||
const int num_blocks_per_row = ncols / QK_K;
|
||||
const int ib0 = row*num_blocks_per_row;
|
||||
@@ -1831,11 +1837,14 @@ static void dequantize_mul_mat_vec_q5_K_sycl(const void *vx, const float *y,
|
||||
const int nrows,
|
||||
dpct::queue_ptr stream) {
|
||||
GGML_ASSERT(ncols % QK_K == 0);
|
||||
const sycl::range<3> block_dims(1, 1, WARP_SIZE);
|
||||
const int ny = 2 / K_QUANTS_PER_ITERATION;
|
||||
const int block_num_y = (nrows + ny - 1) / ny;
|
||||
const sycl::range<3> block_nums(1, 1, block_num_y);
|
||||
const sycl::range<3> block_dims(1, ny, WARP_SIZE);
|
||||
stream->parallel_for(
|
||||
sycl::nd_range<3>(sycl::range<3>(1, 1, nrows) * block_dims, block_dims),
|
||||
sycl::nd_range<3>(block_nums * block_dims, block_dims),
|
||||
[=](sycl::nd_item<3> item_ct1) [[sycl::reqd_sub_group_size(WARP_SIZE)]] {
|
||||
dequantize_mul_mat_vec_q5_k(vx, y, dst, ncols, item_ct1);
|
||||
dequantize_mul_mat_vec_q5_k(vx, y, dst, ncols, nrows, item_ct1);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,24 @@ typedef struct VkPhysicalDeviceShaderFloat8FeaturesEXT {
|
||||
} VkPhysicalDeviceShaderFloat8FeaturesEXT;
|
||||
#endif
|
||||
|
||||
#ifndef VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME
|
||||
#define VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME "VK_KHR_internally_synchronized_queues"
|
||||
#define VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INTERNALLY_SYNCHRONIZED_QUEUES_FEATURES_KHR ((VkStructureType)1000504000)
|
||||
#define VK_DEVICE_QUEUE_CREATE_INTERNALLY_SYNCHRONIZED_BIT_KHR ((VkDeviceQueueCreateFlagBits)0x00000004)
|
||||
|
||||
// Compile-time constant guaranteed; no runtime initialization overhead
|
||||
static constexpr vk::DeviceQueueCreateFlagBits eInternallySynchronizedKHR =
|
||||
static_cast<vk::DeviceQueueCreateFlagBits>(0x00000004);
|
||||
|
||||
typedef struct VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR {
|
||||
VkStructureType sType;
|
||||
void* pNext;
|
||||
VkBool32 internallySynchronizedQueues;
|
||||
} VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR;
|
||||
#else
|
||||
static constexpr vk::DeviceQueueCreateFlagBits eInternallySynchronizedKHR = vk::DeviceQueueCreateFlagBits::eInternallySynchronizedKHR;
|
||||
#endif
|
||||
|
||||
#define ROUNDUP_POW2(M, N) (((M) + (N) - 1) & ~((N) - 1))
|
||||
#define CEIL_DIV(M, N) (((M) / (N)) + (((M) % (N)) != 0))
|
||||
static bool is_pow2(uint32_t x) { return x > 1 && (x & (x-1)) == 0; }
|
||||
@@ -285,27 +303,41 @@ struct vk_command_pool {
|
||||
};
|
||||
|
||||
// Prevent simultaneous submissions to the same queue.
|
||||
// This could be per vk_queue if we stopped having two vk_queue structures
|
||||
// sharing the same vk::Queue.
|
||||
static std::mutex queue_mutex;
|
||||
struct vk_queue_handle {
|
||||
vk::Queue queue;
|
||||
virtual void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) = 0;
|
||||
virtual void lock() {} // no-op by default (internally synchronized case)
|
||||
virtual void unlock() {}
|
||||
virtual ~vk_queue_handle() = default;
|
||||
};
|
||||
|
||||
struct vk_queue_handle_synchronized : vk_queue_handle {
|
||||
std::mutex mutex;
|
||||
void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) override {
|
||||
std::lock_guard<std::mutex> guard(mutex);
|
||||
queue.submit(submits, fence);
|
||||
}
|
||||
void lock() override { mutex.lock(); }
|
||||
void unlock() override { mutex.unlock(); }
|
||||
};
|
||||
|
||||
struct vk_queue_handle_unsynchronized : vk_queue_handle {
|
||||
void submit(vk::ArrayProxy<const vk::SubmitInfo> submits, vk::Fence fence) override {
|
||||
// Driver guarantees internal synchronization via VK_KHR_internally_synchronized_queues
|
||||
queue.submit(submits, fence);
|
||||
}
|
||||
// lock()/unlock() inherited no-ops
|
||||
};
|
||||
|
||||
struct vk_queue {
|
||||
uint32_t queue_family_index;
|
||||
vk::Queue queue;
|
||||
std::shared_ptr<vk_queue_handle> handle;
|
||||
|
||||
vk_command_pool cmd_pool;
|
||||
|
||||
vk::PipelineStageFlags stage_flags;
|
||||
|
||||
bool transfer_only;
|
||||
|
||||
// copy everything except the cmd_pool
|
||||
void copyFrom(vk_queue &other) {
|
||||
queue_family_index = other.queue_family_index;
|
||||
queue = other.queue;
|
||||
stage_flags = other.stage_flags;
|
||||
transfer_only = other.transfer_only;
|
||||
}
|
||||
};
|
||||
|
||||
static const char * ggml_backend_vk_buffer_type_name(ggml_backend_buffer_type_t buft);
|
||||
@@ -712,11 +744,12 @@ struct vk_device_struct {
|
||||
uint32_t vendor_id;
|
||||
vk::DriverId driver_id;
|
||||
vk_device_architecture architecture;
|
||||
vk_queue compute_queue;
|
||||
vk_queue transfer_queue;
|
||||
std::unique_ptr<vk_queue> compute_queue;
|
||||
std::unique_ptr<vk_queue> transfer_queue;
|
||||
bool single_queue;
|
||||
bool support_async;
|
||||
bool async_use_transfer_queue;
|
||||
bool has_internally_synchronized_queues = false;
|
||||
uint32_t subgroup_size;
|
||||
uint32_t subgroup_size_log2;
|
||||
uint32_t shader_core_count;
|
||||
@@ -1019,8 +1052,13 @@ struct vk_device_struct {
|
||||
|
||||
ggml_vk_destroy_buffer(sync_staging);
|
||||
|
||||
compute_queue.cmd_pool.destroy(device);
|
||||
transfer_queue.cmd_pool.destroy(device);
|
||||
if (compute_queue) compute_queue->cmd_pool.destroy(device);
|
||||
if (transfer_queue) transfer_queue->cmd_pool.destroy(device);
|
||||
|
||||
// Explicitly clear to ensure queues drop their shared_ptrs to handles
|
||||
// before the Vulkan logical device instance is destroyed
|
||||
compute_queue.reset();
|
||||
transfer_queue.reset();
|
||||
|
||||
for (auto& pipeline : all_pipelines) {
|
||||
if (pipeline.expired()) {
|
||||
@@ -2909,8 +2947,7 @@ static vk_command_buffer* ggml_vk_create_cmd_buffer(vk_device& device, vk_comman
|
||||
static void ggml_vk_submit(vk_context& ctx, vk::Fence fence) {
|
||||
if (ctx->seqs.empty()) {
|
||||
if (fence) {
|
||||
std::lock_guard<std::mutex> guard(queue_mutex);
|
||||
ctx->p->q->queue.submit({}, fence);
|
||||
ctx->p->q->handle->submit({}, fence);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -2979,8 +3016,7 @@ static void ggml_vk_submit(vk_context& ctx, vk::Fence fence) {
|
||||
}
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> guard(queue_mutex);
|
||||
ctx->p->q->queue.submit(submit_infos, fence);
|
||||
ctx->p->q->handle->submit(submit_infos, fence);
|
||||
|
||||
ctx->seqs.clear();
|
||||
}
|
||||
@@ -3031,18 +3067,44 @@ static uint32_t ggml_vk_find_queue_family_index(std::vector<vk::QueueFamilyPrope
|
||||
abort();
|
||||
}
|
||||
|
||||
static void ggml_vk_create_queue(vk_device& device, vk_queue& q, uint32_t queue_family_index, uint32_t queue_index, vk::PipelineStageFlags&& stage_flags, bool transfer_only) {
|
||||
static std::unique_ptr<vk_queue> ggml_vk_create_queue(vk_device& device, uint32_t queue_family_index, uint32_t queue_index, vk::PipelineStageFlags&& stage_flags, bool transfer_only) {
|
||||
VK_LOG_DEBUG("ggml_vk_create_queue()");
|
||||
std::lock_guard<std::recursive_mutex> guard(device->mutex);
|
||||
|
||||
q.queue_family_index = queue_family_index;
|
||||
q.transfer_only = transfer_only;
|
||||
auto q = std::make_unique<vk_queue>();
|
||||
q->queue_family_index = queue_family_index;
|
||||
q->transfer_only = transfer_only;
|
||||
|
||||
q.cmd_pool.init(device, &q);
|
||||
std::shared_ptr<vk_queue_handle> h;
|
||||
vk::DeviceQueueInfo2 queue_info2{};
|
||||
queue_info2.queueFamilyIndex = queue_family_index;
|
||||
queue_info2.queueIndex = queue_index;
|
||||
|
||||
q.queue = device->device.getQueue(queue_family_index, queue_index);
|
||||
if (device->has_internally_synchronized_queues) {
|
||||
h = std::make_shared<vk_queue_handle_unsynchronized>();
|
||||
queue_info2.flags = eInternallySynchronizedKHR;
|
||||
} else {
|
||||
h = std::make_shared<vk_queue_handle_synchronized>();
|
||||
}
|
||||
|
||||
q.stage_flags = stage_flags;
|
||||
h->queue = device->device.getQueue2(queue_info2);
|
||||
q->handle = h;
|
||||
|
||||
q->cmd_pool.init(device, q.get());
|
||||
|
||||
q->stage_flags = stage_flags;
|
||||
return q;
|
||||
}
|
||||
|
||||
static std::unique_ptr<vk_queue> ggml_vk_create_aliased_queue(vk_device& device, const std::unique_ptr<vk_queue>& source) {
|
||||
std::lock_guard<std::recursive_mutex> guard(device->mutex);
|
||||
auto q = std::make_unique<vk_queue>();
|
||||
q->handle = source->handle;
|
||||
q->queue_family_index = source->queue_family_index;
|
||||
q->stage_flags = source->stage_flags;
|
||||
q->transfer_only = source->transfer_only;
|
||||
q->cmd_pool.init(device, q.get());
|
||||
return q;
|
||||
}
|
||||
|
||||
static vk_context ggml_vk_create_context(ggml_backend_vk_context * ctx, vk_command_pool& p) {
|
||||
@@ -3107,11 +3169,11 @@ static void ggml_vk_queue_command_pools_cleanup(vk_device& device) {
|
||||
// Arbitrary frequency to cleanup/reuse command buffers
|
||||
static constexpr uint32_t cleanup_frequency = 10;
|
||||
|
||||
if (device->compute_queue.cmd_pool.buffers_in_use() >= cleanup_frequency) {
|
||||
ggml_vk_command_pool_cleanup(device, device->compute_queue.cmd_pool);
|
||||
if (device->compute_queue->cmd_pool.buffers_in_use() >= cleanup_frequency) {
|
||||
ggml_vk_command_pool_cleanup(device, device->compute_queue->cmd_pool);
|
||||
}
|
||||
if (device->transfer_queue.cmd_pool.buffers_in_use() >= cleanup_frequency) {
|
||||
ggml_vk_command_pool_cleanup(device, device->transfer_queue.cmd_pool);
|
||||
if (device->transfer_queue->cmd_pool.buffers_in_use() >= cleanup_frequency) {
|
||||
ggml_vk_command_pool_cleanup(device, device->transfer_queue->cmd_pool);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3735,6 +3797,7 @@ static bool ggml_vk_matmul_int_shmem_support(const vk_device& device, const std:
|
||||
|
||||
uint32_t block_a_size = 0;
|
||||
switch (src0_type) {
|
||||
case GGML_TYPE_Q2_0: block_a_size = std430_size({{32, 4}, {fp_size, fp_align}}); break; // qs[8] + dm
|
||||
case GGML_TYPE_Q4_0: block_a_size = std430_size({{16, 4}, {fp_size, fp_align}}); break; // qs[16/4] + dm
|
||||
case GGML_TYPE_Q4_1: block_a_size = std430_size({{16, 4}, {fp2_size, fp2_align}}); break; // qs[16/4] + dm(vec2)
|
||||
case GGML_TYPE_Q5_0: block_a_size = std430_size({{16, 4}, {4, 4}, {fp_size, fp_align}}); break; // qs[16/4] + qh + dm
|
||||
@@ -4339,6 +4402,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
}
|
||||
#endif
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_f16[GGML_TYPE_Q1_0], matmul_q1_0_f16, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_f16[GGML_TYPE_Q2_0], matmul_q2_0_f16, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_f16[GGML_TYPE_Q4_0], matmul_q4_0_f16, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_f16[GGML_TYPE_Q4_1], matmul_q4_1_f16, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_f16[GGML_TYPE_Q5_0], matmul_q5_0_f16, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3)
|
||||
@@ -4378,6 +4442,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
}
|
||||
#endif
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q1_0], matmul_id_subgroup_q1_0_f16, mmqid_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, 5)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q2_0], matmul_id_subgroup_q2_0_f16, mmqid_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, 5)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_0], matmul_id_subgroup_q4_0_f16, mmqid_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, 5)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_1], matmul_id_subgroup_q4_1_f16, mmqid_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, 5)
|
||||
CREATE_MM2(pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q5_0], matmul_id_subgroup_q5_0_f16, mmqid_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, 5)
|
||||
@@ -4448,6 +4513,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
#endif
|
||||
|
||||
CREATE_MM2(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q1_0], matmul_q1_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MM2(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q2_0], matmul_q2_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MM2(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q4_0], matmul_q4_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MM2(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q4_1], matmul_q4_1_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MM2(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q5_0], matmul_q5_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, );
|
||||
@@ -4492,6 +4558,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
#endif
|
||||
|
||||
CREATE_MM2(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q1_0], matmul_id_subgroup_q1_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id);
|
||||
CREATE_MM2(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q2_0], matmul_id_subgroup_q2_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id);
|
||||
CREATE_MM2(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_0], matmul_id_subgroup_q4_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id);
|
||||
CREATE_MM2(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_1], matmul_id_subgroup_q4_1_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id);
|
||||
CREATE_MM2(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q5_0], matmul_id_subgroup_q5_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id);
|
||||
@@ -4581,6 +4648,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
CREATE_MM_NODOT2(GGML_TYPE_BF16, pipeline_matmul_bf16, matmul_bf16, , wg_denoms, warptile, vk_mat_mat_push_constants, 3, , 0);
|
||||
|
||||
CREATE_MM2(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q1_0], matmul_q1_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM2(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q2_0], matmul_q2_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM2(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q4_0], matmul_q4_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM2(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q4_1], matmul_q4_1_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM2(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q5_0], matmul_q5_0_f32, mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
@@ -4605,6 +4673,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
|
||||
#if defined(GGML_VULKAN_INTEGER_DOT_GLSLC_SUPPORT)
|
||||
if (device->integer_dot_product) {
|
||||
CREATE_MMQ(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q2_0], matmul_q2_0_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MMQ(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q4_0], matmul_q4_0_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MMQ(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q4_1], matmul_q4_1_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MMQ(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q5_0], matmul_q5_0_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, , 0);
|
||||
@@ -4627,6 +4696,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
CREATE_MM2(GGML_TYPE_F16, pipeline_matmul_id_f16_f32, matmul_id_subgroup_f16_f32, wg_denoms, warptile_id, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size_16);
|
||||
CREATE_MM_NODOT2(GGML_TYPE_BF16, pipeline_matmul_id_bf16, matmul_id_subgroup_bf16, , wg_denoms, warptile_id, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size_16);
|
||||
CREATE_MM2(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q1_0], matmul_id_subgroup_q1_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM2(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q2_0], matmul_id_subgroup_q2_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM2(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_0], matmul_id_subgroup_q4_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM2(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_1], matmul_id_subgroup_q4_1_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM2(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q5_0], matmul_id_subgroup_q5_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
@@ -4651,6 +4721,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
|
||||
#if defined(GGML_VULKAN_INTEGER_DOT_GLSLC_SUPPORT)
|
||||
if (device->integer_dot_product) {
|
||||
CREATE_MMQ(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q2_0], matmul_id_subgroup_q2_0_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MMQ(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q4_0], matmul_id_subgroup_q4_0_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MMQ(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q4_1], matmul_id_subgroup_q4_1_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MMQ(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q5_0], matmul_id_subgroup_q5_0_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
@@ -4672,6 +4743,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
CREATE_MM2(GGML_TYPE_F16, pipeline_matmul_id_f16_f32, matmul_id_f16_f32, wg_denoms, warptile, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM_NODOT2(GGML_TYPE_BF16, pipeline_matmul_id_bf16, matmul_id_bf16, , wg_denoms, warptile, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM2(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q1_0], matmul_id_q1_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM2(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q2_0], matmul_id_q2_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM2(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_0], matmul_id_q4_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM2(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_1], matmul_id_q4_1_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM2(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q5_0], matmul_id_q5_0_f32, mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
@@ -4696,6 +4768,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
|
||||
#if defined(GGML_VULKAN_INTEGER_DOT_GLSLC_SUPPORT)
|
||||
if (device->integer_dot_product) {
|
||||
CREATE_MMQ(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q2_0], matmul_id_q2_0_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MMQ(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q4_0], matmul_id_q4_0_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MMQ(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q4_1], matmul_id_q4_1_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MMQ(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id_q8_1[GGML_TYPE_Q5_0], matmul_id_q5_0_q8_1, mmq_wg_denoms, warptile_mmqid_int, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
@@ -4748,6 +4821,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
CREATE_MM(GGML_TYPE_BF16, pipeline_matmul_bf16, matmul_bf16, , wg_denoms, warptile, vk_mat_mat_push_constants, 3, , 0);
|
||||
|
||||
CREATE_MM(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q1_0].f32acc, matmul_q1_0_f32, , mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q2_0].f32acc, matmul_q2_0_f32, , mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q4_0].f32acc, matmul_q4_0_f32, , mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q4_1].f32acc, matmul_q4_1_f32, , mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
CREATE_MM(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat[GGML_TYPE_Q5_0].f32acc, matmul_q5_0_f32, , mmq_wg_denoms, warptile_mmq, vk_mat_mat_push_constants, 3, , 0);
|
||||
@@ -4773,6 +4847,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
|
||||
#if defined(GGML_VULKAN_INTEGER_DOT_GLSLC_SUPPORT)
|
||||
if (device->integer_dot_product) {
|
||||
CREATE_MMQ(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q2_0].f32acc, matmul_q2_0_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MMQ(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q4_0].f32acc, matmul_q4_0_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MMQ(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q4_1].f32acc, matmul_q4_1_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, );
|
||||
CREATE_MMQ(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_q8_1[GGML_TYPE_Q5_0].f32acc, matmul_q5_0_q8_1, mmq_wg_denoms, warptile_mmq_int, vk_mat_mat_push_constants, 3, );
|
||||
@@ -4794,6 +4869,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
CREATE_MM(GGML_TYPE_BF16, pipeline_matmul_id_bf16, matmul_id_subgroup_bf16, , wg_denoms, warptile_id, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size_16);
|
||||
|
||||
CREATE_MM(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q1_0].f32acc, matmul_id_subgroup_q1_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q2_0].f32acc, matmul_id_subgroup_q2_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_0].f32acc, matmul_id_subgroup_q4_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_1].f32acc, matmul_id_subgroup_q4_1_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
CREATE_MM(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q5_0].f32acc, matmul_id_subgroup_q5_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, mul_mat_subgroup_size);
|
||||
@@ -4822,6 +4898,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
CREATE_MM(GGML_TYPE_BF16, pipeline_matmul_id_bf16, matmul_id_bf16, , wg_denoms, warptile, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
|
||||
CREATE_MM(GGML_TYPE_Q1_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q1_0].f32acc, matmul_id_q1_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM(GGML_TYPE_Q2_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q2_0].f32acc, matmul_id_q2_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM(GGML_TYPE_Q4_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_0].f32acc, matmul_id_q4_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM(GGML_TYPE_Q4_1, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q4_1].f32acc, matmul_id_q4_1_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
CREATE_MM(GGML_TYPE_Q5_0, pipeline_dequant_mul_mat_mat_id[GGML_TYPE_Q5_0].f32acc, matmul_id_q5_0_f32, , mmq_wg_denoms, warptile_mmqid, vk_mat_mat_id_push_constants, mul_mat_id_param_count, _id, 0);
|
||||
@@ -4924,6 +5001,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_F16 ][i], "mul_mat_vec_f16_f32_f32", arr_dmmv_f16_f32_f32_len[reduc], arr_dmmv_f16_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2, 1, 1}, {wg_size_subgroup, 2, i+1}, 1, false, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_BF16][i], "mul_mat_vec_bf16_f32_f32", arr_dmmv_bf16_f32_f32_len[reduc], arr_dmmv_bf16_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2, 1, 1}, {wg_size_subgroup, 2, i+1}, 1, false, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_Q1_0][i], "mul_mat_vec_q1_0_f32_f32", arr_dmmv_q1_0_f32_f32_len[reduc], arr_dmmv_q1_0_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_Q2_0][i], "mul_mat_vec_q2_0_f32_f32", arr_dmmv_q2_0_f32_f32_len[reduc], arr_dmmv_q2_0_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_Q4_0][i], "mul_mat_vec_q4_0_f32_f32", arr_dmmv_q4_0_f32_f32_len[reduc], arr_dmmv_q4_0_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_Q4_1][i], "mul_mat_vec_q4_1_f32_f32", arr_dmmv_q4_1_f32_f32_len[reduc], arr_dmmv_q4_1_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f32_f32[w][GGML_TYPE_Q5_0][i], "mul_mat_vec_q5_0_f32_f32", arr_dmmv_q5_0_f32_f32_len[reduc], arr_dmmv_q5_0_f32_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
@@ -4950,6 +5028,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_F16 ][i], "mul_mat_vec_f16_f16_f32", arr_dmmv_f16_f16_f32_len[reduc], arr_dmmv_f16_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2, 1, 1}, {wg_size_subgroup, 2, i+1}, 1, false, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_BF16][i], "mul_mat_vec_bf16_f16_f32", arr_dmmv_bf16_f16_f32_len[reduc], arr_dmmv_bf16_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2, 1, 1}, {wg_size_subgroup, 2, i+1}, 1, false, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_Q1_0][i], "mul_mat_vec_q1_0_f16_f32", arr_dmmv_q1_0_f16_f32_len[reduc], arr_dmmv_q1_0_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_Q2_0][i], "mul_mat_vec_q2_0_f16_f32", arr_dmmv_q2_0_f16_f32_len[reduc], arr_dmmv_q2_0_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_Q4_0][i], "mul_mat_vec_q4_0_f16_f32", arr_dmmv_q4_0_f16_f32_len[reduc], arr_dmmv_q4_0_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_Q4_1][i], "mul_mat_vec_q4_1_f16_f32", arr_dmmv_q4_1_f16_f32_len[reduc], arr_dmmv_q4_1_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_f16_f32[w][GGML_TYPE_Q5_0][i], "mul_mat_vec_q5_0_f16_f32", arr_dmmv_q5_0_f16_f32_len[reduc], arr_dmmv_q5_0_f16_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq, i+1}, 1, true, use_subgroups, force_subgroup_size);
|
||||
@@ -4977,6 +5056,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
const uint32_t subgroup_size_int = (device->vendor_id == VK_VENDOR_ID_INTEL && device->subgroup_size_control) ? device->subgroup_min_size : device->subgroup_size;
|
||||
const uint32_t wg_size_subgroup_int = (w == DMMV_WG_SIZE_SUBGROUP) ? subgroup_size_int : (subgroup_size_int * 4);
|
||||
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_q8_1_f32[w][GGML_TYPE_Q2_0][i], "mul_mat_vec_q2_0_q8_1_f32", arr_dmmv_q2_0_q8_1_f32_len[reduc], arr_dmmv_q2_0_q8_1_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {2*rm_kq_int, 1, 1}, {wg_size_subgroup_int, 2*rm_kq_int, i+1}, 1, true, use_subgroups, subgroup_size_int);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_q8_1_f32[w][GGML_TYPE_Q4_0][i], "mul_mat_vec_q4_0_q8_1_f32", arr_dmmv_q4_0_q8_1_f32_len[reduc], arr_dmmv_q4_0_q8_1_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {1*rm_stdq_int, 1, 1}, {wg_size_subgroup_int, 1*rm_stdq_int, i+1}, 1, true, use_subgroups, subgroup_size_int);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_q8_1_f32[w][GGML_TYPE_Q4_1][i], "mul_mat_vec_q4_1_q8_1_f32", arr_dmmv_q4_1_q8_1_f32_len[reduc], arr_dmmv_q4_1_q8_1_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {1*rm_stdq_int, 1, 1}, {wg_size_subgroup_int, 1*rm_stdq_int, i+1}, 1, true, use_subgroups, subgroup_size_int);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_q8_1_f32[w][GGML_TYPE_Q5_0][i], "mul_mat_vec_q5_0_q8_1_f32", arr_dmmv_q5_0_q8_1_f32_len[reduc], arr_dmmv_q5_0_q8_1_f32_data[reduc], "main", mul_mat_vec_num_bindings, sizeof(vk_mat_vec_push_constants), {1*rm_stdq_int, 1, 1}, {wg_size_subgroup_int, 1*rm_stdq_int, i+1}, 1, true, use_subgroups, subgroup_size_int);
|
||||
@@ -5002,6 +5082,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_F16 ], "mul_mat_vec_id_f16_f32", arr_dmmv_id_f16_f32_f32_len[reduc], arr_dmmv_id_f16_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2, 1, 1}, {wg_size_subgroup, 2}, 1, false, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_BF16], "mul_mat_vec_id_bf16_f32", arr_dmmv_id_bf16_f32_f32_len[reduc], arr_dmmv_id_bf16_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2, 1, 1}, {wg_size_subgroup, 2}, 1, false, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_Q1_0], "mul_mat_vec_id_q1_0_f32", arr_dmmv_id_q1_0_f32_f32_len[reduc], arr_dmmv_id_q1_0_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_Q2_0], "mul_mat_vec_id_q2_0_f32", arr_dmmv_id_q2_0_f32_f32_len[reduc], arr_dmmv_id_q2_0_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_Q4_0], "mul_mat_vec_id_q4_0_f32", arr_dmmv_id_q4_0_f32_f32_len[reduc], arr_dmmv_id_q4_0_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_Q4_1], "mul_mat_vec_id_q4_1_f32", arr_dmmv_id_q4_1_f32_f32_len[reduc], arr_dmmv_id_q4_1_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq}, 1, true, use_subgroups, force_subgroup_size);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_f32[w][GGML_TYPE_Q5_0], "mul_mat_vec_id_q5_0_f32", arr_dmmv_id_q5_0_f32_f32_len[reduc], arr_dmmv_id_q5_0_f32_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2*rm_stdq, 1, 1}, {wg_size_subgroup, 2*rm_stdq}, 1, true, use_subgroups, force_subgroup_size);
|
||||
@@ -5029,6 +5110,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
const uint32_t subgroup_size_int = (device->vendor_id == VK_VENDOR_ID_INTEL && device->subgroup_size_control) ? device->subgroup_min_size : device->subgroup_size;
|
||||
const uint32_t wg_size_subgroup_int = (w == DMMV_WG_SIZE_SUBGROUP) ? subgroup_size_int : (subgroup_size_int * 4);
|
||||
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_q8_1_f32[w][GGML_TYPE_Q2_0], "mul_mat_vec_id_q2_0_q8_1_f32", arr_dmmv_id_q2_0_q8_1_f32_len[reduc], arr_dmmv_id_q2_0_q8_1_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {2*rm_kq_int, 1, 1}, {wg_size_subgroup_int, 2*rm_kq_int}, 1, true, use_subgroups, subgroup_size_int);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_q8_1_f32[w][GGML_TYPE_Q4_0], "mul_mat_vec_id_q4_0_q8_1_f32", arr_dmmv_id_q4_0_q8_1_f32_len[reduc], arr_dmmv_id_q4_0_q8_1_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {1*rm_stdq_int, 1, 1}, {wg_size_subgroup_int, 1*rm_stdq_int}, 1, true, use_subgroups, subgroup_size_int);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_q8_1_f32[w][GGML_TYPE_Q4_1], "mul_mat_vec_id_q4_1_q8_1_f32", arr_dmmv_id_q4_1_q8_1_f32_len[reduc], arr_dmmv_id_q4_1_q8_1_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {1*rm_stdq_int, 1, 1}, {wg_size_subgroup_int, 1*rm_stdq_int}, 1, true, use_subgroups, subgroup_size_int);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant_mul_mat_vec_id_q8_1_f32[w][GGML_TYPE_Q5_0], "mul_mat_vec_id_q5_0_q8_1_f32", arr_dmmv_id_q5_0_q8_1_f32_len[reduc], arr_dmmv_id_q5_0_q8_1_f32_data[reduc], "main", mul_mat_vec_id_num_bindings, sizeof(vk_mat_vec_id_push_constants), {1*rm_stdq_int, 1, 1}, {wg_size_subgroup_int, 1*rm_stdq_int}, 1, true, use_subgroups, subgroup_size_int);
|
||||
@@ -5061,6 +5143,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
// dequant shaders
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant[GGML_TYPE_F32 ], "f32_to_f16", dequant_f32_len, dequant_f32_data, "main", 2, 5 * sizeof(uint32_t), {256 * 16, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant[GGML_TYPE_Q1_0], "dequant_q1_0", dequant_q1_0_len, dequant_q1_0_data, "main", 2, 5 * sizeof(uint32_t), {256 * 8, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant[GGML_TYPE_Q2_0], "dequant_q2_0", dequant_q2_0_len, dequant_q2_0_data, "main", 2, 5 * sizeof(uint32_t), {256 * 4, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant[GGML_TYPE_Q4_0], "dequant_q4_0", dequant_q4_0_len, dequant_q4_0_data, "main", 2, 5 * sizeof(uint32_t), {256 * 16, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant[GGML_TYPE_Q4_1], "dequant_q4_1", dequant_q4_1_len, dequant_q4_1_data, "main", 2, 5 * sizeof(uint32_t), {256 * 16, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_dequant[GGML_TYPE_Q5_0], "dequant_q5_0", dequant_q5_0_len, dequant_q5_0_data, "main", 2, 5 * sizeof(uint32_t), {256 * 16, 1, 1}, {}, 1);
|
||||
@@ -5088,6 +5171,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_F16 ], "get_rows_f16", get_rows_f16_len, get_rows_f16_data, "main", 3, sizeof(vk_op_binary_push_constants), { 512, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_BF16], "get_rows_bf16", get_rows_bf16_len, get_rows_bf16_data, "main", 3, sizeof(vk_op_binary_push_constants), { 512, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_Q1_0], "get_rows_q1_0", get_rows_q1_0_len, get_rows_q1_0_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_Q2_0], "get_rows_q2_0", get_rows_q2_0_len, get_rows_q2_0_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_Q4_0], "get_rows_q4_0", get_rows_q4_0_len, get_rows_q4_0_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_Q4_1], "get_rows_q4_1", get_rows_q4_1_len, get_rows_q4_1_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows[GGML_TYPE_Q5_0], "get_rows_q5_0", get_rows_q5_0_len, get_rows_q5_0_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
@@ -5115,6 +5199,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_F16 ], "get_rows_f16_f32", get_rows_f16_f32_len, get_rows_f16_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), { 512, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_BF16], "get_rows_bf16_f32", get_rows_bf16_f32_len, get_rows_bf16_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), { 512, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_Q1_0], "get_rows_q1_0_f32", get_rows_q1_0_f32_len, get_rows_q1_0_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_Q2_0], "get_rows_q2_0_f32", get_rows_q2_0_f32_len, get_rows_q2_0_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_Q4_0], "get_rows_q4_0_f32", get_rows_q4_0_f32_len, get_rows_q4_0_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_Q4_1], "get_rows_q4_1_f32", get_rows_q4_1_f32_len, get_rows_q4_1_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_get_rows_f32[GGML_TYPE_Q5_0], "get_rows_q5_0_f32", get_rows_q5_0_f32_len, get_rows_q5_0_f32_data, "main", 3, sizeof(vk_op_binary_push_constants), {1024, 1, 1}, {}, 1);
|
||||
@@ -5199,6 +5284,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_transpose_16, "cpy_transpose_16", cpy_transpose_16_len, cpy_transpose_16_data, "main", 2, sizeof(vk_op_unary_push_constants), {1, 1, 1}, {}, 1);
|
||||
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_Q1_0], "cpy_f32_q1_0", cpy_f32_q1_0_len, cpy_f32_q1_0_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_Q2_0], "cpy_f32_q2_0", cpy_f32_q2_0_len, cpy_f32_q2_0_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_Q4_0], "cpy_f32_q4_0", cpy_f32_q4_0_len, cpy_f32_q4_0_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_Q4_1], "cpy_f32_q4_1", cpy_f32_q4_1_len, cpy_f32_q4_1_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_f32_quant[GGML_TYPE_Q5_0], "cpy_f32_q5_0", cpy_f32_q5_0_len, cpy_f32_q5_0_data, "main", 2, sizeof(vk_op_unary_push_constants), {32, 1, 1}, {}, 1);
|
||||
@@ -5211,6 +5297,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_F16], "set_rows_" #src "_f16" #itype, set_rows_ ## src ## _f16 ## itype ## _len, set_rows_ ## src ## _f16 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_BF16], "set_rows_" #src "_bf16" #itype, set_rows_ ## src ## _bf16 ## itype ## _len, set_rows_ ## src ## _bf16 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q1_0], "set_rows_" #src "_q1_0" #itype, set_rows_ ## src ## _q1_0 ## itype ## _len, set_rows_ ## src ## _q1_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q2_0], "set_rows_" #src "_q2_0" #itype, set_rows_ ## src ## _q2_0 ## itype ## _len, set_rows_ ## src ## _q2_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q4_0], "set_rows_" #src "_q4_0" #itype, set_rows_ ## src ## _q4_0 ## itype ## _len, set_rows_ ## src ## _q4_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q4_1], "set_rows_" #src "_q4_1" #itype, set_rows_ ## src ## _q4_1 ## itype ## _len, set_rows_ ## src ## _q4_1 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
ggml_vk_create_pipeline(device, device->pipeline_set_rows ## itype [src_idx][GGML_TYPE_Q5_0], "set_rows_" #src "_q5_0" #itype, set_rows_ ## src ## _q5_0 ## itype ## _len, set_rows_ ## src ## _q5_0 ## itype ## _data, "main", 3, sizeof(vk_op_binary_push_constants), {1, 1, 1}, {1}, 1, true); \
|
||||
@@ -5226,6 +5313,7 @@ static void ggml_vk_load_shaders(vk_device& device, vk_pipeline requested) {
|
||||
|
||||
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_quant_f32[GGML_TYPE_Q1_0], "cpy_q1_0_f32", cpy_q1_0_f32_len, cpy_q1_0_f32_data, "main", 2, sizeof(vk_op_unary_push_constants), {(uint32_t)ggml_blck_size(GGML_TYPE_Q1_0), 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_quant_f32[GGML_TYPE_Q2_0], "cpy_q2_0_f32", cpy_q2_0_f32_len, cpy_q2_0_f32_data, "main", 2, sizeof(vk_op_unary_push_constants), {(uint32_t)ggml_blck_size(GGML_TYPE_Q2_0), 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_quant_f32[GGML_TYPE_Q4_0], "cpy_q4_0_f32", cpy_q4_0_f32_len, cpy_q4_0_f32_data, "main", 2, sizeof(vk_op_unary_push_constants), {(uint32_t)ggml_blck_size(GGML_TYPE_Q4_0), 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_quant_f32[GGML_TYPE_Q4_1], "cpy_q4_1_f32", cpy_q4_1_f32_len, cpy_q4_1_f32_data, "main", 2, sizeof(vk_op_unary_push_constants), {(uint32_t)ggml_blck_size(GGML_TYPE_Q4_1), 1, 1}, {}, 1);
|
||||
ggml_vk_create_pipeline(device, device->pipeline_cpy_quant_f32[GGML_TYPE_Q5_0], "cpy_q5_0_f32", cpy_q5_0_f32_len, cpy_q5_0_f32_data, "main", 2, sizeof(vk_op_unary_push_constants), {(uint32_t)ggml_blck_size(GGML_TYPE_Q5_0), 1, 1}, {}, 1);
|
||||
@@ -5860,6 +5948,7 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
bool coopmat2_support = false;
|
||||
bool coopmat2_decode_vector_support = false;
|
||||
bool pipeline_executable_properties_support = false;
|
||||
bool internally_sync_support = false;
|
||||
device->coopmat_support = false;
|
||||
device->integer_dot_product = false;
|
||||
device->shader_64b_indexing = false;
|
||||
@@ -5931,6 +6020,8 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
} else if (strcmp("VK_EXT_shader_64bit_indexing", properties.extensionName) == 0) {
|
||||
device->shader_64b_indexing = true;
|
||||
#endif
|
||||
} else if (strcmp(VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME, properties.extensionName) == 0) {
|
||||
internally_sync_support = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6117,14 +6208,6 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
device->single_queue = compute_queue_family_index == transfer_queue_family_index && queue_family_props[compute_queue_family_index].queueCount == 1;
|
||||
|
||||
std::vector<vk::DeviceQueueCreateInfo> device_queue_create_infos;
|
||||
if (compute_queue_family_index != transfer_queue_family_index) {
|
||||
device_queue_create_infos.push_back({vk::DeviceQueueCreateFlags(), compute_queue_family_index, 1, priorities});
|
||||
device_queue_create_infos.push_back({vk::DeviceQueueCreateFlags(), transfer_queue_family_index, 1, priorities + 1});
|
||||
} else if(!device->single_queue) {
|
||||
device_queue_create_infos.push_back({vk::DeviceQueueCreateFlags(), compute_queue_family_index, 2, priorities});
|
||||
} else {
|
||||
device_queue_create_infos.push_back({vk::DeviceQueueCreateFlags(), compute_queue_family_index, 1, priorities});
|
||||
}
|
||||
vk::DeviceCreateInfo device_create_info{};
|
||||
std::vector<const char *> device_extensions;
|
||||
vk::PhysicalDeviceFeatures device_features = device->physical_device.getFeatures();
|
||||
@@ -6146,6 +6229,17 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
|
||||
last_struct = (VkBaseOutStructure *)&vk12_features;
|
||||
|
||||
VkPhysicalDeviceInternallySynchronizedQueuesFeaturesKHR internally_synchronized_queues_features{};
|
||||
internally_synchronized_queues_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INTERNALLY_SYNCHRONIZED_QUEUES_FEATURES_KHR;
|
||||
internally_synchronized_queues_features.pNext = nullptr;
|
||||
internally_synchronized_queues_features.internallySynchronizedQueues = VK_FALSE;
|
||||
|
||||
if (internally_sync_support) {
|
||||
last_struct->pNext = (VkBaseOutStructure *)&internally_synchronized_queues_features;
|
||||
last_struct = (VkBaseOutStructure *)&internally_synchronized_queues_features;
|
||||
device_extensions.push_back(VK_KHR_INTERNALLY_SYNCHRONIZED_QUEUES_EXTENSION_NAME);
|
||||
}
|
||||
|
||||
VkPhysicalDevicePipelineRobustnessFeaturesEXT pl_robustness_features;
|
||||
pl_robustness_features.pNext = nullptr;
|
||||
pl_robustness_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_ROBUSTNESS_FEATURES_EXT;
|
||||
@@ -6284,6 +6378,23 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
|
||||
vkGetPhysicalDeviceFeatures2(device->physical_device, &device_features2);
|
||||
|
||||
device->has_internally_synchronized_queues = internally_synchronized_queues_features.internallySynchronizedQueues;
|
||||
|
||||
// Build queue create infos only after querying whether internally synchronized queues are enabled.
|
||||
// getQueue2() later uses the same flag, so creation/retrieval must stay consistent.
|
||||
vk::DeviceQueueCreateFlags queue_flags = device->has_internally_synchronized_queues ?
|
||||
eInternallySynchronizedKHR :
|
||||
vk::DeviceQueueCreateFlags();
|
||||
|
||||
if (compute_queue_family_index != transfer_queue_family_index) {
|
||||
device_queue_create_infos.push_back({queue_flags, compute_queue_family_index, 1, priorities});
|
||||
device_queue_create_infos.push_back({queue_flags, transfer_queue_family_index, 1, priorities + 1});
|
||||
} else if(!device->single_queue) {
|
||||
device_queue_create_infos.push_back({queue_flags, compute_queue_family_index, 2, priorities});
|
||||
} else {
|
||||
device_queue_create_infos.push_back({queue_flags, compute_queue_family_index, 1, priorities});
|
||||
}
|
||||
|
||||
device->pipeline_executable_properties_support = pipeline_executable_properties_support;
|
||||
|
||||
device->fp16 = device->fp16 && vk12_features.shaderFloat16;
|
||||
@@ -6566,7 +6677,7 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
device->device = device->physical_device.createDevice(device_create_info);
|
||||
|
||||
// Queues
|
||||
ggml_vk_create_queue(device, device->compute_queue, compute_queue_family_index, 0, { vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer }, false);
|
||||
device->compute_queue = ggml_vk_create_queue(device, compute_queue_family_index, 0, { vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer }, false);
|
||||
|
||||
// Shaders
|
||||
// Disable matmul tile sizes early if performance low or not supported
|
||||
@@ -6668,13 +6779,11 @@ static vk_device ggml_vk_get_device(size_t idx) {
|
||||
|
||||
if (!device->single_queue) {
|
||||
const uint32_t transfer_queue_index = compute_queue_family_index == transfer_queue_family_index ? 1 : 0;
|
||||
ggml_vk_create_queue(device, device->transfer_queue, transfer_queue_family_index, transfer_queue_index, { vk::PipelineStageFlagBits::eTransfer }, true);
|
||||
device->transfer_queue = ggml_vk_create_queue(device, transfer_queue_family_index, transfer_queue_index, { vk::PipelineStageFlagBits::eTransfer }, true);
|
||||
|
||||
device->async_use_transfer_queue = prefers_transfer_queue || (getenv("GGML_VK_ASYNC_USE_TRANSFER_QUEUE") != nullptr);
|
||||
} else {
|
||||
// TODO: Use pointer or reference to avoid copy
|
||||
device->transfer_queue.copyFrom(device->compute_queue);
|
||||
device->transfer_queue.cmd_pool.init(device, &device->transfer_queue);
|
||||
device->transfer_queue = ggml_vk_create_aliased_queue(device, device->compute_queue);
|
||||
|
||||
device->async_use_transfer_queue = false;
|
||||
}
|
||||
@@ -7237,7 +7346,7 @@ static void ggml_vk_init(ggml_backend_vk_context * ctx, size_t idx) {
|
||||
ctx->fence = ctx->device->device.createFence({});
|
||||
ctx->almost_ready_fence = ctx->device->device.createFence({});
|
||||
|
||||
ctx->compute_cmd_pool.init(ctx->device, &ctx->device->compute_queue);
|
||||
ctx->compute_cmd_pool.init(ctx->device, ctx->device->compute_queue.get());
|
||||
if (ctx->device->async_use_transfer_queue) {
|
||||
vk::SemaphoreTypeCreateInfo tci{ vk::SemaphoreType::eTimeline, 0 };
|
||||
vk::SemaphoreCreateInfo ci{};
|
||||
@@ -7245,7 +7354,7 @@ static void ggml_vk_init(ggml_backend_vk_context * ctx, size_t idx) {
|
||||
ctx->transfer_semaphore.s = ctx->device->device.createSemaphore(ci);
|
||||
ctx->transfer_semaphore.value = 0;
|
||||
|
||||
ctx->transfer_cmd_pool.init(ctx->device, &ctx->device->transfer_queue);
|
||||
ctx->transfer_cmd_pool.init(ctx->device, ctx->device->transfer_queue.get());
|
||||
}
|
||||
|
||||
if (vk_perf_logger_enabled) {
|
||||
@@ -7265,6 +7374,7 @@ static vk_pipeline ggml_vk_get_to_fp16(ggml_backend_vk_context * ctx, ggml_type
|
||||
switch (type) {
|
||||
case GGML_TYPE_F32:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7338,6 +7448,7 @@ static vk_matmul_pipeline ggml_vk_get_mul_mat_mat_pipeline(ggml_backend_vk_conte
|
||||
|
||||
switch (src0_type) {
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7381,6 +7492,7 @@ static vk_pipeline ggml_vk_get_dequantize_mul_mat_vec(ggml_backend_vk_context *
|
||||
|
||||
if (b_type == GGML_TYPE_Q8_1) {
|
||||
switch (a_type) {
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7405,6 +7517,7 @@ static vk_pipeline ggml_vk_get_dequantize_mul_mat_vec(ggml_backend_vk_context *
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7497,6 +7610,7 @@ static vk_matmul_pipeline ggml_vk_get_mul_mat_mat_id_pipeline(ggml_backend_vk_co
|
||||
|
||||
switch (src0_type) {
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7543,6 +7657,7 @@ static vk_pipeline ggml_vk_get_dequantize_mul_mat_vec_id(ggml_backend_vk_context
|
||||
|
||||
if (b_type == GGML_TYPE_Q8_1) {
|
||||
switch (a_type) {
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7567,6 +7682,7 @@ static vk_pipeline ggml_vk_get_dequantize_mul_mat_vec_id(ggml_backend_vk_context
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -7829,6 +7945,20 @@ static vk_context ggml_vk_get_compute_ctx(ggml_backend_vk_context * ctx) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static vk_context ggml_vk_get_transfer_ctx(ggml_backend_vk_context * ctx) {
|
||||
vk_context result;
|
||||
if (!ctx->transfer_ctx.expired()) {
|
||||
result = ctx->transfer_ctx.lock();
|
||||
} else {
|
||||
result = ggml_vk_create_context(ctx, ctx->transfer_cmd_pool);
|
||||
|
||||
ctx->transfer_ctx = result;
|
||||
ggml_vk_ctx_begin(ctx->device, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Submit any pending transfer queue work and signal the transfer semaphore.
|
||||
// The next compute context created via ggml_vk_get_compute_ctx will wait on this semaphore.
|
||||
// Returns true if work was submitted.
|
||||
@@ -8079,7 +8209,7 @@ static void ggml_vk_buffer_write_2d(vk_buffer& dst, size_t offset, const void *
|
||||
} else {
|
||||
std::lock_guard<std::recursive_mutex> guard(dst->device->mutex);
|
||||
|
||||
vk_context subctx = ggml_vk_create_temporary_context(dst->device->transfer_queue.cmd_pool);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(dst->device->transfer_queue->cmd_pool);
|
||||
ggml_vk_ctx_begin(dst->device, subctx);
|
||||
bool ret = ggml_vk_buffer_write_2d_async(subctx, dst, offset, src, spitch, dpitch, width, height, true);
|
||||
GGML_ASSERT(ret);
|
||||
@@ -8194,7 +8324,7 @@ static void ggml_vk_buffer_read_2d(vk_buffer& src, size_t offset, void * dst, si
|
||||
GGML_ASSERT(src->memory_property_flags & vk::MemoryPropertyFlagBits::eHostCoherent);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(src->device->mutex);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(src->device->compute_queue.cmd_pool);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(src->device->compute_queue->cmd_pool);
|
||||
ggml_vk_ctx_begin(src->device, subctx);
|
||||
subctx->s->buffer->buf.pipelineBarrier(
|
||||
vk::PipelineStageFlagBits::eComputeShader | vk::PipelineStageFlagBits::eTransfer,
|
||||
@@ -8220,7 +8350,7 @@ static void ggml_vk_buffer_read_2d(vk_buffer& src, size_t offset, void * dst, si
|
||||
} else {
|
||||
std::lock_guard<std::recursive_mutex> guard(src->device->mutex);
|
||||
|
||||
vk_context subctx = ggml_vk_create_temporary_context(src->device->transfer_queue.cmd_pool);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(src->device->transfer_queue->cmd_pool);
|
||||
ggml_vk_ctx_begin(src->device, subctx);
|
||||
bool ret = ggml_vk_buffer_read_2d_async(subctx, src, offset, dst, spitch, dpitch, width, height, true);
|
||||
GGML_ASSERT(ret);
|
||||
@@ -8257,7 +8387,7 @@ static void ggml_vk_buffer_copy(vk_buffer& dst, size_t dst_offset, vk_buffer& sr
|
||||
std::lock_guard<std::recursive_mutex> guard(src->device->mutex);
|
||||
VK_LOG_DEBUG("ggml_vk_buffer_copy(SINGLE_DEVICE, " << size << ")");
|
||||
// Copy within the device
|
||||
vk_context subctx = ggml_vk_create_temporary_context(src->device->transfer_queue.cmd_pool);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(src->device->transfer_queue->cmd_pool);
|
||||
ggml_vk_ctx_begin(src->device, subctx);
|
||||
ggml_vk_buffer_copy_async(subctx, dst, dst_offset, src, src_offset, size);
|
||||
ggml_vk_ctx_end(subctx);
|
||||
@@ -8300,7 +8430,7 @@ static void ggml_vk_buffer_memset(vk_buffer& dst, size_t offset, uint32_t c, siz
|
||||
}
|
||||
|
||||
std::lock_guard<std::recursive_mutex> guard(dst->device->mutex);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(dst->device->transfer_queue.cmd_pool);
|
||||
vk_context subctx = ggml_vk_create_temporary_context(dst->device->transfer_queue->cmd_pool);
|
||||
ggml_vk_ctx_begin(dst->device, subctx);
|
||||
subctx->s->buffer->buf.fillBuffer(dst->buffer, offset, size, c);
|
||||
ggml_vk_ctx_end(subctx);
|
||||
@@ -8589,6 +8719,7 @@ static vk_pipeline ggml_vk_get_cpy_pipeline(ggml_backend_vk_context * ctx, const
|
||||
if (src->type == GGML_TYPE_F32) {
|
||||
switch (to) {
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -8604,6 +8735,7 @@ static vk_pipeline ggml_vk_get_cpy_pipeline(ggml_backend_vk_context * ctx, const
|
||||
if (to == GGML_TYPE_F32) {
|
||||
switch (src->type) {
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -9030,7 +9162,7 @@ static bool ggml_vk_should_use_mmvq(const vk_device& device, uint32_t m, uint32_
|
||||
// Quantization overhead is not worth it for small k
|
||||
switch (device->vendor_id) {
|
||||
case VK_VENDOR_ID_NVIDIA:
|
||||
if (src0_type == GGML_TYPE_Q2_K || src0_type == GGML_TYPE_Q3_K || src0_type == GGML_TYPE_IQ1_S || src0_type == GGML_TYPE_IQ1_M) {
|
||||
if (src0_type == GGML_TYPE_Q2_0 || src0_type == GGML_TYPE_Q2_K || src0_type == GGML_TYPE_Q3_K || src0_type == GGML_TYPE_IQ1_S || src0_type == GGML_TYPE_IQ1_M) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -9058,7 +9190,7 @@ static bool ggml_vk_should_use_mmvq(const vk_device& device, uint32_t m, uint32_
|
||||
}
|
||||
case VK_VENDOR_ID_INTEL:
|
||||
if (device->architecture == vk_device_architecture::INTEL_XE2) {
|
||||
if (src0_type == GGML_TYPE_Q2_K || src0_type == GGML_TYPE_Q3_K || src0_type == GGML_TYPE_Q6_K) {
|
||||
if (src0_type == GGML_TYPE_Q2_0 || src0_type == GGML_TYPE_Q2_K || src0_type == GGML_TYPE_Q3_K || src0_type == GGML_TYPE_Q6_K) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -15633,13 +15765,7 @@ static void ggml_backend_vk_set_tensor_2d_async(ggml_backend_t backend, ggml_ten
|
||||
vk_context cpy_ctx;
|
||||
|
||||
if (ctx->device->async_use_transfer_queue) {
|
||||
if (ctx->transfer_ctx.expired()) {
|
||||
cpy_ctx = ggml_vk_create_context(ctx, ctx->transfer_cmd_pool);
|
||||
ctx->transfer_ctx = cpy_ctx;
|
||||
ggml_vk_ctx_begin(ctx->device, cpy_ctx);
|
||||
} else {
|
||||
cpy_ctx = ctx->transfer_ctx.lock();
|
||||
}
|
||||
cpy_ctx = ggml_vk_get_transfer_ctx(ctx);
|
||||
} else {
|
||||
cpy_ctx = ggml_vk_get_compute_ctx(ctx);
|
||||
}
|
||||
@@ -15785,13 +15911,7 @@ static bool ggml_backend_vk_cpy_tensor_async(ggml_backend_t backend_src, ggml_ba
|
||||
|
||||
vk_context cpy_ctx;
|
||||
if (ctx->device->async_use_transfer_queue) {
|
||||
if (ctx->transfer_ctx.expired()) {
|
||||
cpy_ctx = ggml_vk_create_context(ctx, ctx->transfer_cmd_pool);
|
||||
ctx->transfer_ctx = cpy_ctx;
|
||||
ggml_vk_ctx_begin(ctx->device, cpy_ctx);
|
||||
} else {
|
||||
cpy_ctx = ctx->transfer_ctx.lock();
|
||||
}
|
||||
cpy_ctx = ggml_vk_get_transfer_ctx(ctx);
|
||||
} else {
|
||||
cpy_ctx = ggml_vk_get_compute_ctx(ctx);
|
||||
}
|
||||
@@ -15838,19 +15958,17 @@ static void ggml_vk_synchronize(ggml_backend_vk_context * ctx) {
|
||||
1, &ctx->transfer_semaphore.value,
|
||||
0, nullptr,
|
||||
};
|
||||
vk::PipelineStageFlags stage = ctx->device->transfer_queue.stage_flags;
|
||||
vk::PipelineStageFlags stage = ctx->device->transfer_queue->stage_flags;
|
||||
vk::SubmitInfo si{
|
||||
1, &ctx->transfer_semaphore.s, &stage,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
};
|
||||
si.setPNext(&tl_info);
|
||||
std::lock_guard<std::mutex> guard(queue_mutex);
|
||||
ctx->device->compute_queue.queue.submit({ si }, ctx->fence);
|
||||
ctx->device->compute_queue->handle->submit({ si }, ctx->fence);
|
||||
ctx->transfer_semaphore_last_submitted = ctx->transfer_semaphore.value;
|
||||
} else {
|
||||
std::lock_guard<std::mutex> guard(queue_mutex);
|
||||
ctx->device->compute_queue.queue.submit({}, ctx->fence);
|
||||
ctx->device->compute_queue->handle->submit({}, ctx->fence);
|
||||
}
|
||||
ggml_vk_wait_for_fence(ctx);
|
||||
ctx->submit_pending = false;
|
||||
@@ -16412,7 +16530,9 @@ static ggml_status ggml_backend_vk_graph_compute(ggml_backend_t backend, ggml_cg
|
||||
vk::DebugUtilsLabelEXT dul = {};
|
||||
dul.pLabelName = "ggml_backend_vk_graph_compute";
|
||||
dul.color = std::array<float,4>{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
vk_instance.pfn_vkQueueBeginDebugUtilsLabelEXT(ctx->device->compute_queue.queue, reinterpret_cast<VkDebugUtilsLabelEXT*>(&dul));
|
||||
|
||||
std::lock_guard<vk_queue_handle> guard(*ctx->device->compute_queue->handle);
|
||||
vk_instance.pfn_vkQueueBeginDebugUtilsLabelEXT(ctx->device->compute_queue->handle->queue, reinterpret_cast<VkDebugUtilsLabelEXT*>(&dul));
|
||||
}
|
||||
|
||||
ctx->prealloc_size_add_rms_partials_offset = 0;
|
||||
@@ -17123,6 +17243,11 @@ static void ggml_backend_vk_event_wait(ggml_backend_t backend, ggml_backend_even
|
||||
if (vkev->has_event) {
|
||||
// Wait for latest event
|
||||
ggml_vk_wait_events(compute_ctx, { vkev->event });
|
||||
|
||||
if (ctx->device->async_use_transfer_queue) {
|
||||
vk_context transfer_ctx = ggml_vk_get_transfer_ctx(ctx);
|
||||
transfer_ctx->s->wait_semaphores.push_back(vkev->tl_semaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17422,6 +17547,7 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -17527,6 +17653,7 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -17567,6 +17694,7 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -17591,6 +17719,7 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
@@ -17607,6 +17736,7 @@ static bool ggml_backend_vk_device_supports_op(ggml_backend_dev_t dev, const ggm
|
||||
case GGML_TYPE_F16:
|
||||
case GGML_TYPE_BF16:
|
||||
case GGML_TYPE_Q1_0:
|
||||
case GGML_TYPE_Q2_0:
|
||||
case GGML_TYPE_Q4_0:
|
||||
case GGML_TYPE_Q4_1:
|
||||
case GGML_TYPE_Q5_0:
|
||||
|
||||
@@ -208,6 +208,36 @@ void quantize(uint dst_idx, uint src_idx)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DATA_A_Q2_0)
|
||||
uint quantize_q2_0(float x)
|
||||
{
|
||||
const int q = int(x >= 0.0f ? floor(x + 0.5f) : ceil(x - 0.5f)) + 1;
|
||||
return uint(clamp(q, 0, 3));
|
||||
}
|
||||
|
||||
void quantize(uint dst_idx, uint src_idx)
|
||||
{
|
||||
float amax = 0.0f;
|
||||
|
||||
[[unroll]] for (int j = 0; j < QUANT_K_Q2_0; ++j) {
|
||||
amax = max(amax, abs(float(data_s[src_idx + j])));
|
||||
}
|
||||
|
||||
const float d = amax;
|
||||
const float id = d != 0.0f ? 1.0f / d : 0.0f;
|
||||
|
||||
data_q[dst_idx].d = float16_t(d);
|
||||
|
||||
[[unroll]] for (int j = 0; j < QUANT_K_Q2_0 / 4; ++j) {
|
||||
const uint q0 = quantize_q2_0(float(data_s[src_idx + 4*j ]) * id);
|
||||
const uint q1 = quantize_q2_0(float(data_s[src_idx + 4*j + 1]) * id);
|
||||
const uint q2 = quantize_q2_0(float(data_s[src_idx + 4*j + 2]) * id);
|
||||
const uint q3 = quantize_q2_0(float(data_s[src_idx + 4*j + 3]) * id);
|
||||
data_q[dst_idx].qs[j] = uint8_t(q0 | (q1 << 2u) | (q2 << 4u) | (q3 << 6u));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DATA_A_IQ4_NL)
|
||||
uint best_index(float x) {
|
||||
if (x <= kvalues_iq4nl[0]) return 0;
|
||||
|
||||
@@ -143,6 +143,17 @@ vec4 dequantize4(uint ib, uint iqs, uint a_offset) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DATA_A_Q2_0)
|
||||
vec2 dequantize(uint ib, uint iqs, uint a_offset) {
|
||||
const uint bits = uint(data_a[a_offset + ib].qs[iqs / 4u]) >> (2u * (iqs % 4u));
|
||||
return vec2(bits & 3u, (bits >> 2u) & 3u) - 1.0f;
|
||||
}
|
||||
vec4 dequantize4(uint ib, uint iqs, uint a_offset) {
|
||||
const uint bits = uint(data_a[a_offset + ib].qs[iqs / 4u]);
|
||||
return vec4(bits & 3u, (bits >> 2u) & 3u, (bits >> 4u) & 3u, bits >> 6u) - 1.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DATA_A_IQ1_S)
|
||||
vec2 dequantize(uint ib, uint iqs, uint a_offset) {
|
||||
const uint ib32 = iqs / 32;
|
||||
@@ -547,7 +558,7 @@ vec2 get_dm(uint ib, uint a_offset) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DATA_A_Q4_0) || defined(DATA_A_Q5_0) || defined(DATA_A_Q8_0) || defined(DATA_A_IQ1_S) || defined(DATA_A_IQ2_XXS) || defined(DATA_A_IQ2_XS) || defined(DATA_A_IQ2_S) || defined(DATA_A_IQ3_XXS) || defined(DATA_A_IQ3_S) || defined(DATA_A_IQ4_XS) || defined(DATA_A_IQ4_NL)
|
||||
#if defined(DATA_A_Q2_0) || defined(DATA_A_Q4_0) || defined(DATA_A_Q5_0) || defined(DATA_A_Q8_0) || defined(DATA_A_IQ1_S) || defined(DATA_A_IQ2_XXS) || defined(DATA_A_IQ2_XS) || defined(DATA_A_IQ2_S) || defined(DATA_A_IQ3_XXS) || defined(DATA_A_IQ3_S) || defined(DATA_A_IQ4_XS) || defined(DATA_A_IQ4_NL)
|
||||
vec2 get_dm(uint ib, uint a_offset) {
|
||||
return vec2(float(data_a[a_offset + ib].d), 0);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,26 @@ f16vec4 dequantFuncQ1_0_v(const in decodeBufQ1_0 bl, const in uint blockCoords[2
|
||||
(qs_nib & 8u) != 0u ? d : md);
|
||||
}
|
||||
|
||||
layout(buffer_reference, std430, buffer_reference_align = 2) buffer decodeBufQ2_0 {
|
||||
block_q2_0 block;
|
||||
};
|
||||
|
||||
float16_t dequantFuncQ2_0(const in decodeBufQ2_0 bl, const in uint blockCoords[2], const in uint coordInBlock[2])
|
||||
{
|
||||
const float16_t d = bl.block.d;
|
||||
const uint idx = coordInBlock[1];
|
||||
const uint bits = uint(bl.block.qs[idx >> 2]) >> (2u * (idx & 3u));
|
||||
return (float16_t(bits & 3u) - float16_t(1.0)) * d;
|
||||
}
|
||||
|
||||
f16vec4 dequantFuncQ2_0_v(const in decodeBufQ2_0 bl, const in uint blockCoords[2], const in uint coordInBlock[2])
|
||||
{
|
||||
const float16_t d = bl.block.d;
|
||||
const uint idx = coordInBlock[1];
|
||||
const uint bits = uint(bl.block.qs[idx >> 2]);
|
||||
return f16vec4((vec4(bits & 3u, (bits >> 2u) & 3u, (bits >> 4u) & 3u, bits >> 6u) - 1.0f) * float(d));
|
||||
}
|
||||
|
||||
layout(buffer_reference, std430, buffer_reference_align = 2) buffer decodeBufQ4_0 {
|
||||
block_q4_0_packed16 block;
|
||||
};
|
||||
@@ -1330,6 +1350,9 @@ f16vec4 dequantFuncNVFP4_v(const in decodeBufNVFP4 bl, const in uint blockCoords
|
||||
#if defined(DATA_A_Q1_0)
|
||||
#define dequantFuncA dequantFuncQ1_0
|
||||
#define dequantFuncA_v dequantFuncQ1_0_v
|
||||
#elif defined(DATA_A_Q2_0)
|
||||
#define dequantFuncA dequantFuncQ2_0
|
||||
#define dequantFuncA_v dequantFuncQ2_0_v
|
||||
#elif defined(DATA_A_Q4_0)
|
||||
#define dequantFuncA dequantFuncQ4_0
|
||||
#define dequantFuncA_v dequantFuncQ4_0_v
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user