mirror of
https://github.com/ggerganov/llama.cpp.git
synced 2024-12-27 06:39:25 +01:00
vulkan: Implement "fast divide" (mul+shift) for unary ops like copy (#10642)
This commit is contained in:
parent
40c6d79fb5
commit
2759916d86
@ -353,7 +353,45 @@ struct vk_op_unary_push_constants {
|
|||||||
uint32_t ne10; uint32_t ne11; uint32_t ne12; uint32_t ne13; uint32_t nb10; uint32_t nb11; uint32_t nb12; uint32_t nb13;
|
uint32_t ne10; uint32_t ne11; uint32_t ne12; uint32_t ne13; uint32_t nb10; uint32_t nb11; uint32_t nb12; uint32_t nb13;
|
||||||
uint32_t d_offset;
|
uint32_t d_offset;
|
||||||
float param1; float param2;
|
float param1; float param2;
|
||||||
|
uint32_t ne0_012mp; uint32_t ne0_012L;
|
||||||
|
uint32_t ne0_01mp; uint32_t ne0_01L;
|
||||||
|
uint32_t ne0_0mp; uint32_t ne0_0L;
|
||||||
|
uint32_t ne1_012mp; uint32_t ne1_012L;
|
||||||
|
uint32_t ne1_01mp; uint32_t ne1_01L;
|
||||||
|
uint32_t ne1_0mp; uint32_t ne1_0L;
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(vk_op_unary_push_constants) <= 128, "sizeof(vk_op_unary_push_constants) must be <= 128");
|
||||||
|
|
||||||
|
// See https://gmplib.org/~tege/divcnst-pldi94.pdf figure 4.1.
|
||||||
|
// Precompute mp (m' in the paper) and L such that division
|
||||||
|
// can be computed using a multiply (high 32b of 64b result)
|
||||||
|
// and a shift:
|
||||||
|
//
|
||||||
|
// n/d = (mulhi(n, mp) + n) >> L;
|
||||||
|
void init_fastdiv_values(uint32_t d, uint32_t &mp, uint32_t &L)
|
||||||
|
{
|
||||||
|
// compute L = ceil(log2(d));
|
||||||
|
L = 0;
|
||||||
|
while (L < 32 && (uint32_t{1} << L) < d) {
|
||||||
|
L++;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp = (uint32_t)((uint64_t{1} << 32) * ((uint64_t{1} << L) - d) / d + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> void init_pushconst_fastdiv(T &p) {
|
||||||
|
static_assert(!std::is_const<T>::value, "unexpected type");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void init_pushconst_fastdiv(vk_op_unary_push_constants &p) {
|
||||||
|
// Compute magic values to divide by these six numbers.
|
||||||
|
init_fastdiv_values(p.ne02*p.ne01*p.ne00, p.ne0_012mp, p.ne0_012L);
|
||||||
|
init_fastdiv_values(p.ne01*p.ne00, p.ne0_01mp, p.ne0_01L);
|
||||||
|
init_fastdiv_values(p.ne00, p.ne0_0mp, p.ne0_0L);
|
||||||
|
init_fastdiv_values(p.ne12*p.ne11*p.ne10, p.ne1_012mp, p.ne1_012L);
|
||||||
|
init_fastdiv_values(p.ne11*p.ne10, p.ne1_01mp, p.ne1_01L);
|
||||||
|
init_fastdiv_values(p.ne10, p.ne1_0mp, p.ne1_0L);
|
||||||
|
}
|
||||||
|
|
||||||
struct vk_op_binary_push_constants {
|
struct vk_op_binary_push_constants {
|
||||||
uint32_t ne;
|
uint32_t ne;
|
||||||
@ -2914,13 +2952,14 @@ static void ggml_vk_cpy_to_contiguous(ggml_backend_vk_context * ctx, vk_context&
|
|||||||
elements = { ne, 1, 1 };
|
elements = { ne, 1, 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const vk_op_unary_push_constants pc = {
|
vk_op_unary_push_constants pc = {
|
||||||
(uint32_t)ne,
|
(uint32_t)ne,
|
||||||
(uint32_t)tensor->ne[0], (uint32_t)tensor->ne[1], (uint32_t)tensor->ne[2], (uint32_t)tensor->ne[3], (uint32_t)tensor->nb[0] / tensor_type_size, (uint32_t)tensor->nb[1] / tensor_type_size, (uint32_t)tensor->nb[2] / tensor_type_size, (uint32_t)tensor->nb[3] / tensor_type_size,
|
(uint32_t)tensor->ne[0], (uint32_t)tensor->ne[1], (uint32_t)tensor->ne[2], (uint32_t)tensor->ne[3], (uint32_t)tensor->nb[0] / tensor_type_size, (uint32_t)tensor->nb[1] / tensor_type_size, (uint32_t)tensor->nb[2] / tensor_type_size, (uint32_t)tensor->nb[3] / tensor_type_size,
|
||||||
(uint32_t)tensor->ne[0], (uint32_t)tensor->ne[1], (uint32_t)tensor->ne[2], (uint32_t)tensor->ne[3], 1 , (uint32_t)tensor->ne[0] , (uint32_t)(tensor->ne[0] * tensor->ne[1]) , (uint32_t)(tensor->ne[0] * tensor->ne[1] * tensor->ne[2]),
|
(uint32_t)tensor->ne[0], (uint32_t)tensor->ne[1], (uint32_t)tensor->ne[2], (uint32_t)tensor->ne[3], 1 , (uint32_t)tensor->ne[0] , (uint32_t)(tensor->ne[0] * tensor->ne[1]) , (uint32_t)(tensor->ne[0] * tensor->ne[1] * tensor->ne[2]),
|
||||||
0,
|
0,
|
||||||
0.0f, 0.0f,
|
0.0f, 0.0f,
|
||||||
};
|
};
|
||||||
|
init_pushconst_fastdiv(pc);
|
||||||
ggml_vk_sync_buffers(subctx);
|
ggml_vk_sync_buffers(subctx);
|
||||||
ggml_vk_dispatch_pipeline(ctx, subctx, pipeline, { in, out }, sizeof(vk_op_unary_push_constants), &pc, elements);
|
ggml_vk_dispatch_pipeline(ctx, subctx, pipeline, { in, out }, sizeof(vk_op_unary_push_constants), &pc, elements);
|
||||||
}
|
}
|
||||||
@ -4125,7 +4164,7 @@ static bool ggml_vk_op_supports_incontiguous(ggml_op op) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename PC>
|
template<typename PC>
|
||||||
static void ggml_vk_op_f32(ggml_backend_vk_context * ctx, vk_context& subctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * src2, ggml_tensor * dst, ggml_op op, const PC&& pc, bool dryrun = false) {
|
static void ggml_vk_op_f32(ggml_backend_vk_context * ctx, vk_context& subctx, const ggml_tensor * src0, const ggml_tensor * src1, const ggml_tensor * src2, ggml_tensor * dst, ggml_op op, PC&& pc, bool dryrun = false) {
|
||||||
VK_LOG_DEBUG("ggml_vk_op_f32((" << src0 << ", name=" << src0->name << ", type=" << src0->type << ", ne0=" << src0->ne[0] << ", ne1=" << src0->ne[1] << ", ne2=" << src0->ne[2] << ", ne3=" << src0->ne[3] << ", nb0=" << src0->nb[0] << ", nb1=" << src0->nb[1] << ", nb2=" << src0->nb[2] << ", nb3=" << src0->nb[3];
|
VK_LOG_DEBUG("ggml_vk_op_f32((" << src0 << ", name=" << src0->name << ", type=" << src0->type << ", ne0=" << src0->ne[0] << ", ne1=" << src0->ne[1] << ", ne2=" << src0->ne[2] << ", ne3=" << src0->ne[3] << ", nb0=" << src0->nb[0] << ", nb1=" << src0->nb[1] << ", nb2=" << src0->nb[2] << ", nb3=" << src0->nb[3];
|
||||||
if (src1 != nullptr) {
|
if (src1 != nullptr) {
|
||||||
std::cerr << "), (" << src1 << ", name=" << src1->name << ", type=" << src1->type << ", ne0=" << src1->ne[0] << ", ne1=" << src1->ne[1] << ", ne2=" << src1->ne[2] << ", ne3=" << src1->ne[3] << ", nb0=" << src1->nb[0] << ", nb1=" << src1->nb[1] << ", nb2=" << src1->nb[2] << ", nb3=" << src1->nb[3];
|
std::cerr << "), (" << src1 << ", name=" << src1->name << ", type=" << src1->type << ", ne0=" << src1->ne[0] << ", ne1=" << src1->ne[1] << ", ne2=" << src1->ne[2] << ", ne3=" << src1->ne[3] << ", nb0=" << src1->nb[0] << ", nb1=" << src1->nb[1] << ", nb2=" << src1->nb[2] << ", nb3=" << src1->nb[3];
|
||||||
@ -4165,6 +4204,8 @@ static void ggml_vk_op_f32(ggml_backend_vk_context * ctx, vk_context& subctx, co
|
|||||||
const uint64_t ned3 = dst->ne[3];
|
const uint64_t ned3 = dst->ne[3];
|
||||||
const uint64_t ned = ned0 * ned1;
|
const uint64_t ned = ned0 * ned1;
|
||||||
|
|
||||||
|
init_pushconst_fastdiv(pc);
|
||||||
|
|
||||||
vk_pipeline pipeline = ggml_vk_op_get_pipeline(ctx, src0, src1, src2, dst, op);
|
vk_pipeline pipeline = ggml_vk_op_get_pipeline(ctx, src0, src1, src2, dst, op);
|
||||||
|
|
||||||
if (pipeline == nullptr) {
|
if (pipeline == nullptr) {
|
||||||
|
@ -8,6 +8,13 @@ layout (push_constant) uniform parameter
|
|||||||
uint ne10; uint ne11; uint ne12; uint ne13; uint nb10; uint nb11; uint nb12; uint nb13;
|
uint ne10; uint ne11; uint ne12; uint ne13; uint nb10; uint nb11; uint nb12; uint nb13;
|
||||||
uint d_offset;
|
uint d_offset;
|
||||||
float param1; float param2;
|
float param1; float param2;
|
||||||
|
|
||||||
|
uint ne0_012mp; uint ne0_012L;
|
||||||
|
uint ne0_01mp; uint ne0_01L;
|
||||||
|
uint ne0_0mp; uint ne0_0L;
|
||||||
|
uint ne1_012mp; uint ne1_012L;
|
||||||
|
uint ne1_01mp; uint ne1_01L;
|
||||||
|
uint ne1_0mp; uint ne1_0L;
|
||||||
} p;
|
} p;
|
||||||
|
|
||||||
layout (binding = 0) readonly buffer A {A_TYPE data_a[];};
|
layout (binding = 0) readonly buffer A {A_TYPE data_a[];};
|
||||||
@ -17,22 +24,30 @@ uint get_idx() {
|
|||||||
return gl_GlobalInvocationID.z * 262144 + gl_GlobalInvocationID.y * 512 + gl_GlobalInvocationID.x;
|
return gl_GlobalInvocationID.z * 262144 + gl_GlobalInvocationID.y * 512 + gl_GlobalInvocationID.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// see init_fastdiv_values in ggml-vulkan.cpp
|
||||||
|
uint fastdiv(uint n, uint mp, uint L) {
|
||||||
|
uint msbs, lsbs;
|
||||||
|
// msbs = mulhi(n, mp)
|
||||||
|
umulExtended(n, mp, msbs, lsbs);
|
||||||
|
return (msbs + n) >> L;
|
||||||
|
}
|
||||||
|
|
||||||
uint src0_idx(uint idx) {
|
uint src0_idx(uint idx) {
|
||||||
const uint i03 = idx / (p.ne02*p.ne01*p.ne00);
|
const uint i03 = fastdiv(idx, p.ne0_012mp, p.ne0_012L);
|
||||||
const uint i03_offset = i03 * p.ne02*p.ne01*p.ne00;
|
const uint i03_offset = i03 * p.ne02*p.ne01*p.ne00;
|
||||||
const uint i02 = (idx - i03_offset) / (p.ne01*p.ne00);
|
const uint i02 = fastdiv(idx - i03_offset, p.ne0_01mp, p.ne0_01L);
|
||||||
const uint i02_offset = i02*p.ne01*p.ne00;
|
const uint i02_offset = i02*p.ne01*p.ne00;
|
||||||
const uint i01 = (idx - i03_offset - i02_offset) / p.ne00;
|
const uint i01 = fastdiv(idx - i03_offset - i02_offset, p.ne0_0mp, p.ne0_0L);
|
||||||
const uint i00 = idx - i03_offset - i02_offset - i01*p.ne00;
|
const uint i00 = idx - i03_offset - i02_offset - i01*p.ne00;
|
||||||
return i03*p.nb03 + i02*p.nb02 + i01*p.nb01 + i00*p.nb00;
|
return i03*p.nb03 + i02*p.nb02 + i01*p.nb01 + i00*p.nb00;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint dst_idx(uint idx) {
|
uint dst_idx(uint idx) {
|
||||||
const uint i13 = idx / (p.ne12*p.ne11*p.ne10);
|
const uint i13 = fastdiv(idx, p.ne1_012mp, p.ne1_012L);
|
||||||
const uint i13_offset = i13 * p.ne12*p.ne11*p.ne10;
|
const uint i13_offset = i13 * p.ne12*p.ne11*p.ne10;
|
||||||
const uint i12 = (idx - i13_offset) / (p.ne11*p.ne10);
|
const uint i12 = fastdiv(idx - i13_offset, p.ne1_01mp, p.ne1_01L);
|
||||||
const uint i12_offset = i12*p.ne11*p.ne10;
|
const uint i12_offset = i12*p.ne11*p.ne10;
|
||||||
const uint i11 = (idx - i13_offset - i12_offset) / p.ne10;
|
const uint i11 = fastdiv(idx - i13_offset - i12_offset, p.ne1_0mp, p.ne1_0L);
|
||||||
const uint i10 = idx - i13_offset - i12_offset - i11*p.ne10;
|
const uint i10 = idx - i13_offset - i12_offset - i11*p.ne10;
|
||||||
return i13*p.nb13 + i12*p.nb12 + i11*p.nb11 + i10*p.nb10;
|
return i13*p.nb13 + i12*p.nb12 + i11*p.nb11 + i10*p.nb10;
|
||||||
}
|
}
|
||||||
|
@ -3862,6 +3862,8 @@ static std::vector<std::unique_ptr<test_case>> make_test_cases_perf() {
|
|||||||
test_cases.emplace_back(new test_bin_bcast(ggml_add, GGML_TYPE_F32, {4096, 1, 1, 1}, {1, 512, 1, 1}));
|
test_cases.emplace_back(new test_bin_bcast(ggml_add, GGML_TYPE_F32, {4096, 1, 1, 1}, {1, 512, 1, 1}));
|
||||||
|
|
||||||
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_F16, {512, 3072, 1, 1}));
|
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_F16, {512, 3072, 1, 1}));
|
||||||
|
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_F32, {8192, 512, 2, 1}, {0, 2, 1, 3}));
|
||||||
|
test_cases.emplace_back(new test_cpy(GGML_TYPE_F32, GGML_TYPE_F32, {3072, 512, 2, 1}, {0, 2, 1, 3}));
|
||||||
|
|
||||||
test_cases.emplace_back(new test_soft_max(GGML_TYPE_F32, {4096, 4096, 5, 1}, false, 1.0f, 0.0f));
|
test_cases.emplace_back(new test_soft_max(GGML_TYPE_F32, {4096, 4096, 5, 1}, false, 1.0f, 0.0f));
|
||||||
test_cases.emplace_back(new test_soft_max(GGML_TYPE_F32, {77, 4096, 5, 1}, false, 1.0f, 0.0f));
|
test_cases.emplace_back(new test_soft_max(GGML_TYPE_F32, {77, 4096, 5, 1}, false, 1.0f, 0.0f));
|
||||||
|
Loading…
Reference in New Issue
Block a user