chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 12:40:42 +08:00
commit e25996e7db
15472 changed files with 3536181 additions and 0 deletions
+380
View File
@@ -0,0 +1,380 @@
// Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <array>
#include <set>
#include "gtest/gtest.h"
#include "paddle/phi/backends/context_pool.h"
#include "paddle/phi/kernels/funcs/blas/blas.h"
#include "paddle/phi/kernels/funcs/math_function.h"
namespace phi {
namespace tests {
template <typename T>
inline phi::funcs::BlasT<phi::CPUContext, T> GetBlas(
const phi::CPUContext& context) {
return phi::funcs::GetBlas<phi::CPUContext, T>(context);
}
TEST(math_function, gemm_notrans_cblas) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
int m = 2;
int n = 3;
int k = 3;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
input1.Resize({2, 3});
float* input1_ptr = dev_ctx->template Alloc<float>(&input1);
std::array<float, 6> arr1 = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr1.data(), 6 * sizeof(float));
input2.Resize({3, 4});
float* input2_ptr = dev_ctx->template Alloc<float>(&input2);
std::array<float, 12> arr2 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
memcpy(input2_ptr, arr2.data(), 12 * sizeof(float));
input3.Resize({2, 4});
float* input3_ptr = dev_ctx->template Alloc<float>(&input3);
std::array<float, 8> arr3 = {0, 1, 2, 3, 4, 5, 6, 7};
memcpy(input3_ptr, arr3.data(), 8 * sizeof(float));
GetBlas<float>(*dev_ctx).GEMM(false,
false,
m,
n,
k,
1,
input1_ptr,
3,
input2_ptr + 1,
4,
1,
input3_ptr + 1,
4);
EXPECT_EQ(input3_ptr[0], 0);
EXPECT_EQ(input3_ptr[1], 24);
EXPECT_EQ(input3_ptr[2], 28);
EXPECT_EQ(input3_ptr[3], 32);
EXPECT_EQ(input3_ptr[4], 4);
EXPECT_EQ(input3_ptr[5], 73);
EXPECT_EQ(input3_ptr[6], 86);
EXPECT_EQ(input3_ptr[7], 99);
}
#ifdef PADDLE_WITH_LIBXSMM
template <typename T>
void MklSmmCompare(int m, int n, int k) {
phi::DenseTensor mat_a;
phi::DenseTensor mat_b;
phi::DenseTensor mat_c_smm;
phi::DenseTensor mat_c_mkl;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
mat_a.Resize({m, k});
T* A = dev_ctx->template Alloc<T>(&mat_a);
mat_b.Resize({k, n});
T* B = dev_ctx->template Alloc<T>(&mat_b);
mat_c_smm.Resize({m, n});
T* CSMM = dev_ctx->template Alloc<T>(&mat_c_smm);
mat_c_mkl.Resize({m, n});
T* CMKL = dev_ctx->template Alloc<T>(&mat_c_mkl);
T alpha = static_cast<T>(1);
T beta = static_cast<T>(0);
for (int i = 0; i < mat_a.numel(); ++i) {
A[i] = static_cast<T>(i);
}
for (int i = 0; i < mat_b.numel(); ++i) {
B[i] = static_cast<T>(i);
}
// lda,ldb,ldc follow RowMajor
int lda = k;
int ldb = n;
int ldc = n;
auto smm = [&, m, n, k, lda, ldb, ldc, alpha, beta]() {
const char transa = 'N';
const char transb = 'N';
phi::funcs::CBlas<T>::SMM_GEMM(&transa,
&transb,
&n,
&m,
&k,
&alpha,
B,
&ldb,
A,
&lda,
&beta,
CSMM,
&ldc);
};
auto mkl = [&, m, n, k, lda, ldb, ldc, alpha, beta]() {
phi::funcs::CBlas<T>::GEMM(CblasRowMajor,
CblasNoTrans,
CblasNoTrans,
m,
n,
k,
alpha,
A,
lda,
B,
ldb,
beta,
CMKL,
ldc);
};
smm();
mkl();
ASSERT_EQ(mat_c_mkl.numel(), mat_c_smm.numel());
for (int i = 0; i < mat_c_mkl.numel(); ++i) {
EXPECT_FLOAT_EQ(CSMM[i], CMKL[i]);
}
}
TEST(math_function, gemm_mkl_vs_smm) {
MklSmmCompare<float>(1, 2, 3);
MklSmmCompare<double>(1, 2, 3);
MklSmmCompare<float>(3, 2, 1);
MklSmmCompare<double>(3, 2, 1);
MklSmmCompare<float>(3, 8, 5);
MklSmmCompare<double>(3, 8, 5);
}
#endif
TEST(math_function, gemm_trans_cblas) {
phi::DenseTensor input1;
phi::DenseTensor input2;
phi::DenseTensor input3;
int m = 2;
int n = 3;
int k = 3;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
input1.Resize({2, 3});
float* input1_ptr = dev_ctx->template Alloc<float>(&input1);
std::array<float, 6> arr1 = {0, 1, 2, 3, 4, 5};
memcpy(input1_ptr, arr1.data(), 6 * sizeof(float));
input2.Resize({4, 3});
float* input2_ptr = dev_ctx->template Alloc<float>(&input2);
std::array<float, 12> arr2 = {0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11};
memcpy(input2_ptr, arr2.data(), 12 * sizeof(float));
input3.Resize({2, 4});
float* input3_ptr = dev_ctx->template Alloc<float>(&input3);
std::array<float, 8> arr3 = {0, 1, 2, 3, 4, 5, 6, 7};
memcpy(input3_ptr, arr3.data(), 8 * sizeof(float));
GetBlas<float>(*dev_ctx).GEMM(false,
true,
m,
n,
k,
1,
input1_ptr,
3,
input2_ptr + 3,
3,
1,
input3_ptr + 1,
4);
EXPECT_EQ(input3_ptr[0], 0);
EXPECT_EQ(input3_ptr[1], 24);
EXPECT_EQ(input3_ptr[2], 28);
EXPECT_EQ(input3_ptr[3], 32);
EXPECT_EQ(input3_ptr[4], 4);
EXPECT_EQ(input3_ptr[5], 73);
EXPECT_EQ(input3_ptr[6], 86);
EXPECT_EQ(input3_ptr[7], 99);
}
TEST(math_function, zero) {
phi::DenseTensor tensor;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
tensor.Resize({2, 2});
float* t = dev_ctx->template Alloc<float>(&tensor);
phi::funcs::SetConstant<phi::CPUContext, float> functor;
functor(*dev_ctx, &tensor, 0);
EXPECT_EQ(t[0], 0);
EXPECT_EQ(t[1], 0);
EXPECT_EQ(t[2], 0);
EXPECT_EQ(t[3], 0);
functor(*dev_ctx, &tensor, 1);
EXPECT_EQ(t[0], 1);
EXPECT_EQ(t[1], 1);
EXPECT_EQ(t[2], 1);
EXPECT_EQ(t[3], 1);
}
template <typename T>
void GemvTest(int m, int n, bool trans) {
phi::DenseTensor mat_a;
phi::DenseTensor vec_b;
phi::DenseTensor vec_c;
int b_num = trans ? m : n;
int c_num = trans ? n : m;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
mat_a.Resize({m, n});
T* data_a = dev_ctx->template Alloc<T>(&mat_a);
vec_b.Resize({b_num});
T* data_b = dev_ctx->template Alloc<T>(&vec_b);
vec_c.Resize({c_num});
T* data_c = dev_ctx->template Alloc<T>(&vec_c);
for (int i = 0; i < mat_a.numel(); ++i) {
data_a[i] = static_cast<T>(i);
}
for (int i = 0; i < vec_b.numel(); ++i) {
data_b[i] = static_cast<T>(i);
}
GetBlas<T>(*dev_ctx).GEMV(trans,
static_cast<int>(m),
static_cast<int>(n),
1.,
data_a,
data_b,
0.,
data_c);
if (!trans) {
for (int i = 0; i < m; ++i) {
T sum = 0.0;
for (int j = 0; j < n; ++j) {
sum += data_a[i * n + j] * data_b[j];
}
ASSERT_FLOAT_EQ(data_c[i], sum);
}
} else {
for (int i = 0; i < n; ++i) {
T sum = 0.0;
for (int j = 0; j < m; ++j) {
sum += data_a[j * n + i] * data_b[j];
}
ASSERT_FLOAT_EQ(data_c[i], sum);
}
}
}
TEST(math_function, gemv) {
GemvTest<float>(3, 13, false);
GemvTest<double>(4, 5, false);
GemvTest<float>(12, 7, true);
GemvTest<double>(7, 9, true);
}
TEST(math_function, set_constant) {
phi::DenseTensor t;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
t.Resize({10, 10});
dev_ctx->template Alloc<int>(&t);
phi::funcs::set_constant(*dev_ctx, &t, static_cast<int>(10));
for (int64_t i = 0; i < t.numel(); ++i) {
PADDLE_ENFORCE_EQ(10,
t.data<int>()[i],
common::errors::InvalidArgument(
"Each value of input tensor should be 10, "
"but received %d.",
t.data<int>()[i]));
}
}
template <typename T>
void GemmWarpTest(int m, int n, int k, T alpha, T beta) {
phi::DenseTensor mat_a;
phi::DenseTensor mat_b;
phi::DenseTensor mat_c_ref;
phi::DenseTensor mat_c_mkl;
auto* dev_ctx =
phi::DeviceContextPool::Instance().GetByPlace(phi::CPUPlace());
mat_a.Resize({m, k});
T* A = dev_ctx->template Alloc<T>(&mat_a);
mat_b.Resize({k, n});
T* B = dev_ctx->template Alloc<T>(&mat_b);
mat_c_ref.Resize({m, n});
T* CREF = dev_ctx->template Alloc<T>(&mat_c_ref);
mat_c_mkl.Resize({m, n});
T* CMKL = dev_ctx->template Alloc<T>(&mat_c_mkl);
ASSERT_EQ(mat_c_mkl.numel(), mat_c_ref.numel());
for (int i = 0; i < mat_a.numel(); ++i) {
A[i] = static_cast<T>(i);
}
for (int i = 0; i < mat_b.numel(); ++i) {
B[i] = static_cast<T>(i + 1);
}
for (int i = 0; i < mat_c_ref.numel(); ++i) {
CREF[i] = static_cast<T>(i + 2);
CMKL[i] = CREF[i];
}
// this would call gemm_warp
GetBlas<T>(*dev_ctx).GEMM(
CblasNoTrans, CblasNoTrans, m, n, k, alpha, A, B, beta, CREF);
// lda,ldb,ldc follow RowMajor
int lda = k;
int ldb = n;
int ldc = n;
phi::funcs::CBlas<T>::GEMM(CblasRowMajor,
CblasNoTrans,
CblasNoTrans,
m,
n,
k,
alpha,
A,
lda,
B,
ldb,
beta,
CMKL,
ldc);
for (int i = 0; i < mat_c_mkl.numel(); ++i) {
EXPECT_FLOAT_EQ(CREF[i], CMKL[i]);
}
}
TEST(math_function, gemm_warp) {
GemmWarpTest<float>(3, 2, 5, 1.f, 0.f);
GemmWarpTest<float>(3, 2, 5, 2.f, 1.f);
GemmWarpTest<float>(8, 5, 6, 1.f, 0.f);
GemmWarpTest<float>(8, 5, 6, 2.f, 1.f);
GemmWarpTest<double>(3, 2, 5, 1.0, 0.0);
GemmWarpTest<double>(3, 2, 5, 2.0, 1.0);
GemmWarpTest<double>(8, 5, 6, 1.0, 0.0);
GemmWarpTest<double>(8, 5, 6, 2.0, 1.0);
}
} // namespace tests
} // namespace phi