#ifndef GRAPH_BACKEND_DNNL_KERNELS_MQA_DECOMP_CONFIG_HPP
#define GRAPH_BACKEND_DNNL_KERNELS_MQA_DECOMP_CONFIG_HPP
#include <algorithm>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "oneapi/dnnl/dnnl.hpp"
#include "common/dnnl_thread.hpp"
#include "graph/interface/c_types_map.hpp"
#include "graph/backend/dnnl/scratchpad.hpp"
#include "graph/backend/dnnl/subgraph.hpp"
namespace dnnl {
namespace impl {
namespace graph {
namespace dnnl_impl {
using ltw = logical_tensor_wrapper_t;
using op_ptr = std::shared_ptr<op_t>;
using registry_key = size_t;
struct mqa_reorder_t {
public:
status_t init(const dnnl::reorder::primitive_desc &pd) {
is_inplace_ = pd.src_desc() == pd.dst_desc();
reorder_ = dnnl::reorder(pd);
return status::success;
}
bool get_inplace() const { return is_inplace_; }
status_t execute(const dnnl::stream &astream,
const std::unordered_map<int, dnnl::memory> &args) const {
if (is_inplace_) {
void *handle = args.at(DNNL_ARG_SRC).get_data_handle();
args.at(DNNL_ARG_DST).set_data_handle(handle);
} else
dnnl_primitive_execute_without_tp_hook(reorder_, astream, args);
return status::success;
}
private:
dnnl::primitive reorder_;
bool is_inplace_ = false;
};
struct mqa_decomp_config_t {
public:
mqa_decomp_config_t() = default;
memory::dim batch_size, num_head, seq_len, size_per_head;
int nthr;
std::vector<int> graph_inport;
primitive sub_mm1_prim, sub_softmax_prim, sub_mm2_prim;
mqa_reorder_t sub_reorder0, sub_reorder1, sub_reorder2, sub_reorder3;
std::unordered_map<int, memory> sub_reorder0_args, sub_reorder1_args,
sub_mm1_args, sub_softmax_args, sub_reorder2_args, sub_mm2_args,
sub_reorder3_args;
std::unordered_map<dnnl_memory_t, registry_key> mem_key_map;
memory sub_src1;
memory sub_wei1_user;
memory sub_mm1_src, sub_mm1_wei, sub_mm1_dst, sub_mm1_post_add;
memory sub_softmax_dst;
memory sub_src2_user;
memory sub_mm2_src, sub_mm2_dst;
memory sub_dst_user;
memory sub_scratchpad;
memory sub_max_src1_src2, sub_max_dst1_dst2;
private:
std::vector<std::shared_ptr<op_t>> mqa_op;
public:
bool initial_check(const std::shared_ptr<subgraph_t> &sg,
const std::vector<logical_tensor_t> &inputs);
template <bool quantized = false,
memory::data_type dt = memory::data_type::f32>
status_t construct_params(std::shared_ptr<subgraph_t> &sg,
registry_t &mqa_registry, const dnnl::engine &p_engine,
const std::vector<logical_tensor_t> &inputs);
private:
op_ptr get_post_op(const op_ptr &op) const;
status_t record_input_offset(const std::shared_ptr<subgraph_t> &sg,
const std::vector<logical_tensor_t> &inputs);
status_t record_mqa_ops(std::shared_ptr<subgraph_t> &sg);
void memory_planning(registry_t &mqa_registry);
template <typename attr_dt, typename target_dt>
target_dt get_attr_value(
std::shared_ptr<op_t> &op, int i, op_attr_t attr_name) {
const auto in_val = op->get_input_value(i);
auto &producer = in_val->get_producer();
return static_cast<target_dt>(
producer.get_attr<std::vector<attr_dt>>(attr_name)[0]);
}
dnnl::primitive_attr make_primitive_attr(std::shared_ptr<op_t> &op);
};
} } } }
#endif