#ifndef GGML_ZDNN_COMMON_HPP
#define GGML_ZDNN_COMMON_HPP
#include "ggml.h"
#include "ggml-impl.h"
#include "zdnn.h"
#include "scratch.hpp"
#include <algorithm>
#include <cstdlib>
#include <future>
#include <map>
#include <memory>
#include <utility>
#include <vector>
#define GGML_ZDNN_NAME "zDNN"
#define GGML_ZDNN_VERSION ZDNN_VERNUM
#define ZDNN_CHECK(stmt) \
do { \
zdnn_status status = (stmt); \
GGML_ASSERT(status == ZDNN_OK); \
} while (0);
struct ggml_backend_zdnn_device_context {
int zdnn_device;
int zdnn_device_ref_count;
bool has_parmblkformat_0;
bool has_parmblkformat_1;
size_t max_size;
char name[128];
};
struct ggml_backend_zdnn_buffer {
void * data;
ggml_backend_zdnn_buffer * extra; size_t size;
zdnn_tensor_desc pre_tfm_desc;
zdnn_tensor_desc tfm_desc;
zdnn_ztensor ztensor;
std::vector<float> scales; std::vector<float> channel_scales;
char name[GGML_MAX_NAME];
};
struct ggml_backend_zdnn_buffer_context {
void * all_data;
size_t all_size;
bool owned;
int n_buffers;
std::vector<std::unique_ptr<ggml_backend_zdnn_buffer>> buffers;
};
struct ggml_backend_zdnn_context {
int device;
int32_t n_threads; ggml_cgraph * gf;
std::map<std::pair<int64_t, int64_t>, std::unique_ptr<ggml_backend_zdnn_buffer>> zero_bias;
ggml_zdnn_pool pool; };
static inline void ggml_zdnn_init_scratch_ztensor(ggml_backend_zdnn_context * ctx,
zdnn_tensor_desc * pre_tfm_desc,
zdnn_tensor_desc * tfm_desc,
zdnn_ztensor * ztensor,
ggml_zdnn_pool_alloc<uint8_t> & scratch) {
const uint64_t size = zdnn_getsize_ztensor(tfm_desc);
zdnn_init_quantized_ztensor(pre_tfm_desc, tfm_desc, 1.0f, 0.0f, ztensor);
ztensor->buffer = scratch.alloc(ctx->pool, size);
ztensor->buffer_size = size;
}
static inline void ggml_zdnn_init_scratch_ztensor_dlf16(ggml_backend_zdnn_context * ctx,
zdnn_tensor_desc * pre_tfm_desc,
zdnn_tensor_desc * tfm_desc,
zdnn_ztensor * ztensor,
ggml_zdnn_pool_alloc<uint8_t> & scratch) {
const uint64_t size = zdnn_getsize_ztensor(tfm_desc);
zdnn_init_ztensor(pre_tfm_desc, tfm_desc, ztensor);
ztensor->buffer = scratch.alloc(ctx->pool, size);
ztensor->buffer_size = size;
}
static inline zdnn_ztensor ggml_zdnn_stack_view(zdnn_tensor_desc * pre_tfm_desc,
zdnn_tensor_desc * tfm_desc,
const zdnn_ztensor & src,
int64_t n_stacks,
int64_t s0,
int64_t n) {
GGML_ASSERT(src.buffer_size % n_stacks == 0);
const uint64_t stack_bytes = src.buffer_size / n_stacks;
*pre_tfm_desc = *src.pre_transformed_desc;
*tfm_desc = *src.transformed_desc;
switch (pre_tfm_desc->layout) {
case ZDNN_3DS:
{
pre_tfm_desc->dim3 = n;
} break;
case ZDNN_2DS:
{
pre_tfm_desc->dim2 = n;
} break;
default:
GGML_ABORT("%s: unsupported stacked layout", __func__);
}
tfm_desc->dim4 = n;
GGML_ASSERT(zdnn_getsize_ztensor(tfm_desc) == n*stack_bytes);
zdnn_ztensor view = src;
view.pre_transformed_desc = pre_tfm_desc;
view.transformed_desc = tfm_desc;
view.buffer = (char *) src.buffer + s0*stack_bytes;
view.buffer_size = n * stack_bytes;
return view;
}
static inline const zdnn_ztensor & ggml_zdnn_zero_bias(ggml_backend_zdnn_context * ctx, int64_t n_stacks, int64_t ne0) {
std::unique_ptr<ggml_backend_zdnn_buffer> & bias = ctx->zero_bias[{ n_stacks, ne0 }];
if (!bias) {
bias = std::make_unique<ggml_backend_zdnn_buffer>();
std::vector<float> zeros(n_stacks * ne0, 0.0f);
zdnn_init_pre_transformed_desc(ZDNN_2DS, FP32, &bias->pre_tfm_desc, n_stacks, ne0);
ZDNN_CHECK(zdnn_generate_transformed_desc(&bias->pre_tfm_desc, &bias->tfm_desc));
ZDNN_CHECK(zdnn_init_ztensor_with_malloc(&bias->pre_tfm_desc, &bias->tfm_desc, &bias->ztensor));
ZDNN_CHECK(zdnn_transform_ztensor(&bias->ztensor, zeros.data()));
}
return bias->ztensor;
}
template <typename F>
static inline void ggml_zdnn_parallel_for(int32_t n_threads, int64_t n, const F & f) {
n_threads = (int32_t)std::max<int64_t>(1, std::min<int64_t>(n_threads, n));
std::vector<std::future<void>> tasks;
for (int32_t ith = 1; ith < n_threads; ith++) {
const int64_t start = (ith + 0) * n / n_threads;
const int64_t end = (ith + 1) * n / n_threads;
tasks.push_back(std::async(std::launch::async, [&f, start, end]() { f(start, end); }));
}
f(0, n/n_threads);
for (auto & task : tasks) {
task.get();
}
}
#endif