chore: import upstream snapshot with attribution
This commit is contained in:
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
add_subdirectory(pe)
|
||||
@@ -0,0 +1 @@
|
||||
cinn_cc_test(test_load_params SRCS load_params_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/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
|
||||
@@ -0,0 +1 @@
|
||||
add_subdirectory(test)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user