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
+9
View File
@@ -0,0 +1,9 @@
add_subdirectory(adt)
add_subdirectory(ast_gen_ius)
add_subdirectory(common)
add_subdirectory(hlir)
add_subdirectory(ir)
add_subdirectory(lang)
add_subdirectory(optim)
add_subdirectory(runtime)
add_subdirectory(utils)
+4
View File
@@ -0,0 +1,4 @@
cinn_cc_test(equation_value_match_trait_test SRCS
equation_value_match_trait_test.cc DEPS gtest glog)
cinn_cc_test(tree_test SRCS tree_test.cc DEPS gtest glog)
@@ -0,0 +1,143 @@
// Copyright (c) 2023 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 "paddle/cinn/adt/equation_value_match_trait.h"
#include "gtest/gtest.h"
#include "paddle/cinn/adt/equation_value.h"
#include "paddle/cinn/adt/match.h"
namespace cinn::adt::test {
TEST(Match, Union) {
using Pattern = Union<IndexUnDotValue<Value, List<DimExpr>>,
IndexDotValue<Value, List<DimExpr>>>;
{
Value expr = IndexUnDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
bool ret = cinn::adt::Match<Pattern>(expr);
ASSERT_TRUE(ret);
}
{
Value expr = IndexDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
bool ret = cinn::adt::Match<Pattern>(expr);
ASSERT_TRUE(ret);
}
{
Value expr = List<Value>{Value{Ok()}, Value{Ok()}, Value{Ok()}};
bool ret = cinn::adt::Match<Pattern>(expr);
ASSERT_FALSE(ret);
}
}
TEST(Match, index_undot) {
Value expr = IndexUnDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
bool ret = cinn::adt::Match<IndexUnDotValue<Value, List<DimExpr>>>(expr);
ASSERT_TRUE(ret);
}
TEST(Match, index_dot) {
Value expr = IndexDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
bool ret = cinn::adt::Match<IndexDotValue<Value, List<DimExpr>>>(expr);
ASSERT_TRUE(ret);
}
TEST(Match, list) {
Value expr = List<Value>{Value{Ok()}, Value{Ok()}, Value{Ok()}};
bool ret = cinn::adt::Match<List<Value>>(expr);
ASSERT_TRUE(ret);
}
TEST(Match, list_get_item) {
Value list = List<Value>{Value{Ok()}, Value{Ok()}, Value{Ok()}};
Value expr = ListGetItem<Value, DimExpr>{list, DimExpr{std::int64_t(1)}};
bool ret = cinn::adt::Match<ListGetItem<Value, std::int64_t>>(expr);
ASSERT_TRUE(ret);
}
TEST(Match, list_get_item_index_undot) {
Value undot1 = IndexUnDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
ASSERT_TRUE(
(cinn::adt::Match<IndexUnDotValue<Value, List<DimExpr>>>(undot1)));
Value expr = ListGetItem<Value, DimExpr>{undot1, DimExpr{std::int64_t(1)}};
ASSERT_TRUE(
(cinn::adt::Match<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>(
expr)));
}
// List<ListGetItem<IndexUnDotValue<Value>, std::int64_t>>
TEST(Match, list_list_get_item_index_undot) {
Value undot = IndexUnDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
ASSERT_TRUE((cinn::adt::Match<IndexUnDotValue<Value, List<DimExpr>>>(undot)));
Value expr1 = ListGetItem<Value, DimExpr>{undot, DimExpr{std::int64_t(0)}};
ASSERT_TRUE(
(cinn::adt::Match<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>(
expr1)));
Value expr2 = ListGetItem<Value, DimExpr>{undot, DimExpr{std::int64_t(1)}};
ASSERT_TRUE(
(cinn::adt::Match<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>(
expr2)));
Value list = List<Value>{expr1, expr2};
ASSERT_TRUE(
(cinn::adt::Match<List<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>>(
list)));
}
// IndexDotValue<List<ListGetItem<IndexUnDotValue<Value>, std::int64_t>>>
TEST(Match, index_dot_list_list_get_item_index_undot) {
Value undot1 = IndexUnDotValue<Value, List<DimExpr>>{
Value{Ok()}, List<DimExpr>{std::int64_t(1)}};
ASSERT_TRUE(
(cinn::adt::Match<IndexUnDotValue<Value, List<DimExpr>>>(undot1)));
Value expr1 = ListGetItem<Value, DimExpr>{undot1, DimExpr{std::int64_t(0)}};
ASSERT_TRUE(
(cinn::adt::Match<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>(
expr1)));
Value expr2 = ListGetItem<Value, DimExpr>{undot1, DimExpr{std::int64_t(1)}};
ASSERT_TRUE(
(cinn::adt::Match<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>(
expr2)));
Value list = List<Value>{expr1, expr2};
ASSERT_TRUE(
(cinn::adt::Match<List<
ListGetItem<IndexUnDotValue<Value, List<DimExpr>>, std::int64_t>>>(
list)));
Value dot =
IndexDotValue<Value, List<DimExpr>>{list, List<DimExpr>{std::int64_t(1)}};
ASSERT_TRUE(
(cinn::adt::Match<
IndexDotValue<List<ListGetItem<IndexUnDotValue<Value, List<DimExpr>>,
std::int64_t>>,
List<DimExpr>>>(dot)));
}
} // namespace cinn::adt::test
+199
View File
@@ -0,0 +1,199 @@
// Copyright (c) 2023 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 "paddle/cinn/adt/tree.h"
#include "gtest/gtest.h"
namespace cinn::adt {
namespace test {
using IntTreeLeafT = std::vector<int>;
using IntTreeInnerDataT = std::vector<int>;
using IntVecTree = Tree<TreeInner<IntTreeInnerDataT>::Node, IntTreeLeafT>;
using IntTreeInnerT = TreeInner<IntTreeInnerDataT>::template Node<IntVecTree>;
} // namespace test
template <>
struct TreeMerger<test::IntVecTree> {
using tree_type = test::IntVecTree;
using inner_type = typename TreeTrait<test::IntVecTree>::inner_type;
using leaf_type = typename TreeTrait<test::IntVecTree>::leaf_type;
using inner_data_type = typename inner_type::value_type;
inner_data_type GetInnerDataForLeaf(const leaf_type& leaf) const {
return leaf;
}
inner_type MakeInnerNode(const inner_data_type& inner_data,
const List<test::IntVecTree>& children) const {
return inner_type{inner_data, children};
}
using MergeResult = std::tuple<tCommon<inner_data_type>,
tLhsRemainder<inner_data_type>,
tRhsRemainder<inner_data_type>>;
MergeResult MergeInnerValue(const inner_data_type& lhs,
const inner_data_type& rhs) const {
inner_data_type common{};
inner_data_type lhs_remainder{};
inner_data_type rhs_remainder{};
int min_size = std::min(lhs.size(), rhs.size());
int idx = 0;
for (; idx < min_size; ++idx) {
if (lhs.at(idx) == rhs.at(idx)) {
common.emplace_back(lhs.at(idx));
} else {
break;
}
}
for (int lhs_idx = idx; lhs_idx < lhs.size(); ++lhs_idx) {
lhs_remainder.emplace_back(lhs.at(lhs_idx));
}
for (int rhs_idx = idx; rhs_idx < rhs.size(); ++rhs_idx) {
rhs_remainder.emplace_back(rhs.at(rhs_idx));
}
return MergeResult{common, lhs_remainder, rhs_remainder};
}
};
namespace test {
TEST(IntVecTree, naive) {
List<IntTreeLeafT> leaves{IntTreeLeafT{1, 2, 3}, IntTreeLeafT{4, 5, 6}};
TreeMerger<test::IntVecTree> tree_merger{};
List<IntVecTree> ret = MakeMergedTrees(tree_merger, leaves);
ASSERT_EQ(ret->size(), 2);
ASSERT_TRUE(ret->at(0).Has<IntTreeInnerT>());
const auto& [inner_data0, children0] =
ret->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data0 == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->size() == 1));
ASSERT_TRUE((children0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children0->at(0).Get<IntTreeLeafT>() == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE(ret->at(1).Has<IntTreeInnerT>());
const auto& [inner_data1, children1] =
ret->at(1).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data1 == IntTreeLeafT{4, 5, 6}));
ASSERT_TRUE((children1->size() == 1));
ASSERT_TRUE((children1->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children1->at(0).Get<IntTreeLeafT>() == IntTreeLeafT{4, 5, 6}));
}
TEST(IntVecTree, left_equal_right) {
List<IntTreeLeafT> leaves{IntTreeLeafT{1, 2, 3}, IntTreeLeafT{1, 2, 3}};
List<IntVecTree> ret =
MakeMergedTrees(TreeMerger<test::IntVecTree>{}, leaves);
ASSERT_EQ(ret->size(), 1);
ASSERT_TRUE(ret->at(0).Has<IntTreeInnerT>());
const auto& [inner_data0, children0] =
ret->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data0 == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->size() == 2));
ASSERT_TRUE((children0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children0->at(0).Get<IntTreeLeafT>() == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->at(1).Has<IntTreeLeafT>()));
ASSERT_TRUE((children0->at(1).Get<IntTreeLeafT>() == IntTreeLeafT{1, 2, 3}));
}
TEST(IntVecTree, left_gt_right) {
List<IntTreeLeafT> leaves{IntTreeLeafT{1, 2, 3, 4, 5}, IntTreeLeafT{1, 2, 3}};
List<IntVecTree> ret =
MakeMergedTrees(TreeMerger<test::IntVecTree>{}, leaves);
ASSERT_EQ(ret->size(), 1);
ASSERT_TRUE(ret->at(0).Has<IntTreeInnerT>());
const auto& [inner_data0, children0] =
ret->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data0 == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->size() == 2));
ASSERT_TRUE((children0->at(0).Has<IntTreeInnerT>()));
const auto& [inner_data_left0, children_left0] =
children0->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data_left0 == IntTreeLeafT{4, 5}));
ASSERT_TRUE((children_left0->size() == 1));
ASSERT_TRUE((children_left0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children_left0->at(0).Get<IntTreeLeafT>() ==
IntTreeLeafT{1, 2, 3, 4, 5}));
ASSERT_TRUE((children0->at(1).Has<IntTreeLeafT>()));
ASSERT_TRUE((children0->at(1).Get<IntTreeLeafT>() == IntTreeLeafT{1, 2, 3}));
}
TEST(IntVecTree, left_lt_right) {
List<IntTreeLeafT> leaves{IntTreeLeafT{1, 2, 3}, IntTreeLeafT{1, 2, 3, 4, 5}};
List<IntVecTree> ret =
MakeMergedTrees(TreeMerger<test::IntVecTree>{}, leaves);
ASSERT_EQ(ret->size(), 1);
ASSERT_TRUE(ret->at(0).Has<IntTreeInnerT>());
const auto& [inner_data0, children0] =
ret->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data0 == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->size() == 2));
ASSERT_TRUE((children0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children0->at(0).Get<IntTreeLeafT>() == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->at(1).Has<IntTreeInnerT>()));
const auto& [inner_data_right0, children_right0] =
children0->at(1).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data_right0 == IntTreeLeafT{4, 5}));
ASSERT_TRUE((children_right0->size() == 1));
ASSERT_TRUE((children_right0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children_right0->at(0).Get<IntTreeLeafT>() ==
IntTreeLeafT{1, 2, 3, 4, 5}));
}
TEST(IntVecTree, left_ne_right) {
List<IntTreeLeafT> leaves{IntTreeLeafT{1, 2, 3, 4, 5},
IntTreeLeafT{1, 2, 3, 6, 7}};
List<IntVecTree> ret =
MakeMergedTrees(TreeMerger<test::IntVecTree>{}, leaves);
ASSERT_EQ(ret->size(), 1);
ASSERT_TRUE(ret->at(0).Has<IntTreeInnerT>());
const auto& [inner_data0, children0] =
ret->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data0 == IntTreeLeafT{1, 2, 3}));
ASSERT_TRUE((children0->size() == 2));
ASSERT_TRUE((children0->at(0).Has<IntTreeInnerT>()));
const auto& [inner_data_left0, children_left0] =
children0->at(0).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data_left0 == IntTreeLeafT{4, 5}));
ASSERT_TRUE((children_left0->size() == 1));
ASSERT_TRUE((children_left0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children_left0->at(0).Get<IntTreeLeafT>() ==
IntTreeLeafT{1, 2, 3, 4, 5}));
ASSERT_TRUE((children0->at(1).Has<IntTreeInnerT>()));
const auto& [inner_data_right0, children_right0] =
children0->at(1).Get<IntTreeInnerT>().tuple();
ASSERT_TRUE((inner_data_right0 == IntTreeLeafT{6, 7}));
ASSERT_TRUE((children_right0->size() == 1));
ASSERT_TRUE((children_right0->at(0).Has<IntTreeLeafT>()));
ASSERT_TRUE((children_right0->at(0).Get<IntTreeLeafT>() ==
IntTreeLeafT{1, 2, 3, 6, 7}));
}
} // namespace test
} // namespace cinn::adt
+1
View File
@@ -0,0 +1 @@
cinn_cc_test(test_tensor_group SRCS tensor_group_test.cc DEPS cinncore)
@@ -0,0 +1,138 @@
// Copyright (c) 2023 CINN 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 <gtest/gtest.h>
#include <vector>
#include "paddle/utils/flat_hash_map.h"
#include "paddle/cinn/ast_gen_ius/tensor_group.h"
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/ir_base.h"
#include "paddle/cinn/ir/tensor.h"
#include "paddle/cinn/lang/compute.h"
#include "paddle/cinn/lang/placeholder.h"
namespace cinn {
namespace ast_gen_ius {
using ir::Expr;
using ir::Tensor;
using ir::Var;
using lang::Compute;
using lang::Placeholder;
TEST(TensorGroup, Easy) {
auto M = Expr(100);
auto N = Expr(15);
Placeholder<float> A("A", {M, N});
Tensor B = Compute(
{M, N}, [=](Var i, Var j) -> Expr { return A(i, j) + 1.f; }, "B");
TensorGroup tensor_group({B});
ASSERT_TRUE(tensor_group.Contain("A"));
ASSERT_TRUE(tensor_group.Contain("B"));
ASSERT_EQ(tensor_group.Get("B")->name, "B");
ASSERT_EQ(tensor_group.Get("A")->name, "A");
ASSERT_EQ(tensor_group.GetAllTensors().size(), 2UL);
ASSERT_EQ(tensor_group.GetCtrlDepTensors("A").size(), 0UL);
ASSERT_EQ(tensor_group.GetCtrlDepTensors("B").size(), 1UL);
ASSERT_TRUE(tensor_group.GetCtrlDepTensors("B").count(A));
std::vector<ir::Tensor> topo_tensors =
tensor_group.GetGenFuncTopoOrder({A.tensor(), B});
ASSERT_EQ(topo_tensors.size(), 1UL);
ASSERT_EQ(topo_tensors[0]->name, "B");
ASSERT_EQ(tensor_group.GetShareMemRootName("A"), "A");
ASSERT_EQ(tensor_group.GetShareMemRootName("B"), "B");
tensor_group.MarkShareMemBuffer(tensor_group.Get("A"), tensor_group.Get("B"));
paddle::flat_hash_map<std::string, ir::Tensor> buffered_tensors =
tensor_group.AllocateBuffers();
ASSERT_EQ(buffered_tensors["A"]->buffer->name,
buffered_tensors["B"]->buffer->name);
}
TEST(TensorGroup, GraphTopo) {
auto M = Expr(16);
auto N = Expr(16);
/*
* A B
* / \ /
* C D
* \ /
* E
*/
Placeholder<float> A("A", {M, N});
Placeholder<float> B("B", {M, N});
Tensor C = Compute(
{M, N}, [=](Var i, Var j) -> Expr { return A(i, j) + 1.f; }, "C");
Tensor D = Compute(
{M, N}, [=](Var i, Var j) -> Expr { return A(i, j) + B(i, j); }, "D");
Tensor E = Compute(
{M, N}, [=](Var i, Var j) -> Expr { return C(i, j) / D(i, j); }, "E");
TensorGroup tensor_group({C, D, E});
std::vector<std::string> check_names = {"A", "B", "C", "D", "E"};
ASSERT_EQ(tensor_group.GetAllTensors().size(), check_names.size());
for (const std::string& name : check_names) {
ASSERT_TRUE(tensor_group.Contain(name));
ASSERT_EQ(tensor_group.Get(name)->name, name);
}
ASSERT_TRUE(tensor_group.GetCtrlDepTensors("E").count(D));
ASSERT_TRUE(tensor_group.GetCtrlDepTensors("E").count(C));
ASSERT_TRUE(tensor_group.GetCtrlDepTensors("D").count(A));
ASSERT_TRUE(tensor_group.GetCtrlDepTensors("D").count(B));
ASSERT_TRUE(tensor_group.GetCtrlDepTensors("C").count(A));
std::vector<ir::Tensor> topo_tensors = tensor_group.GetGenFuncTopoOrder();
ASSERT_EQ(topo_tensors.size(), check_names.size());
for (size_t i = 0; i < check_names.size(); ++i) {
ASSERT_EQ(topo_tensors[i]->name, check_names[i]);
}
std::vector<ir::Tensor> topo_except_argu =
tensor_group.GetGenFuncTopoOrder({A.tensor(), B.tensor()});
ASSERT_EQ(topo_except_argu.size(), 3);
for (int i = 0; i < 3; ++i) {
ASSERT_EQ(topo_except_argu[i]->name, check_names[i + 2]);
}
for (size_t i = 0; i < check_names.size(); ++i) {
ASSERT_EQ(tensor_group.GetShareMemRootName(check_names[i]), check_names[i]);
}
tensor_group.MarkShareMemBuffer(tensor_group.Get("A"), tensor_group.Get("B"));
tensor_group.MarkShareMemBuffer(tensor_group.Get("B"), tensor_group.Get("C"));
tensor_group.MarkShareMemBuffer(tensor_group.Get("C"), tensor_group.Get("D"));
ASSERT_EQ(tensor_group.GetShareMemRootName("A"),
tensor_group.GetShareMemRootName("D"));
paddle::flat_hash_map<std::string, ir::Tensor> buffered_tensors =
tensor_group.AllocateBuffers();
ASSERT_EQ(buffered_tensors["A"]->buffer->name,
buffered_tensors["D"]->buffer->name);
}
} // namespace ast_gen_ius
} // namespace cinn
+23
View File
@@ -0,0 +1,23 @@
cinn_cc_test(test_dfs_walker SRCS dfs_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_dfs_topo_walker SRCS dfs_topo_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_cinn_value SRCS cinn_value_test.cc DEPS cinncore)
cinn_cc_test(test_axis SRCS axis_test.cc DEPS cinncore)
cinn_cc_test(dim_expr_converter_test SRCS dim_expr_converter_test.cc DEPS
cinncore)
cinn_cc_test(broadcast_tree_test SRCS broadcast_tree_test.cc DEPS cinncore)
cinn_cc_test(test_equation_graph_topo_walker SRCS
equation_graph_topo_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_type SRCS type_test.cc DEPS cinncore)
cinn_cc_test(test_topo_walker SRCS topo_walker_test.cc DEPS gtest glog)
cinn_cc_test(test_shared SRCS shared_test.cc DEPS cinncore)
cinn_cc_test(test_is_reachable_predicator SRCS is_reachable_predicator_test.cc
DEPS gtest glog)
cinn_cc_test(test_integer_set SRCS integer_set_test.cc DEPS cinncore)
if(WITH_CUDA)
cinn_nv_test(test_fp16_bf16_cuda SRCS float16_bfloat16_cuda_test.cu DEPS
gtest glog)
endif()
cinn_cc_test(test_fp16_bf16_host SRCS float16_bfloat16_host_test.cc DEPS gtest
glog)
+45
View File
@@ -0,0 +1,45 @@
// Copyright (c) 2023 CINN 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 "paddle/cinn/common/axis.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <string>
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace common {
TEST(AXISNAME, BASE) {
ASSERT_EQ(axis_name(0), std::string("i"));
ASSERT_EQ(axis_name(1), std::string("j"));
ASSERT_EQ(axis_name(22), std::string("ii"));
ASSERT_EQ(axis_name(44), std::string("iii"));
}
TEST(AXISNAME, CHECK_RESERVED) {
ASSERT_TRUE(IsAxisNameReserved("i"));
ASSERT_TRUE(IsAxisNameReserved("j"));
ASSERT_TRUE(IsAxisNameReserved("ii"));
ASSERT_TRUE(IsAxisNameReserved("iiiiiiiiii"));
ASSERT_FALSE(IsAxisNameReserved("ijk"));
ASSERT_FALSE(IsAxisNameReserved("iiiiiiiiiij"));
ASSERT_FALSE(IsAxisNameReserved("x"));
}
} // namespace common
} // namespace cinn
+118
View File
@@ -0,0 +1,118 @@
// Copyright (c) 2024 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 "paddle/cinn/common/broadcast_tree.h"
#include "gtest/gtest.h"
namespace cinn::common {
using namespace symbol; // NOLINT
namespace {
DimExpr MakeBroadcastDimExpr(const DimExpr& expr1, const DimExpr& expr2) {
List<DimExpr> operands{expr1, expr2};
return Broadcast<DimExpr>{operands};
}
bool DimExprNonBroadcast(const DimExpr& dim_expr) {
if (dim_expr.Has<Broadcast<DimExpr>>()) {
return false;
} else {
return true;
}
}
void CheckLeafNonBroadcast(const BroadcastLeaf& leaf) {
for (const auto& operands : *leaf) {
for (const auto& operand : operands) {
ASSERT_TRUE(DimExprNonBroadcast(operand));
}
}
}
void CheckInnerBranchNonBroadcast(
const BroadcastBranch<BroadcastTree>& branch) {
const auto& [_, lhs_eq_rhs_tree, lhs_eq_one_tree, rhs_eq_one_tree] =
branch.tuple();
ASSERT_TRUE(lhs_eq_rhs_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(lhs_eq_one_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(rhs_eq_one_tree.Has<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_rhs_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_one_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(rhs_eq_one_tree.Get<BroadcastLeaf>());
}
} // namespace
TEST(BroadcastTree, Naive) {
DimExpr expr1("S1");
DimExpr expr2("S2");
DimExpr expr3("S3");
DimExpr expr4("S4");
std::vector<DimExpr> tensor_shape{expr1,
expr2,
MakeBroadcastDimExpr(expr1, expr2),
MakeBroadcastDimExpr(expr3, expr4)};
BroadcastLeaf leaf = adt::List<std::vector<DimExpr>>{tensor_shape};
int num_of_leaves = 0;
BroadcastTree tree = ConstructBroadcastTree(leaf, &num_of_leaves);
ASSERT_TRUE(tree.Has<BroadcastBranch<BroadcastTree>>());
const auto& branch = tree.Get<BroadcastBranch<BroadcastTree>>();
const auto& [cstr_broadcastable,
lhs_eq_rhs_tree,
lhs_eq_one_tree,
rhs_eq_one_tree] = branch.tuple();
ASSERT_EQ(cstr_broadcastable->lhs, DimExpr("S1"));
ASSERT_EQ(cstr_broadcastable->rhs, DimExpr("S2"));
ASSERT_TRUE(lhs_eq_rhs_tree.Has<BroadcastBranch<BroadcastTree>>());
ASSERT_TRUE(lhs_eq_one_tree.Has<BroadcastBranch<BroadcastTree>>());
ASSERT_TRUE(rhs_eq_one_tree.Has<BroadcastBranch<BroadcastTree>>());
CheckInnerBranchNonBroadcast(
lhs_eq_rhs_tree.Get<BroadcastBranch<BroadcastTree>>());
CheckInnerBranchNonBroadcast(
lhs_eq_one_tree.Get<BroadcastBranch<BroadcastTree>>());
CheckInnerBranchNonBroadcast(
rhs_eq_one_tree.Get<BroadcastBranch<BroadcastTree>>());
}
TEST(BroadcastTree, SimplifyConstantBroadcast) {
DimExpr expr1("S1");
DimExpr expr2("S2");
DimExpr expr3("S3");
DimExpr expr4(4);
std::vector<DimExpr> tensor_shape{expr1,
expr2,
MakeBroadcastDimExpr(expr1, expr2),
MakeBroadcastDimExpr(expr3, expr4)};
BroadcastLeaf leaf = adt::List<std::vector<DimExpr>>{tensor_shape};
int num_of_leaves = 0;
BroadcastTree tree = ConstructBroadcastTree(leaf, &num_of_leaves);
ASSERT_TRUE(tree.Has<BroadcastBranch<BroadcastTree>>());
const auto& branch = tree.Get<BroadcastBranch<BroadcastTree>>();
const auto& [cstr_broadcastable,
lhs_eq_rhs_tree,
lhs_eq_one_tree,
rhs_eq_one_tree] = branch.tuple();
ASSERT_EQ(cstr_broadcastable->lhs, DimExpr("S1"));
ASSERT_EQ(cstr_broadcastable->rhs, DimExpr("S2"));
ASSERT_TRUE(lhs_eq_rhs_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(lhs_eq_one_tree.Has<BroadcastLeaf>());
ASSERT_TRUE(rhs_eq_one_tree.Has<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_rhs_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(lhs_eq_one_tree.Get<BroadcastLeaf>());
CheckLeafNonBroadcast(rhs_eq_one_tree.Get<BroadcastLeaf>());
}
} // namespace cinn::common
+59
View File
@@ -0,0 +1,59 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/common/cinn_value.h"
#include <gtest/gtest.h>
#include "paddle/cinn/common/common.h"
#include "paddle/cinn/common/ir_util.h"
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/ir_printer.h"
namespace cinn {
namespace common {
TEST(CINNValue, test) {
{
CINNValue value(32);
ASSERT_EQ(int(value), 32); // NOLINT
}
{
CINNValue value(32.f);
ASSERT_NEAR(float(value), 32.f, 1e-6); // NOLINT
}
}
TEST(CINNValue, buffer) {
cinn_buffer_t* v = nullptr;
CINNValue value(v);
ASSERT_EQ((cinn_buffer_t*)value, nullptr);
}
TEST(CINNValue, Expr) {
Expr a(1);
{
CINNValue value(a);
ASSERT_TRUE(a == value);
}
{
CINNValue copied = CINNValue(a);
ASSERT_TRUE(copied == cinn::common::make_const(1));
}
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,54 @@
// Copyright (c) 2023 CINN 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 <glog/logging.h>
#include <gtest/gtest.h>
#include "paddle/cinn/common/dfs_topo_walker.h"
namespace cinn {
namespace common {
TEST(DfsTopoWalker, simple) {
std::vector<std::pair<int, int>> edges{
{0, 1}, {2, 3}, {1, 3}, {0, 3}, {3, 4}};
DfsTopoWalker<int> walker(
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.second == node) {
NodeHandler(pair.first);
}
}
},
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.first == node) {
NodeHandler(pair.second);
}
}
});
std::vector<int> sources{0, 2};
std::vector<int> outputs;
walker(sources.begin(), sources.end(), [&](int node) {
outputs.push_back(node);
});
for (auto output : outputs) {
LOG(INFO) << output;
}
std::vector<int> expected{0, 1, 2, 3, 4};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace cinn
+72
View File
@@ -0,0 +1,72 @@
// Copyright (c) 2023 CINN 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 "paddle/cinn/common/dfs_walker.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace cinn {
namespace common {
TEST(DfsWalker, simple_on_push) {
DfsWalker<int> visitor(
[](int node, const std::function<void(int)>& NodeHandler) {
if (node == 0) {
NodeHandler(3);
} else if (node == 1) {
NodeHandler(2);
NodeHandler(3);
} else if (node == 2 || node == 3) {
NodeHandler(4);
}
});
std::vector<int> sources{0, 1};
std::vector<int> outputs;
visitor(sources.begin(), sources.end(), [&](int node) {
LOG(ERROR) << node;
outputs.push_back(node);
});
std::vector<int> expected{0, 3, 4, 1, 2};
EXPECT_TRUE((outputs == expected));
}
TEST(DfsWalker, simple_on_pop) {
DfsWalker<int> visitor(
[](int node, const std::function<void(int)>& NodeHandler) {
if (node == 0) {
NodeHandler(3);
} else if (node == 1) {
NodeHandler(2);
NodeHandler(3);
} else if (node == 2 || node == 3) {
NodeHandler(4);
}
});
std::vector<int> sources{0, 1};
std::vector<int> outputs;
visitor(
sources.begin(),
sources.end(),
[](int) {},
[&](int node) {
LOG(ERROR) << node;
outputs.push_back(node);
});
std::vector<int> expected{4, 3, 0, 2, 1};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,96 @@
// Copyright (c) 2023 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 <sstream>
#include "gtest/gtest.h"
#include "paddle/cinn/common/dim_expr_converter.h"
#include "paddle/cinn/common/ir_util.h"
#include "paddle/cinn/ir/ir_printer.h"
namespace cinn::common::test {
using namespace symbol; // NOLINT
TEST(Convert, AddExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Add<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
ir::Expr expr1 =
ir::Add::Make(ir::Expr(std::int64_t(4)), ir::Expr(std::int64_t(5)));
ir::Expr dst_expr =
ir::Add::Make(expr1,
ir::_Var_::Make(ir::Expr(static_cast<int64_t>(1)),
ir::Expr(INT32_MAX),
"sym_0",
/* is_reduce = */ false,
/* is_symbolic_constant = */ true));
ASSERT_TRUE(MathEqual(src_expr, dst_expr));
}
TEST(Convert, SubExpr) {
DimExpr dim_expr = DimExpr(4) - DimExpr("sym_0");
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
ir::Expr expr1 =
ir::Sub::Make(ir::Expr(std::int64_t(0)),
ir::_Var_::Make(ir::Expr(static_cast<int64_t>(1)),
ir::Expr(INT32_MAX),
"sym_0",
/* is_reduce = */ false,
/* is_symbolic_constant = */ true));
ir::Expr dst_expr = ir::Add::Make(ir::Expr(std::int64_t(4)), expr1);
ASSERT_TRUE(MathEqual(src_expr, dst_expr));
}
TEST(Convert, MulExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Mul<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
ir::Expr expr1 =
ir::Mul::Make(ir::Expr(std::int64_t(4)), ir::Expr(std::int64_t(5)));
ir::Expr dst_expr =
ir::Mul::Make(expr1,
ir::_Var_::Make(ir::Expr(static_cast<int64_t>(1)),
ir::Expr(INT32_MAX),
"sym_0",
/* is_reduce = */ false,
/* is_symbolic_constant = */ true));
ASSERT_TRUE(MathEqual(src_expr, dst_expr));
}
TEST(Convert, MaxExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Max<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
std::ostringstream stream;
stream << src_expr;
ASSERT_EQ(stream.str(), "cinn_max(cinn_max(4ll, 5ll), sym_0)");
}
TEST(Convert, MinExpr) {
List<DimExpr> num_lists{DimExpr(4), DimExpr(5), DimExpr("sym_0")};
DimExpr dim_expr{Min<DimExpr>{num_lists}};
ir::Expr src_expr = DimExprConverter().ConvertToIrExpr(dim_expr);
std::ostringstream stream;
stream << src_expr;
ASSERT_EQ(stream.str(), "cinn_min(cinn_min(4ll, 5ll), sym_0)");
}
} // namespace cinn::common::test
@@ -0,0 +1,116 @@
// Copyright (c) 2023 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.
// TODO(yifan): Add unittest here
#include "paddle/cinn/common/equation_graph_topo_walker.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace adt {
namespace common {
using VT = int;
using FT = std::string;
/*
Graph ex:
1-> "1->10" -> 10
2-> "2->20" -> 20
*/
TEST(EquationGraphTopoWalker, simple1) {
auto F4V = [](VT variable, const std::function<void(FT)>& visitor) {
if (variable == 1) {
visitor("1->10");
} else if (variable == 2) {
visitor("2->20");
}
};
auto InV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10") {
visitor(1);
} else if (function == "2->20") {
visitor(2);
}
};
auto OutV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10") {
visitor(10);
} else if (function == "2->20") {
visitor(20);
}
};
cinn::EquationGraphTopoWalker<VT, FT> walker(F4V, InV4F, OutV4F);
std::vector<FT> outputs;
std::function<void(FT)> FunctionVisitor = [&](FT function) {
outputs.push_back(function);
};
walker.WalkFunction(1, FunctionVisitor);
std::vector<FT> expected{"1->10"};
EXPECT_TRUE((outputs == expected));
}
/*
Graph ex:
1 -> "1->10, 1->11" -> 10
-> 11
2 -> "2->20" -> 20
3 -> "3->30, 3->31" -> 30
-> 31
*/
TEST(EquationGraphTopoWalker, simple2) {
auto F4V = [](VT variable, const std::function<void(FT)>& visitor) {
if (variable == 1) {
visitor("1->10, 1->11");
} else if (variable == 2) {
visitor("2->20");
} else if (variable == 3) {
visitor("3->30, 3->31");
}
};
auto InV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10, 1->11") {
visitor(1);
} else if (function == "2->20") {
visitor(2);
} else if (function == "3->30, 3->31") {
visitor(3);
}
};
auto OutV4F = [](FT function, const std::function<void(VT)>& visitor) {
if (function == "1->10, 1->11") {
visitor(10);
visitor(11);
} else if (function == "2->20") {
visitor(20);
} else if (function == "3->30, 3->31") {
visitor(30);
visitor(31);
}
};
cinn::EquationGraphTopoWalker<VT, FT> walker(F4V, InV4F, OutV4F);
std::vector<VT> outputs;
std::function<void(VT)> VariableVisitor = [&](VT variable) {
outputs.push_back(variable);
};
walker.WalkVariable(1, VariableVisitor);
std::vector<VT> expected{1, 10, 11};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace adt
@@ -0,0 +1,286 @@
// Copyright (c) 2021 CINN 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 <glog/logging.h>
#include <gtest/gtest.h>
#include <random>
#include <vector>
#include "paddle/cinn/common/bfloat16.h"
#include "paddle/cinn/common/float16.h"
#include "paddle/common/enforce.h"
namespace cinn {
namespace common {
#define CUDA_CALL(func) \
{ \
auto status = func; \
if (status != cudaSuccess) { \
std::stringstream ss; \
ss << "CUDA Error : " << cudaGetErrorString(status); \
PADDLE_THROW(::common::errors::Fatal(ss.str())); \
} \
}
class CudaMem {
public:
CudaMem() = default;
void* mutable_data(size_t bytes) {
PADDLE_ENFORCE_GT(
bytes,
0,
::common::errors::InvalidArgument("Cannot allocate empty memory!"));
if (ptr) {
PADDLE_ENFORCE_EQ(
bytes,
bytes_,
::common::errors::InvalidArgument("Try allocate memory twice!"));
return ptr;
}
CUDA_CALL(cudaMalloc(&ptr, bytes));
bytes_ = bytes;
return ptr;
}
template <typename T>
T* mutable_data(size_t num) {
return reinterpret_cast<T*>(mutable_data(num * sizeof(T)));
}
void* data() const {
PADDLE_ENFORCE_NOT_NULL(ptr,
::common::errors::InvalidArgument(
"Pointer is null; please ensure it is properly "
"initialized before use."));
return ptr;
}
template <typename T>
T* data() const {
return reinterpret_cast<T*>(data());
}
void MemcpyFromHost(const void* src,
size_t bytes,
cudaStream_t stream = nullptr) {
PADDLE_ENFORCE_LE(
bytes,
bytes_,
::common::errors::InvalidArgument("Too many data need copy"));
CUDA_CALL(cudaMemcpyAsync(ptr, src, bytes, cudaMemcpyHostToDevice, stream));
}
void MemcpyToHost(void* dst, size_t bytes, cudaStream_t stream = nullptr) {
PADDLE_ENFORCE_LE(
bytes,
bytes_,
::common::errors::InvalidArgument("Too many data need copy"));
CUDA_CALL(cudaMemcpyAsync(dst, ptr, bytes, cudaMemcpyDeviceToHost, stream));
}
~CudaMem() {
if (ptr) {
cudaFree(ptr);
}
bytes_ = 0;
}
private:
void* ptr{nullptr};
size_t bytes_{0};
};
__global__ void cast_fp32_to_fp16_cuda_kernel(const float* input,
const int num,
float16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = float16(input[idx]);
}
}
__global__ void cast_fp16_to_fp32_cuda_kernel(const float16* input,
const int num,
float* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = static_cast<float>(input[idx]);
}
}
__global__ void test_fp16_cuda_kernel(const float16* x,
const float16* y,
const int num,
float16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
float16 x_i = x[idx], y_i = y[idx];
x_i += float16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
}
__global__ void cast_fp32_to_bf16_cuda_kernel(const float* input,
const int num,
bfloat16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = bfloat16(input[idx]);
}
}
__global__ void cast_bf16_to_fp32_cuda_kernel(const bfloat16* input,
const int num,
float* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
out[idx] = static_cast<float>(input[idx]);
}
}
__global__ void test_bf16_cuda_kernel(const bfloat16* x,
const bfloat16* y,
const int num,
bfloat16* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
bfloat16 x_i = x[idx], y_i = y[idx];
x_i += bfloat16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
}
__global__ void test_fp32_cuda_kernel(const float* x,
const float* y,
const int num,
float* out) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
float x_i = x[idx], y_i = y[idx];
x_i += 1.0f;
out[idx] = (x_i + y_i) * (x_i - y_i);
}
}
TEST(FP16_BF16, basic_cuda) {
#ifdef CUDA_VERSION
LOG(INFO) << "CUDA version: " << CUDA_VERSION;
#endif
int num = 2048;
cudaStream_t stream;
CUDA_CALL(cudaStreamCreate(&stream));
dim3 block = 1024;
dim3 grid = (num + block.x - 1) / block.x;
std::vector<float> x_fp32_host(num), y_fp32_host(num);
{ // step1 : generate input data
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<float> dis(1e-5f, 1.0f);
for (int i = 0; i < num; ++i) {
x_fp32_host[i] = dis(eng);
y_fp32_host[i] = dis(eng);
}
}
CudaMem x_fp32_device, y_fp32_device, out_fp32_device;
{ // step2 : compute fp32 result
auto x_fp32_ptr = x_fp32_device.mutable_data<float>(num);
auto y_fp32_ptr = y_fp32_device.mutable_data<float>(num);
auto out_fp32_ptr = out_fp32_device.mutable_data<float>(num);
x_fp32_device.MemcpyFromHost(
x_fp32_host.data(), num * sizeof(float), stream);
y_fp32_device.MemcpyFromHost(
y_fp32_host.data(), num * sizeof(float), stream);
test_fp32_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp32_ptr, y_fp32_ptr, num, out_fp32_ptr);
}
CudaMem x_fp16_device, y_fp16_device, out_fp16_device;
CudaMem x_bf16_device, y_bf16_device, out_bf16_device;
{ // step3 : compute fp16/bf16 result
// step3.1 : compute fp16 result
auto x_fp16_ptr = x_fp16_device.mutable_data<float16>(num);
auto y_fp16_ptr = y_fp16_device.mutable_data<float16>(num);
auto out_fp16_ptr = out_fp16_device.mutable_data<float16>(num);
cast_fp32_to_fp16_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp32_device.data<float>(), num, x_fp16_ptr);
cast_fp32_to_fp16_cuda_kernel<<<grid, block, 0, stream>>>(
y_fp32_device.data<float>(), num, y_fp16_ptr);
test_fp16_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp16_ptr, y_fp16_ptr, num, out_fp16_ptr);
// step3.2 : compute bf16 result
auto x_bf16_ptr = x_bf16_device.mutable_data<bfloat16>(num);
auto y_bf16_ptr = y_bf16_device.mutable_data<bfloat16>(num);
auto out_bf16_ptr = out_bf16_device.mutable_data<bfloat16>(num);
cast_fp32_to_bf16_cuda_kernel<<<grid, block, 0, stream>>>(
x_fp32_device.data<float>(), num, x_bf16_ptr);
cast_fp32_to_bf16_cuda_kernel<<<grid, block, 0, stream>>>(
y_fp32_device.data<float>(), num, y_bf16_ptr);
test_bf16_cuda_kernel<<<grid, block, 0, stream>>>(
x_bf16_ptr, y_bf16_ptr, num, out_bf16_ptr);
}
CudaMem fp32res_fp16_device;
CudaMem fp32res_bf16_device;
{ // step4 : cast fp16/bf16 result to fp32 result
// step4.1 : cast fp16 result to fp32 result
auto fp32res_fp16_ptr = fp32res_fp16_device.mutable_data<float>(num);
cast_fp16_to_fp32_cuda_kernel<<<grid, block, 0, stream>>>(
out_fp16_device.data<float16>(), num, fp32res_fp16_ptr);
// step4.2 : cast bf16 result to fp32 result
auto fp32res_bf16_ptr = fp32res_bf16_device.mutable_data<float>(num);
cast_bf16_to_fp32_cuda_kernel<<<grid, block, 0, stream>>>(
out_bf16_device.data<bfloat16>(), num, fp32res_bf16_ptr);
}
std::vector<float> out_fp32_host(num), out_fp16_host(num), out_bf16_host(num);
{ // step5 : copy result from device to host
out_fp32_device.MemcpyToHost(
out_fp32_host.data(), num * sizeof(float), stream);
fp32res_fp16_device.MemcpyToHost(
out_fp16_host.data(), num * sizeof(float), stream);
fp32res_bf16_device.MemcpyToHost(
out_bf16_host.data(), num * sizeof(float), stream);
}
CUDA_CALL(cudaStreamSynchronize(stream));
for (int i = 0; i < num; ++i) {
ASSERT_NEAR(out_fp32_host[i], out_fp16_host[i], 1e-2f);
ASSERT_NEAR(out_fp32_host[i], out_bf16_host[i], 1e-1f);
}
CUDA_CALL(cudaStreamDestroy(stream));
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,104 @@
// Copyright (c) 2021 CINN 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 <glog/logging.h>
#include <gtest/gtest.h>
#include <random>
#include <vector>
#include "paddle/cinn/common/bfloat16.h"
#include "paddle/cinn/common/float16.h"
namespace cinn {
namespace common {
std::vector<float16> test_fp16_host_kernel(const float16* x,
const float16* y,
const int num) {
std::vector<float16> out(num);
for (int idx = 0; idx < num; ++idx) {
float16 x_i = x[idx], y_i = y[idx];
x_i += float16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
return out;
}
std::vector<bfloat16> test_bf16_host_kernel(const bfloat16* x,
const bfloat16* y,
const int num) {
std::vector<bfloat16> out(num);
for (int idx = 0; idx < num; ++idx) {
bfloat16 x_i = x[idx], y_i = y[idx];
x_i += bfloat16(1);
out[idx] = (x_i + y_i) * (x_i - y_i);
}
return out;
}
std::vector<float> test_fp32_host_kernel(const float* x,
const float* y,
const int num) {
std::vector<float> out(num);
for (int idx = 0; idx < num; ++idx) {
float x_i = x[idx], y_i = y[idx];
x_i += 1.0f;
out[idx] = (x_i + y_i) * (x_i - y_i);
}
return out;
}
TEST(FP16_BF16, basic_host) {
int num = 2048;
// int num = 2;
std::vector<float16> x_fp16(num), y_fp16(num);
std::vector<bfloat16> x_bf16(num), y_bf16(num);
std::vector<float> x_fp32(num), y_fp32(num);
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<float> dis(1e-5f, 1.0f);
for (int i = 0; i < num; ++i) {
x_fp16[i] = x_fp32[i] = dis(eng);
y_fp16[i] = y_fp32[i] = dis(eng);
x_fp16[i] = x_fp32[i];
y_fp16[i] = y_fp32[i];
x_bf16[i] = x_fp32[i];
y_bf16[i] = y_fp32[i];
}
auto out_fp16 = test_fp16_host_kernel(x_fp16.data(), y_fp16.data(), num);
ASSERT_EQ(out_fp16.size(), num);
auto out_bf16 = test_bf16_host_kernel(x_bf16.data(), y_bf16.data(), num);
ASSERT_EQ(out_bf16.size(), num);
auto out_fp32 = test_fp32_host_kernel(x_fp32.data(), y_fp32.data(), num);
ASSERT_EQ(out_fp32.size(), num);
for (int i = 0; i < num; ++i) {
ASSERT_NEAR(static_cast<float>(out_fp16[i]), out_fp32[i], 1e-2f);
ASSERT_NEAR(static_cast<float>(out_bf16[i]), out_fp32[i], 1e-1f);
}
}
} // namespace common
} // namespace cinn
+341
View File
@@ -0,0 +1,341 @@
// Copyright (c) 2023 CINN 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 "paddle/cinn/common/integer_set.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "paddle/cinn/ir/op/ir_operators.h"
namespace cinn {
namespace common {
class TestSymbolicExprAnalyzer : public ::testing::Test {
public:
void SetUp() override {
// Var is [lower_bound, upper_bound)
i = ir::Var(ir::Expr(0), ir::Expr(7), "i"); // i ∈ [0, 7)
j = ir::Var(ir::Expr(0), ir::Expr(15), "j"); // j ∈ [0, 15)
// CasInterval is [lower_bound, upper_bound]
var_intervals = {
{"i", CasInterval(i->lower_bound, i->upper_bound - 1)}, // i ∈ [0, 6]
{"j", CasInterval(j->lower_bound, j->upper_bound - 1)}, // j ∈ [0, 14]
};
}
ir::Var i;
ir::Var j;
cas_intervals_t var_intervals;
SymbolicExprAnalyzer analyzer{var_intervals};
};
TEST_F(TestSymbolicExprAnalyzer, bound) {
ir::Expr e1 = i + j;
EXPECT_EQ(analyzer.LowerBound(e1), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e1), ir::Expr(20)); // 6 + 14 = 20
ir::Expr e2 = 16 * i + j;
EXPECT_EQ(analyzer.LowerBound(e2), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e2), ir::Expr(110)); // 16 * 6 + 14 = 110
ir::Expr e3 = 16 * i + j + 1;
EXPECT_EQ(analyzer.LowerBound(e3), ir::Expr(1));
EXPECT_EQ(analyzer.UpperBound(e3), ir::Expr(111)); // 16 * 6 + 15 = 111
ir::Expr e4 = (16 * i + j) / 16;
EXPECT_EQ(analyzer.LowerBound(e4), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e4), ir::Expr(6)); // 110 / 16 = 6
ir::Expr e5 = (16 * i + j) % 16;
EXPECT_EQ(analyzer.LowerBound(e5), ir::Expr(0));
EXPECT_EQ(analyzer.UpperBound(e5), ir::Expr(14)); // 110 % 16
ir::Expr e6 = i - j;
EXPECT_EQ(analyzer.LowerBound(e6), ir::Expr(-14)); // 0 - 14
EXPECT_EQ(analyzer.UpperBound(e6), ir::Expr(6)); // 6 - 0
ir::Expr e7 = 0 - i - j;
EXPECT_EQ(analyzer.LowerBound(e7), ir::Expr(-20)); // 0 - 6 - 14
EXPECT_EQ(analyzer.UpperBound(e7), ir::Expr(0)); // 0 - 0 - 0
ir::Expr e8 = -1 * i - j;
EXPECT_EQ(analyzer.LowerBound(e8), ir::Expr(-20)); // -1 * 6 - 14
EXPECT_EQ(analyzer.UpperBound(e8), ir::Expr(0)); // -1 * 0 - 0
}
TEST_F(TestSymbolicExprAnalyzer, compare) {
// case 1
ir::Expr e1 = 4 * i + 2 * j;
ir::Expr e2 = 2 * i + j;
EXPECT_TRUE(analyzer.ProveEQ(e1, e1).value() &&
analyzer.Prove(ir::EQ::Make(e1, e1)).value());
EXPECT_FALSE(analyzer.ProveEQ(e1, e2).has_value() ||
analyzer.Prove(ir::EQ::Make(e1, e2)).has_value());
EXPECT_FALSE(analyzer.ProveNE(e1, e1).value() &&
analyzer.Prove(ir::NE::Make(e1, e1)).value());
EXPECT_FALSE(analyzer.ProveNE(e1, e2).has_value() ||
analyzer.Prove(ir::NE::Make(e1, e2)).has_value());
EXPECT_TRUE(analyzer.ProveGE(e1, e2).value() &&
analyzer.Prove(e1 >= e2).value());
EXPECT_FALSE(analyzer.ProveGE(e2, e1).has_value() ||
analyzer.Prove(e2 >= e1).has_value());
EXPECT_TRUE(analyzer.ProveLE(e2, e1).value() &&
analyzer.Prove(e2 <= e1).value());
EXPECT_FALSE(analyzer.ProveLE(e1, e2).has_value() ||
analyzer.Prove(e1 <= e2).has_value());
EXPECT_FALSE(analyzer.ProveGT(e1, e2).has_value() ||
analyzer.Prove(e1 > e2).has_value());
EXPECT_FALSE(analyzer.ProveGT(e2, e1).value() &&
analyzer.Prove(e2 > e1).value());
EXPECT_FALSE(analyzer.ProveLT(e2, e1).has_value() ||
analyzer.Prove(e2 < e1).has_value());
EXPECT_FALSE(analyzer.ProveLT(e1, e2).value() &&
analyzer.Prove(e1 < e2).value());
// case 2
ir::Expr e3 = i + j + 1;
ir::Expr e4 = i + j;
EXPECT_TRUE(analyzer.ProveEQ(e3, e3).value() &&
analyzer.Prove(ir::EQ::Make(e3, e3)).value());
EXPECT_FALSE(analyzer.ProveEQ(e3, e4).value() &&
analyzer.Prove(ir::EQ::Make(e3, e4)).value());
EXPECT_TRUE(analyzer.ProveNE(e3, e4).value() &&
analyzer.Prove(ir::NE::Make(e3, e4)).value());
EXPECT_FALSE(analyzer.ProveNE(e4, e4).value() &&
analyzer.Prove(ir::NE::Make(e4, e4)).value());
EXPECT_TRUE(analyzer.ProveGE(e3, e4).value() &&
analyzer.Prove(e3 >= e4).value());
EXPECT_FALSE(analyzer.ProveGE(e4, e3).value() &&
analyzer.Prove(e4 >= e3).value());
EXPECT_TRUE(analyzer.ProveLE(e4, e3).value() &&
analyzer.Prove(e4 <= e3).value());
EXPECT_FALSE(analyzer.ProveLE(e3, e4).value() &&
analyzer.Prove(e3 <= e4).value());
EXPECT_TRUE(analyzer.ProveGT(e3, e4).value() &&
analyzer.Prove(e3 > e4).value());
EXPECT_FALSE(analyzer.ProveGT(e4, e3).value() &&
analyzer.Prove(e4 > e3).value());
EXPECT_TRUE(analyzer.ProveLT(e4, e3).value() &&
analyzer.Prove(e4 < e3).value());
EXPECT_FALSE(analyzer.ProveLT(e3, e4).value() &&
analyzer.Prove(e3 < e4).value());
}
TEST_F(TestSymbolicExprAnalyzer, Divisible) {
auto x = ir::Var(ir::Expr(1), ir::Expr(7), "x");
auto y = ir::Var(ir::Expr(1), ir::Expr(15), "y");
auto S = ir::Var(ir::Expr(16), ir::Expr(256), "S");
cas_intervals_t divisible_var_intervals = {
{"x", CasInterval(x->lower_bound, x->upper_bound - ir::Expr(1))},
{"y", CasInterval(y->lower_bound, y->upper_bound - ir::Expr(1))},
{"S", CasInterval(S->lower_bound, S->upper_bound - ir::Expr(1))},
};
SymbolicExprAnalyzer divisible_analyzer{divisible_var_intervals};
// case 1
ir::Expr e1 = 4 * x + 2 * y * x;
ir::Expr e2 = x;
ir::Expr e3 = y;
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e1, e2).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e1, e3).value_or(false));
// case 2
ir::Expr e4 = y + y * x + 4 * y - x * y;
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e4, e3).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e4, e2).value_or(false));
// case 3
ir::Expr e5 = x / y + x + y;
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e5, e3).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e5, e2).value_or(false));
// case 4
ir::Expr e6 = S * x / 4 + x * y;
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e6, e2).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e6, e3).value_or(false));
ir::Expr e7 = 16 * x / 4 + x * y;
EXPECT_TRUE(divisible_analyzer.ProveDivisible(e7, e2).value_or(false));
EXPECT_FALSE(divisible_analyzer.ProveDivisible(e7, e3).value_or(false));
}
TEST(SingleIntervalIntSet, constant) {
SingleIntervalIntSet empty_set(ir::Expr(0), ir::Expr(-1));
SingleIntervalIntSet all_set(SymbolicExprLimit::negative_inf,
SymbolicExprLimit::positive_inf);
SingleIntervalIntSet single_point(ir::Expr(0), ir::Expr(0));
SingleIntervalIntSet interval_0_2_set(ir::Expr(0), ir::Expr(2));
SingleIntervalIntSet interval_0_4_set(ir::Expr(0), ir::Expr(4));
SingleIntervalIntSet interval_2_6_set(ir::Expr(2), ir::Expr(6));
SingleIntervalIntSet interval_8_9_set(ir::Expr(8), ir::Expr(9));
EXPECT_TRUE(empty_set.ProveEmpty().value());
EXPECT_FALSE(empty_set.ProveAll().value());
EXPECT_FALSE(all_set.ProveEmpty().value());
EXPECT_TRUE(all_set.ProveAll().value());
EXPECT_TRUE(single_point.ProvePoint().value());
EXPECT_FALSE(interval_0_2_set.ProvePoint().value());
EXPECT_TRUE(interval_0_2_set.ProveSubSet(interval_0_4_set).value());
EXPECT_FALSE(interval_0_4_set.ProveSubSet(interval_0_2_set).value());
EXPECT_FALSE(interval_0_2_set.ProveSuperSet(interval_0_4_set).value());
EXPECT_TRUE(interval_0_4_set.ProveSuperSet(interval_0_2_set).value());
EXPECT_TRUE(ProveEQ(interval_0_2_set, interval_0_2_set).value());
EXPECT_FALSE(ProveEQ(interval_0_2_set, interval_0_4_set).value());
SingleIntervalIntSet union_0_6_set =
ProvedUnion(interval_0_2_set, interval_2_6_set).value();
EXPECT_EQ(union_0_6_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_6_set.Max(), ir::Expr(6));
union_0_6_set = ProvedUnion(interval_2_6_set, interval_0_2_set).value();
EXPECT_EQ(union_0_6_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_6_set.Max(), ir::Expr(6));
SingleIntervalIntSet union_0_4_set =
ProvedUnion(interval_0_2_set, interval_0_4_set).value();
EXPECT_EQ(union_0_4_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_4_set.Max(), ir::Expr(4));
union_0_4_set = ProvedUnion(interval_0_4_set, interval_0_2_set).value();
EXPECT_EQ(union_0_4_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_4_set.Max(), ir::Expr(4));
SingleIntervalIntSet union_0_9_set =
ProvedUnion(interval_0_4_set, interval_8_9_set).value();
EXPECT_EQ(union_0_9_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_9_set.Max(), ir::Expr(9));
union_0_9_set = ProvedUnion(interval_8_9_set, interval_0_4_set).value();
EXPECT_EQ(union_0_9_set.Min(), ir::Expr(0));
EXPECT_EQ(union_0_9_set.Max(), ir::Expr(9));
SingleIntervalIntSet intersect_0_2_set =
ProvedIntersect(interval_0_2_set, interval_0_4_set).value();
EXPECT_EQ(intersect_0_2_set.Min(), ir::Expr(0));
EXPECT_EQ(intersect_0_2_set.Max(), ir::Expr(2));
intersect_0_2_set =
ProvedIntersect(interval_0_4_set, interval_0_2_set).value();
EXPECT_EQ(intersect_0_2_set.Min(), ir::Expr(0));
EXPECT_EQ(intersect_0_2_set.Max(), ir::Expr(2));
SingleIntervalIntSet intersect_2_2_set =
ProvedIntersect(interval_0_2_set, interval_2_6_set).value();
EXPECT_EQ(intersect_2_2_set.Min(), ir::Expr(2));
EXPECT_EQ(intersect_2_2_set.Max(), ir::Expr(2));
intersect_2_2_set =
ProvedIntersect(interval_2_6_set, interval_0_2_set).value();
EXPECT_EQ(intersect_2_2_set.Min(), ir::Expr(2));
EXPECT_EQ(intersect_2_2_set.Max(), ir::Expr(2));
SingleIntervalIntSet intersect_empty_set =
ProvedIntersect(interval_0_4_set, interval_8_9_set).value();
EXPECT_TRUE(intersect_empty_set.ProveEmpty().value());
intersect_empty_set =
ProvedIntersect(interval_8_9_set, interval_0_4_set).value();
EXPECT_TRUE(intersect_empty_set.ProveEmpty().value());
}
TEST(SingleIntervalIntSet, case_0) {
ir::Var S0 = ir::Var(ir::Expr(0), ir::Expr(7), "S0");
ir::Expr e1 = S0 * 16;
ir::Expr e2 = S0 * 16 + 7;
ir::Expr e3 = S0 * 16 + 15;
SingleIntervalIntSet empty_set(e2, e1);
SingleIntervalIntSet single_point(e3, e3);
SingleIntervalIntSet set_0(e1, e2);
SingleIntervalIntSet set_1(e1, e3);
EXPECT_TRUE(empty_set.ProveEmpty().value());
EXPECT_FALSE(empty_set.ProveAll().value());
EXPECT_TRUE(single_point.ProvePoint().value());
EXPECT_FALSE(set_0.ProvePoint().value());
EXPECT_TRUE(ProveEQ(set_0, set_0).value());
EXPECT_FALSE(ProveEQ(set_0, set_1).value());
EXPECT_TRUE(set_0.ProveSubSet(set_1).value());
EXPECT_FALSE(set_1.ProveSubSet(set_0).value());
EXPECT_FALSE(set_0.ProveSuperSet(set_1).value());
EXPECT_TRUE(set_1.ProveSuperSet(set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, set_1).value(), set_1).value());
EXPECT_TRUE(ProveEQ(ProvedIntersect(set_0, set_1).value(), set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_1, single_point).value(), set_1).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_1, single_point).value(), single_point)
.value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, empty_set).value(), set_0).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_0, empty_set).value(), empty_set).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, single_point).value(), set_1).value());
EXPECT_TRUE(ProvedIntersect(set_0, single_point).value().ProveEmpty());
}
TEST(SingleIntervalIntSet, case_1) {
ir::Var S0 = ir::Var(ir::Expr(0), ir::Expr(7), "S0");
ir::Var S1 = ir::Var(ir::Expr(0), ir::Expr(15), "S1");
ir::Expr e1 = S0 * 16;
ir::Expr e2 = S0 * 16 + S1;
ir::Expr e3 = S0 * 16 + S1 * 2 + 1;
SingleIntervalIntSet empty_set(e3, e1);
SingleIntervalIntSet single_point(e3, e3);
SingleIntervalIntSet set_0(e1, e2);
SingleIntervalIntSet set_1(e1, e3);
EXPECT_TRUE(empty_set.ProveEmpty().value());
EXPECT_FALSE(empty_set.ProveAll().value());
EXPECT_TRUE(single_point.ProvePoint().value());
EXPECT_FALSE(set_0.ProvePoint().has_value());
EXPECT_TRUE(ProveEQ(set_0, set_0).value());
EXPECT_FALSE(ProveEQ(set_0, set_1).value());
EXPECT_TRUE(set_0.ProveSubSet(set_1).value());
EXPECT_FALSE(set_1.ProveSubSet(set_0).value());
EXPECT_FALSE(set_0.ProveSuperSet(set_1).value());
EXPECT_TRUE(set_1.ProveSuperSet(set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, set_1).value(), set_1).value());
EXPECT_TRUE(ProveEQ(ProvedIntersect(set_0, set_1).value(), set_0).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_1, single_point).value(), set_1).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_1, single_point).value(), single_point)
.value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, empty_set).value(), set_0).value());
EXPECT_TRUE(
ProveEQ(ProvedIntersect(set_0, empty_set).value(), empty_set).value());
EXPECT_TRUE(ProveEQ(ProvedUnion(set_0, single_point).value(), set_1).value());
EXPECT_TRUE(
ProvedIntersect(set_0, single_point).value().ProveEmpty().value());
}
TEST(SingleIntervalIntSet, case_2) {
ir::Var S = ir::Var(ir::Expr(0), ir::Expr(1), "S"); // S ∈ [0, 1)
SingleIntervalIntSet set_0{S, S + Expr(1)}; // [0, 1]
SingleIntervalIntSet set_1{Expr(0), Expr(1)}; // [0, 1]
SingleIntervalIntSet set_2{Expr(0), Expr(2)}; // [0, 2]
EXPECT_TRUE(ProveEQ(set_0, set_1).value());
EXPECT_FALSE(ProveEQ(set_0, set_2).value());
EXPECT_TRUE(set_0.ProveSubSet(set_2).value());
EXPECT_TRUE(set_2.ProveSuperSet(set_0).value());
}
} // namespace common
} // namespace cinn
@@ -0,0 +1,38 @@
// Copyright (c) 2023 CINN 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 "paddle/cinn/common/is_reachable_predicator.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace cinn {
namespace common {
TEST(IsReachablePredicator, simple) {
IsReachablePredicator<int> IsReachable(
// Get min depth
[](int x) { return std::abs(x); },
// Get max depth
[](int x) { return std::abs(x); },
// visit next node
[](int x, const std::function<void(int)>& Handler) {
Handler(x + (x / std::abs(x)));
});
EXPECT_TRUE(IsReachable(33, 99, [](int) {}));
EXPECT_FALSE(IsReachable(33, -99, [](int) {}));
}
} // namespace common
} // namespace cinn
+55
View File
@@ -0,0 +1,55 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/common/shared.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include "paddle/cinn/common/object.h"
namespace cinn {
namespace common {
struct A : public Object {
const char *type_info() const override { return "A"; }
Shared<A> other;
};
class B : public Object {};
TEST(Shared, test) {
Shared<A> a_ref(make_shared<A>());
ASSERT_EQ(ref_count(a_ref.get()).val(), 1);
{ // local copy
Shared<A> b = a_ref;
EXPECT_EQ(ref_count(a_ref.get()).val(), 2);
ASSERT_EQ(ref_count(b.get()).val(), 2);
}
ASSERT_EQ(ref_count(a_ref.get()).val(), 1);
}
TEST(Shared, cycle_share) {
{
Shared<A> a_ref(make_shared<A>());
a_ref->other = a_ref;
ASSERT_EQ(a_ref->__ref_count__.val(), 2);
}
}
} // namespace common
} // namespace cinn
+51
View File
@@ -0,0 +1,51 @@
// Copyright (c) 2023 CINN 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 "paddle/cinn/common/topo_walker.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
namespace cinn {
namespace common {
TEST(TopoWalker, simple) {
std::vector<std::pair<int, int>> edges{
{0, 3}, {1, 2}, {1, 3}, {2, 3}, {3, 4}};
TopoWalker<int> visitor(
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.second == node) {
NodeHandler(pair.first);
}
}
},
[&](int node, const std::function<void(int)>& NodeHandler) {
for (const auto& pair : edges) {
if (pair.first == node) {
NodeHandler(pair.second);
}
}
});
std::vector<int> sources{0, 1};
std::vector<int> outputs;
visitor(sources.begin(), sources.end(), [&](int node) {
outputs.push_back(node);
});
std::vector<int> expected{0, 1, 2, 3, 4};
EXPECT_TRUE((outputs == expected));
}
} // namespace common
} // namespace cinn
+31
View File
@@ -0,0 +1,31 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/common/type.h"
#include <gtest/gtest.h>
namespace cinn::common {
TEST(Type, basic) {
LOG(INFO) << I32();
auto i32 = I32();
LOG(INFO) << I32();
LOG(INFO) << F32();
LOG(INFO) << type_of<float>();
}
} // namespace cinn::common
+1
View File
@@ -0,0 +1 @@
add_subdirectory(pe)
+1
View File
@@ -0,0 +1 @@
cinn_cc_test(test_load_params SRCS load_params_test.cc DEPS cinncore)
+65
View File
@@ -0,0 +1,65 @@
// Copyright (c) 2021 CINN 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 <gtest/gtest.h>
#include "paddle/cinn/hlir/pe/schedule.h"
namespace cinn {
namespace hlir {
namespace pe {
using ir::Tensor;
TEST(load_x86_params, load_x86_params) {
auto &res = ScheduleParam::get_x86_instance().GetParam();
std::string key =
"X86ScheduleConv input 1 3 224 224 weight 64 3 7 7 stride 2 2 padding 3 "
"3 dilation 1 1";
ASSERT_EQ(res.count(key), 1);
paddle::flat_hash_map<std::string, int> conv2d_factors;
auto target = cinn::common::DefaultHostTarget();
std::vector<int> shape_input = {1, 64, 56, 56};
std::vector<int> shape_weights = {64, 64, 3, 3};
std::vector<int> strides = {1, 1};
std::vector<int> pads = {1, 1};
std::vector<int> dilations = {1, 1};
key =
GenerateX86ConvKey(shape_input, shape_weights, strides, pads, dilations);
GetConv2dFactors(&conv2d_factors, -1, -1, -1, -1, -1, Float(32), target, key);
int ic_bn_size = conv2d_factors["ic_bn"];
int oc_bn_size = conv2d_factors["oc_bn"];
int fc_bn_size = conv2d_factors["fc_bn"];
int ow_bn_size = conv2d_factors["ow_bn"];
int unroll_kw = conv2d_factors["unroll_kw"];
ASSERT_EQ(ic_bn_size, 64);
ASSERT_EQ(fc_bn_size, 64);
ASSERT_EQ(oc_bn_size, 32);
ASSERT_EQ(ow_bn_size, 7);
ASSERT_EQ(unroll_kw, 1);
}
TEST(load_cuda_params, load_cuda_params) {
auto &res = ScheduleParam::get_cuda_instance().GetParam();
if (res.empty()) {
CreateCudaSerialData();
LoadSerialData(&res);
}
std::string key = "CudaDirectConvSchedule 1 3 230 230 64 3 7 7 1 64 112 112";
ASSERT_EQ(res.count(key), 1);
}
} // namespace pe
} // namespace hlir
} // namespace cinn
+1
View File
@@ -0,0 +1 @@
add_subdirectory(test)
+9
View File
@@ -0,0 +1,9 @@
# cinn_cc_test(test_ir SRCS ir_test.cc DEPS core)
# cinn_cc_test(test_ir_printer SRCS ir_printer_test.cc DEPS core)
# cinn_cc_test(test_ir_operators SRCS ir_operators_test.cc DEPS core)
# cinn_cc_test(test_tensor SRCS tensor_test.cc DEPS core)
cinn_cc_test(test_collect_ir_nodes SRCS collect_ir_nodes_test.cc DEPS cinncore)
cinn_cc_test(test_intrinsic_ops SRCS intrinsic_ops_test.cc DEPS cinncore)
cinn_cc_test(test_ir_verify SRCS ir_verify_test.cc DEPS cinncore)
cinn_cc_test(test_ir_copy SRCS ir_copy_test.cc DEPS cinncore)
@@ -0,0 +1,65 @@
// Copyright (c) 2021 CINN 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 <gtest/gtest.h>
#include "paddle/cinn/cinn.h"
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/utils/stmt_converter.h"
namespace cinn {
namespace ir {
namespace ir_utils {
TEST(CollectIRNodes, basic0) {
Expr C = Expr(1) + 2;
auto exprs =
CollectIRNodes(C, [](const Expr* x) { return x->As<ir::Add>(); });
ASSERT_EQ(exprs.size(), 1UL);
auto ints =
CollectIRNodes(C, [](const Expr* x) { return x->As<ir::IntImm>(); });
ASSERT_EQ(ints.size(), 2UL);
}
TEST(CollectIRNodes, basic) {
Expr M(100);
Expr N(200);
Placeholder<float> A("A", {M, N});
Placeholder<float> B("B", {M, N});
auto C = Compute(
{M, N}, [&](Var i, Var j) { return A(i, j) + B(i, j); }, "C");
ast_gen_ius::TensorGroup tensor_group({C});
auto fn = LowerToAst("fn", {A, B, C}, &tensor_group);
LOG(INFO) << "fn:\n" << fn;
Expr expr_func_body = ConvertStmtBlockToExprBlock(fn->body_block);
auto tensors = CollectIRNodes(expr_func_body,
[](const Expr* x) { return x->as_tensor(); });
ASSERT_EQ(tensors.size(), 3UL);
LOG(INFO) << "fn.body:\n" << expr_func_body;
auto tensors2 = CollectIRNodes(expr_func_body,
[](const Expr* x) { return x->as_tensor(); });
auto exprs = CollectIRNodes(expr_func_body, [](const Expr* x) { return x; });
}
} // namespace ir_utils
} // namespace ir
} // namespace cinn
@@ -0,0 +1,31 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/intrinsic_ops.h"
#include <gtest/gtest.h>
namespace cinn::ir {
TEST(IntrinsicOp, basic) {
Expr buffer(1);
buffer->set_type(type_of<cinn_buffer_t*>());
auto op = intrinsics::BufferGetDataHandle::Make(buffer);
auto* ptr = op.As<IntrinsicOp>();
ASSERT_TRUE(ptr);
auto* obj = llvm::dyn_cast<intrinsics::BufferGetDataHandle>(ptr);
ASSERT_TRUE(obj);
}
} // namespace cinn::ir
+32
View File
@@ -0,0 +1,32 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/utils/ir_copy.h"
#include <gtest/gtest.h>
#include "paddle/cinn/ir/ir_printer.h"
namespace cinn {
namespace ir {
namespace ir_utils {
TEST(IrCopy, basic) {
Expr a(1.f);
auto aa = IRCopy(a);
LOG(INFO) << "aa " << aa;
}
} // namespace ir_utils
} // namespace ir
} // namespace cinn
@@ -0,0 +1,28 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/op/ir_operators.h"
#include <gtest/gtest.h>
namespace cinn {
namespace ir {
TEST(ir_operators, test) {
Expr a(1);
Expr b = a + 1;
}
} // namespace ir
} // namespace cinn
+23
View File
@@ -0,0 +1,23 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/ir_printer.h"
#include <gtest/gtest.h>
#include <sstream>
namespace cinn {
namespace ir {} // namespace ir
} // namespace cinn
+31
View File
@@ -0,0 +1,31 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/ir.h"
#include <gtest/gtest.h>
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace ir {
TEST(Expr, basic) {
Expr a(1);
auto b = Expr(a);
LOG(INFO) << b.as_int32();
}
} // namespace ir
} // namespace cinn
+31
View File
@@ -0,0 +1,31 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/ir/utils/ir_verify.h"
#include <gtest/gtest.h>
#include "paddle/cinn/ir/op/ir_operators.h"
namespace cinn {
namespace ir {
namespace ir_utils {
TEST(IrVerify, basic) {
Expr a(1);
Expr b(1);
IrVerify(a + b);
}
} // namespace ir_utils
} // namespace ir
} // namespace cinn
+2
View File
@@ -0,0 +1,2 @@
cinn_cc_test(test_compute SRCS compute_test.cc DEPS cinncore)
cinn_cc_test(test_cinn_packed_func SRCS packed_func_test.cc DEPS cinncore)
+39
View File
@@ -0,0 +1,39 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/lang/compute.h"
#include <gtest/gtest.h>
#include "paddle/cinn/cinn.h"
#include "paddle/cinn/ir/op/ir_operators.h"
#include "paddle/cinn/ir/tensor.h"
#include "paddle/cinn/lang/placeholder.h"
namespace cinn {
namespace lang {
TEST(Call, basic) {
Expr M(100);
Placeholder<float> x("x", {M, Expr(10)});
Placeholder<float> y("y", {M, Expr(10)});
std::vector<ReturnType> return_types(
{{Float(32), std::vector<Expr>{{M, Expr(20)}}, "C"}});
auto tensors = CallLowered("lowered_fun0", {Expr(x), Expr(y)}, return_types);
}
} // namespace lang
} // namespace cinn
+96
View File
@@ -0,0 +1,96 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/lang/packed_func.h"
#include <gtest/gtest.h>
#include "paddle/cinn/ir/ir_printer.h"
#include "paddle/cinn/ir/op/ir_operators.h"
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace lang {
TEST(Function, test) {
PackedFunc::body_t func_body = [](Args args, RetValue* ret) {
int a = args[0];
int b = args[1];
*ret = (a + b);
};
PackedFunc func(func_body);
int c = func(1, 2);
LOG(INFO) << "c " << c;
}
TEST(Function, test1) {
PackedFunc::body_t body = [](Args args, RetValue* ret) {
auto* msg = static_cast<const char*>(args[0]);
(*ret) = msg;
};
PackedFunc func(body);
const char* msg = "hello world";
char* c = func(msg);
LOG(INFO) << static_cast<char*>(c);
}
TEST(Function, Expr) {
PackedFunc::body_t body = [](Args args, RetValue* ret) {
Expr a = args[0];
Expr b = args[1];
ASSERT_EQ(a->__ref_count__.val(), 4);
ASSERT_EQ(b->__ref_count__.val(), 4);
Expr c = a + b;
(*ret) = CINNValue(c);
};
PackedFunc func(body);
Expr a(1);
Expr b(2);
ASSERT_EQ(a->__ref_count__.val(), 1);
ASSERT_EQ(b->__ref_count__.val(), 1);
Expr ret = func(a, b);
ASSERT_EQ(utils::GetStreamCnt(ret), "(1 + 2)");
}
TEST(Function, ReturnMultiValue) {
PackedFunc::body_t body = [](Args args, RetValue* ret) {
int a = args[0];
int b = args[1];
int c = a + b;
int d = a - b;
*ret = cinn::common::CINNValuePack{
{cinn::common::CINNValue(c), cinn::common::CINNValue(d)}};
};
PackedFunc func(body);
cinn::common::CINNValuePack ret = func(1, 2);
int c = ret[0];
int d = ret[1];
EXPECT_EQ(c, 3);
EXPECT_EQ(d, -1);
}
} // namespace lang
} // namespace cinn
+3
View File
@@ -0,0 +1,3 @@
cinn_cc_test(test_cast_simplify SRCS cast_simplify_test.cc DEPS cinncore)
cinn_cc_test(test_replace_cross_thread_reduction SRCS
replace_cross_thread_reduction_test.cc DEPS cinncore)
+62
View File
@@ -0,0 +1,62 @@
// Copyright (c) 2021 CINN 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 <gtest/gtest.h>
#include "paddle/cinn/ir/ir_printer.h"
#include "paddle/cinn/ir/op/ir_operators.h"
#include "paddle/cinn/optim/ir_simplify.h"
#include "paddle/cinn/utils/string.h"
namespace cinn::optim {
TEST(CastSimplify, same_type) {
Var n("n");
Expr a = ir::Cast::Make(Int(32), n);
LOG(INFO) << n->type();
LOG(INFO) << a;
SimplifyCast(&a);
ASSERT_EQ(utils::GetStreamCnt(a), "n");
}
TEST(CastSimplify, Imm_int) {
Expr a = ir::Cast::Make(Int(64), Expr(1));
Expr c = ir::Cast::Make(Int(32), a);
LOG(INFO) << c;
SimplifyCast(&c);
LOG(INFO) << c;
ASSERT_EQ(utils::GetStreamCnt(c), "1");
ASSERT_EQ(c.type(), Int(32));
}
TEST(CastSimplify, Imm_double) {
Expr a = ir::Cast::Make(Float(64), Expr(2.33));
Expr c = ir::Cast::Make(Int(32), a);
LOG(INFO) << c;
SimplifyCast(&c);
LOG(INFO) << c;
ASSERT_EQ(utils::GetStreamCnt(c), "2");
ASSERT_EQ(c.type(), Int(32));
}
TEST(CastSimplify, Imm_uint) {
Expr a = ir::Cast::Make(UInt(64), Expr(1));
Expr c = ir::Cast::Make(UInt(32), a);
LOG(INFO) << c;
SimplifyCast(&c);
LOG(INFO) << c;
ASSERT_EQ(utils::GetStreamCnt(c), "1");
ASSERT_EQ(c.type(), UInt(32));
}
} // namespace cinn::optim
@@ -0,0 +1,102 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/optim/replace_cross_thread_reduction.h"
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include "paddle/cinn/cinn.h"
#include "paddle/cinn/ir/ir.h"
#include "paddle/cinn/ir/ir_printer.h"
#include "paddle/cinn/ir/op/ir_operators.h"
#include "paddle/cinn/ir/schedule/ir_schedule.h"
#include "paddle/cinn/ir/utils/stmt_converter.h"
#include "paddle/cinn/utils/string.h"
namespace cinn {
namespace optim {
TEST(CrossThreadReductionReplacer, basic) {
#ifdef CINN_WITH_CUDA
Context::Global().ResetNameId();
Placeholder<float> A("A", {Expr(64), Expr(128)});
Target target = cinn::common::DefaultNVGPUTarget();
Module::Builder builder("reduce_sum", target);
Var reduce_j(128, "reduce_j");
ir::Tensor B = Compute(
{Expr(64)},
[&](Var i) { return lang::ReduceSum(A(i, reduce_j), {reduce_j}); },
"B");
ast_gen_ius::TensorGroup tensor_group({A, B});
auto func = lang::LowerToAst("reduce_sum", {A, B}, &tensor_group);
VLOG(6) << "original func\n" << func;
ir::Expr expr_func_body = ir::ConvertStmtBlockToExprBlock(func->body_block);
ir::ModuleExpr mod_expr({expr_func_body});
ir::IRSchedule ir_sch(mod_expr);
ir_sch.Bind(ir_sch.GetLoops("B")[0], "blockIdx.x");
ir_sch.Bind(ir_sch.GetLoops("B")[1], "threadIdx.x");
ir::Expr block = ir_sch.GetBlock("B");
block.As<ir::ScheduleBlockRealize>()
->schedule_block.As<ir::ScheduleBlock>()
->reduce_method = ir::BlockReduceMethod();
ir::Expr func_body = ir_sch.GetModule().GetExprs()[0];
std::vector<ir::Argument> args{
ir::Argument(ir::Var("A"), ir::Argument::IO::kInput),
ir::Argument(ir::Var("B"), ir::Argument::IO::kOutput)};
auto new_func = ir::_LoweredFunc_::Make("test_func", args, func_body, {});
VLOG(6) << "After Bind: " << new_func->body;
ReplaceCrossThreadReduction(new_func);
VLOG(6) << "After ReplaceCrossThreadReduction: " << new_func->body;
EXPECT_EQ(utils::GetStreamCnt(new_func->body), utils::Trim(R"ROC({
ScheduleBlock(root)
{
{
thread_bind[blockIdx.x] for (i, 0, 64)
{
ScheduleBlock(B__reduce_init)
{
i0 = axis.bind(i)
{
B__reduce_init[i0] = 0.00000000f
}
}
thread_bind[threadIdx.x] for (reduce_j, 0, 128)
{
ScheduleBlock(B)
{
i0_0, i1 = axis.bind(i, reduce_j)
{
B[i0_0] = cinn_block_reduce_sum_fp32(A[i0_0, i1], _Buffer_<cinn_buffer_t*: 32>(shm32__fp32_reduce), false)
}
}
}
}
}
}
}
)ROC"));
#endif
}
} // namespace optim
} // namespace cinn
+2
View File
@@ -0,0 +1,2 @@
cinn_cc_test(test_compute_at_transform SRCS compute_at_transform_test.cc DEPS
cinncore)
@@ -0,0 +1,58 @@
// Copyright (c) 2021 CINN 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 <gtest/gtest.h>
namespace cinn {
namespace poly {
TEST(ComputeAtTransform2, basic) {
isl::ctx ctx(isl_ctx_alloc());
isl::set pdomain(ctx, "{ p[i,j]: 0<=i,j<100 }");
isl::map ptransform(ctx,
"{ p[i,j]->p[t0,t1,t2]: t0=i%4 and t1=i/4 and t2=j }");
isl::set cdomain(ctx, "{ c[i,j,k]: 0<=i,j,k<50 }");
isl::map ctransform(
ctx, "{ c[i,j,k]->c[t0,t1,t2,t3]: t0=i/4 and t1=i%4 and t2=j and t3=k }");
isl::map access(
ctx, "{ c[i,j,k]->p[i,j]; c[i,j,k]->p[i+1,j]; c[i,j,k]->p[i-1,j] }");
poly::ComputeAtTransform t(
pdomain, cdomain, access, ptransform, ctransform, 1);
t();
t.DisplayC();
isl::map pschedule(ctx,
"{ p[i0,i1,i2,i3,i4] -> [t0,t1,t1t, t2,t3,t4,t5]: t0=i0 "
"and t1=i1 and t2=i2 and t3=i3 and t4=i4 "
"and t5=0 and t1t=0 }");
isl::map cschedule(
ctx,
"[_c_0,_c_1] -> { c[i0,i1,i2,i3] -> [t0,t1,t1t,t2,t3,t4,t5]: t0=i0 and "
"t1=i1 and t2=i2 and t3=i3 "
"and t4=0 and t5=0 and t1t=1 }");
t.DisplayC(pschedule.release(), cschedule.release());
LOG(INFO) << "shape:";
auto shape = t.GetProducerAdjustedShape();
for (int i = 0; i < shape.size(); i++) {
LOG(INFO) << shape[i];
}
}
} // namespace poly
} // namespace cinn
+2
View File
@@ -0,0 +1,2 @@
cinn_cc_test(test_cinn_runtime SRCS cinn_runtime_test.cc DEPS cinn_runtime)
add_subdirectory(cuda)
@@ -0,0 +1,50 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/runtime/cinn_runtime.h"
#include <gtest/gtest.h>
TEST(buffer, basic) {
auto* buffer =
cinn_buffer_t::new_(cinn_x86_device, cinn_float32_t(), {3, 10});
ASSERT_TRUE(buffer);
ASSERT_TRUE(buffer->device_interface);
ASSERT_EQ(buffer->device_interface, cinn_x86_device_interface());
buffer->device_interface->impl->malloc(NULL, buffer);
auto* data = reinterpret_cast<float*>(buffer->memory);
data[0] = 0.f;
data[1] = 1.f;
EXPECT_EQ(data[0], 0.f);
EXPECT_EQ(data[1], 1.f);
}
TEST(cinn_print_debug_string, basic) {
cinn_print_debug_string("hello world");
cinn_print_debug_string("should be 1, %d", 1);
int a = 1;
cinn_print_debug_string("should be pointer, %p", &a);
cinn_print_debug_string("should be 1, %d", a);
cinn_print_debug_string("v3[%d %d %d], ", 1, 2, 3);
}
TEST(cinn_args_construct, basic) {
cinn_pod_value_t arr[4];
cinn_pod_value_t a0(0);
cinn_pod_value_t a1(1);
cinn_pod_value_t a2(2);
cinn_pod_value_t a3(3);
cinn_args_construct(arr, 4, &a0, &a1, &a2, &a3);
for (int i = 0; i < 4; i++) ASSERT_EQ((int)arr[i], i);
}
@@ -0,0 +1,5 @@
if(NOT WITH_CUDA)
return()
endif()
cinn_nv_test(test_cuda_module SRCS cuda_module_test.cc DEPS cinncore)
@@ -0,0 +1,205 @@
// Copyright (c) 2021 CINN 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 "paddle/cinn/runtime/cuda/cuda_module.h"
#include <gtest/gtest.h>
#include <random>
#include "paddle/cinn/backends/nvrtc/nvrtc_util.h"
#include "paddle/cinn/cinn.h"
#include "paddle/cinn/runtime/cuda/cuda_util.h"
#include "paddle/cinn/runtime/cuda/test_util.h"
#include "paddle/cinn/runtime/cuda/use_extern_funcs.h"
#include "paddle/common/enforce.h"
namespace cinn {
namespace runtime {
namespace cuda {
TEST(CUDAModule, basic) {
backends::nvrtc::Compiler compiler;
std::string source_code = R"ROC(
extern "C" __global__
void saxpy(float a, float *x, float *y, float *out, size_t n)
{
size_t tid = blockIdx.x * blockDim.x + threadIdx.x;
if (tid < n) {
out[tid] = a * x[tid] + y[tid];
}
}
)ROC";
auto ptx = compiler(source_code);
PADDLE_ENFORCE_NE(
ptx.empty(), true, ::common::errors::NotFound("ptx is empty!"));
CUDAModule module(ptx, CUDAModule::Kind::PTX);
auto func = module.GetFunction(0, "saxpy");
ASSERT_TRUE(func);
}
TEST(CUDAModule, float16) {
using cinn::common::float16;
using runtime::cuda::util::Vector;
auto generate_ptx = [] {
backends::nvrtc::Compiler compiler;
std::string source_code = R"(
#include <cstdint>
#define CINN_WITH_CUDA
#include "float16.h"
using cinn::common::float16;
extern "C" __global__
void cast_fp32_to_fp16_cuda_kernel(const float* input, const int num, float16* output) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
output[idx] = float16(input[idx]);
}
}
)";
auto ptx = compiler(source_code);
PADDLE_ENFORCE_NE(
ptx.empty(), true, ::common::errors::NotFound("ptx is empty!"));
return ptx;
};
auto ptx = generate_ptx();
CUDAModule cuda_module(ptx, CUDAModule::Kind::PTX);
auto func = cuda_module.GetFunction(0, "cast_fp32_to_fp16_cuda_kernel");
ASSERT_TRUE(func);
int size = 100;
dim3 blocks_per_grid(1);
dim3 threads_per_block(100);
std::vector<float> x_host(size);
{
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<float> dis(1e-5f, 1.0f);
for (size_t i = 0; i < x_host.size(); ++i) {
x_host[i] = dis(eng);
}
}
Vector<float> x_device(x_host);
Vector<float16> y_device(size);
auto* x_p{x_device.data()};
auto* y_p{y_device.data()};
void* args[] = {&x_p, &size, &y_p};
cuda_module.LaunchKernel(0,
"cast_fp32_to_fp16_cuda_kernel",
blocks_per_grid,
threads_per_block,
args);
CUDA_CALL(cudaDeviceSynchronize());
std::vector<float16> y_host = y_device.to_host();
bool res = std::equal(x_host.begin(),
x_host.end(),
y_host.begin(),
[](float x, float16 y) -> bool {
return std::abs(x - static_cast<float>(y)) < 1e-2f;
});
PADDLE_ENFORCE_EQ(
res,
true,
::common::errors::PreconditionNotMet(
"The difference between two arrays exceeds the bound."));
}
TEST(CUDAModule, bfloat16) {
using cinn::common::bfloat16;
using runtime::cuda::util::Vector;
auto generate_ptx = [] {
backends::nvrtc::Compiler compiler;
std::string source_code = R"(
#include <cstdint>
#define CINN_WITH_CUDA
#include "bfloat16.h"
using cinn::common::bfloat16;
extern "C" __global__
void cast_fp32_to_bf16_cuda_kernel(const float* input, const int num, bfloat16* output) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx < num) {
output[idx] = bfloat16(input[idx]);
}
}
)";
auto ptx = compiler(source_code);
PADDLE_ENFORCE_NE(
ptx.empty(), true, ::common::errors::NotFound("ptx is empty!"));
return ptx;
};
auto ptx = generate_ptx();
CUDAModule cuda_module(ptx, CUDAModule::Kind::PTX);
auto func = cuda_module.GetFunction(0, "cast_fp32_to_bf16_cuda_kernel");
ASSERT_TRUE(func);
int size = 100;
dim3 blocks_per_grid(1);
dim3 threads_per_block(100);
std::vector<float> x_host(size);
{
std::random_device r;
std::default_random_engine eng(r());
std::uniform_real_distribution<float> dis(1e-5f, 1.0f);
for (size_t i = 0; i < x_host.size(); ++i) {
x_host[i] = dis(eng);
}
}
Vector<float> x_device(x_host);
Vector<bfloat16> y_device(size);
auto* x_p{x_device.data()};
auto* y_p{y_device.data()};
void* args[] = {&x_p, &size, &y_p};
cuda_module.LaunchKernel(0,
"cast_fp32_to_bf16_cuda_kernel",
blocks_per_grid,
threads_per_block,
args);
CUDA_CALL(cudaDeviceSynchronize());
std::vector<bfloat16> y_host = y_device.to_host();
bool res = std::equal(x_host.begin(),
x_host.end(),
y_host.begin(),
[](float x, bfloat16 y) -> bool {
return std::abs(x - static_cast<float>(y)) < 1e-2f;
});
PADDLE_ENFORCE_EQ(
res,
true,
::common::errors::PreconditionNotMet(
"The difference between two arrays exceeds the bound."));
}
} // namespace cuda
} // namespace runtime
} // namespace cinn
+2
View File
@@ -0,0 +1,2 @@
cinn_cc_test(test_sized_multi_set SRCS sized_multi_set_test.cc DEPS cinncore)
cinn_cc_test(test_multi_threading SRCS multi_threading_test.cc DEPS cinncore)
@@ -0,0 +1,64 @@
// Copyright (c) 2022 CINN 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 "paddle/cinn/utils/multi_threading.h"
#include <glog/logging.h>
#include <gtest/gtest.h>
#include <memory>
#include <vector>
#include "paddle/common/enforce.h"
namespace cinn {
namespace utils {
TEST(JobDispatcher, SequenceDispatcher) {
std::unique_ptr<JobDispatcher> dispatcher =
std::make_unique<SequenceDispatcher>(1, 3);
ASSERT_EQ(1, dispatcher->Next());
ASSERT_EQ(2, dispatcher->Next());
// check reach the end
ASSERT_EQ(-1, dispatcher->Next());
}
TEST(parallel_run, Basic) {
std::vector<int> results(100, -1);
auto worker_fn = [&results](int index) {
PADDLE_ENFORCE_LT(index,
results.size(),
::common::errors::InvalidArgument("invalid index!"));
results[index] = index;
};
// check process every index in the extent of [0, 100) with step 1
parallel_run(worker_fn, SequenceDispatcher(0, 100), 2);
for (int i = 0; i < 100; ++i) {
ASSERT_EQ(results[i], i);
}
// check only indexes in the extent of [0, 100) with step 3 are processed
results.assign(100, -1);
parallel_run(worker_fn, SequenceDispatcher(0, 100, 3), 3);
for (int i = 0; i < 100; ++i) {
if (i % 3 == 0) {
ASSERT_EQ(results[i], i);
} else {
ASSERT_EQ(results[i], -1);
}
}
}
} // namespace utils
} // namespace cinn
@@ -0,0 +1,82 @@
// Copyright (c) 2022 CINN 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 "paddle/cinn/utils/sized_multi_set.h"
#include <gtest/gtest.h>
#include <vector>
namespace cinn {
namespace utils {
TEST(SizedMultiSet, PopMax) {
SizedMultiSet<int> sized_multi_set(5);
for (int i = 0; i < 10; ++i) {
sized_multi_set.Push(i);
if (i < 5) {
EXPECT_EQ(sized_multi_set.Size(), static_cast<size_t>(i + 1));
EXPECT_EQ(sized_multi_set.MaxValue(), i);
EXPECT_EQ(sized_multi_set.MinValue(), 0);
} else {
EXPECT_EQ(sized_multi_set.Size(), 5);
EXPECT_EQ(sized_multi_set.MaxValue(), 4);
EXPECT_EQ(sized_multi_set.MinValue(), 0);
}
}
std::vector<int> vec = sized_multi_set.ReturnAsContainer<std::vector<int>>();
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(vec[i], i);
}
for (int i = 0; i < 4; ++i) {
sized_multi_set.Pop();
EXPECT_EQ(sized_multi_set.Size(), static_cast<size_t>(4 - i));
EXPECT_EQ(sized_multi_set.MaxValue(), static_cast<size_t>(3 - i));
EXPECT_EQ(sized_multi_set.MinValue(), static_cast<size_t>(0));
}
}
TEST(SizedMultiSet, PopMin) {
SizedMultiSet<int> sized_multi_set(5, /* pop_max_when_full = */ false);
for (int i = 0; i < 10; ++i) {
sized_multi_set.Push(i);
if (i < 5) {
EXPECT_EQ(sized_multi_set.Size(), static_cast<size_t>(i + 1));
EXPECT_EQ(sized_multi_set.MaxValue(), i);
EXPECT_EQ(sized_multi_set.MinValue(), 0);
} else {
EXPECT_EQ(sized_multi_set.Size(), 5);
EXPECT_EQ(sized_multi_set.MaxValue(), i);
EXPECT_EQ(sized_multi_set.MinValue(), i - 4);
}
}
std::vector<int> vec = sized_multi_set.ReturnAsContainer<std::vector<int>>();
for (int i = 0; i < 5; ++i) {
EXPECT_EQ(vec[i], i + 5);
}
for (int i = 0; i < 4; ++i) {
sized_multi_set.Pop();
EXPECT_EQ(sized_multi_set.Size(), static_cast<size_t>(4 - i));
EXPECT_EQ(sized_multi_set.MaxValue(), static_cast<size_t>(9));
EXPECT_EQ(sized_multi_set.MinValue(), static_cast<size_t>(6 + i));
}
}
} // namespace utils
} // namespace cinn