777 lines
32 KiB
C++
777 lines
32 KiB
C++
// 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 <glog/logging.h>
|
|
#include <gtest/gtest.h>
|
|
#include <sys/stat.h>
|
|
#include <memory>
|
|
#include <sstream>
|
|
|
|
#include <fstream>
|
|
#include "paddle/cinn/hlir/dialect/operator/ir/op_dialect.h"
|
|
#include "paddle/cinn/ir/group_schedule/config/database.h"
|
|
#include "paddle/cinn/ir/group_schedule/config/file_database.h"
|
|
#include "paddle/cinn/ir/group_schedule/config/group_tile_config.h"
|
|
#include "paddle/cinn/ir/group_schedule/config/schedule_config_manager.h"
|
|
#include "paddle/cinn/ir/group_schedule/search/config_searcher.h"
|
|
#include "paddle/cinn/ir/group_schedule/search/measurer.h"
|
|
#include "paddle/cinn/utils/string.h"
|
|
#include "paddle/common/performance_statistician.h"
|
|
#include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h"
|
|
#include "paddle/fluid/pir/dialect/operator/ir/pd_api.h"
|
|
#include "paddle/fluid/pir/dialect/operator/ir/pd_op.h"
|
|
#include "paddle/pir/include/core/builtin_type.h"
|
|
#include "paddle/pir/include/core/ir_context.h"
|
|
#include "paddle/pir/include/core/program.h"
|
|
|
|
PD_DECLARE_string(tile_config_policy);
|
|
PD_DECLARE_string(cinn_tile_config_filename_label);
|
|
COMMON_DECLARE_bool(print_ir);
|
|
PD_DECLARE_bool(cinn_measure_kernel_time);
|
|
PHI_DECLARE_bool(enable_cinn_compile_cache);
|
|
|
|
#define MKDIR(path) mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)
|
|
struct PerfTestConfig {
|
|
int InnerTestNum;
|
|
int OuterTestNum;
|
|
int MaxTestNum;
|
|
float EarlyStopThreshold;
|
|
PerfTestConfig()
|
|
: InnerTestNum(1),
|
|
OuterTestNum(3),
|
|
MaxTestNum(3),
|
|
EarlyStopThreshold(1.2) {}
|
|
PerfTestConfig(int inner_num, int outer_num, int max_num, float earlystop)
|
|
: InnerTestNum(inner_num),
|
|
OuterTestNum(outer_num),
|
|
MaxTestNum(max_num),
|
|
EarlyStopThreshold(earlystop) {}
|
|
};
|
|
|
|
std::string GenCSVFilePath(const cinn::common::Target target,
|
|
const cinn::ir::IterSpaceType &iter_space_type) {
|
|
std::string dirname = "";
|
|
std::string filename = "";
|
|
for (auto i : iter_space_type) {
|
|
dirname += i.first;
|
|
dirname += "_";
|
|
filename += i.first + i.second;
|
|
filename += "_";
|
|
}
|
|
const std::string kDirSuffix = "_EREBE";
|
|
dirname = dirname.substr(0, dirname.size() - 1) + kDirSuffix;
|
|
filename = filename.substr(0, filename.size() - 1);
|
|
|
|
auto checkexist = [](std::string test_path) {
|
|
bool path_exists = false;
|
|
struct stat statbuf;
|
|
if (stat(test_path.c_str(), &statbuf) != -1) {
|
|
if (S_ISDIR(statbuf.st_mode)) {
|
|
path_exists = true;
|
|
}
|
|
}
|
|
if (!path_exists) {
|
|
PADDLE_ENFORCE_NE(MKDIR(test_path.c_str()),
|
|
-1,
|
|
::common::errors::PreconditionNotMet(
|
|
"Can not create directory: %s, Make sure you "
|
|
"have permission to write",
|
|
test_path));
|
|
}
|
|
};
|
|
std::string root_path = FLAGS_cinn_tile_config_filename_label;
|
|
if (root_path == "") {
|
|
const std::string kTestFileDir = "./tile_file_test/";
|
|
root_path = kTestFileDir;
|
|
}
|
|
std::string target_str = target.arch_str() + "_" + target.device_name_str();
|
|
checkexist(root_path);
|
|
checkexist(root_path + target_str);
|
|
checkexist(root_path + target_str + "/" + dirname);
|
|
VLOG(3) << "Dump_path is " << root_path + dirname + "/" + filename + ".csv";
|
|
return root_path + target_str + "/" + dirname + "/" + filename + ".csv";
|
|
}
|
|
|
|
void WriteBucketInfo(
|
|
std::ofstream &os,
|
|
const std::vector<std::pair<std::string, std::string>> &iter_space_type,
|
|
const cinn::ir::BucketInfo &bucket_info) {
|
|
std::stringstream ss;
|
|
ss << " { ";
|
|
for (int i = 0; i < iter_space_type.size(); ++i) {
|
|
ss << iter_space_type[i].first << "_" << iter_space_type[i].second << ": "
|
|
<< bucket_info.space[i].lower_bound << "-"
|
|
<< bucket_info.space[i].upper_bound << " ";
|
|
}
|
|
ss << "} ";
|
|
os << ss.str() << " \t ";
|
|
}
|
|
|
|
// reduce_sum
|
|
std::shared_ptr<::pir::Program> BuildReduceSumProgram(int spatial_size,
|
|
int reduce_size) {
|
|
::pir::IrContext *ctx = ::pir::IrContext::Instance();
|
|
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
|
|
|
|
auto program = std::make_shared<::pir::Program>(ctx);
|
|
::pir::Builder builder = ::pir::Builder(ctx, program->block());
|
|
|
|
const std::vector<int64_t> shape = {spatial_size, reduce_size};
|
|
auto x = builder
|
|
.Build<paddle::dialect::DataOp>(
|
|
"x", shape, phi::DataType::FLOAT32, phi::GPUPlace())
|
|
.result(0);
|
|
auto out = builder
|
|
.Build<paddle::dialect::SumOp>(
|
|
x, std::vector<int64_t>{-1}, phi::DataType::FLOAT32, true)
|
|
.result(0);
|
|
builder.Build<paddle::dialect::FetchOp>(out, "out", 0);
|
|
return program;
|
|
}
|
|
|
|
// layerNorm
|
|
std::shared_ptr<::pir::Program> BuildLayerNormProgram(int spatial_size,
|
|
int reduce_size) {
|
|
::pir::IrContext *ctx = ::pir::IrContext::Instance();
|
|
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
|
|
|
|
auto program = std::make_shared<::pir::Program>(ctx);
|
|
::pir::Builder builder = ::pir::Builder(ctx, program->block());
|
|
|
|
const std::vector<int64_t> shape = {spatial_size, reduce_size};
|
|
auto x = builder
|
|
.Build<paddle::dialect::DataOp>(
|
|
"x", shape, phi::DataType::FLOAT32, phi::GPUPlace())
|
|
.result(0);
|
|
auto sum_val =
|
|
builder
|
|
.Build<paddle::dialect::SumOp>(
|
|
x, std::vector<int64_t>{-1}, phi::DataType::FLOAT32, true)
|
|
.result(0);
|
|
|
|
auto divide_num =
|
|
builder
|
|
.Build<paddle::dialect::FullOp>(
|
|
std::vector<int64_t>({1}), 1024, phi::DataType::FLOAT32)
|
|
.out();
|
|
auto mean_val =
|
|
builder.Build<paddle::dialect::DivideOp>(sum_val, divide_num).result(0);
|
|
auto sub_num =
|
|
builder.Build<paddle::dialect::SubtractOp>(x, mean_val).result(0);
|
|
auto pow_val = builder.Build<paddle::dialect::PowOp>(x, 2.0).result(0);
|
|
auto pow_sum =
|
|
builder
|
|
.Build<paddle::dialect::SumOp>(
|
|
pow_val, std::vector<int64_t>{-1}, phi::DataType::FLOAT32, true)
|
|
.result(0);
|
|
auto variance_val =
|
|
builder.Build<paddle::dialect::DivideOp>(pow_sum, divide_num).result(0);
|
|
auto add_num =
|
|
builder
|
|
.Build<paddle::dialect::FullOp>(
|
|
std::vector<int64_t>({1}), 1e-6, phi::DataType::FLOAT32)
|
|
.out();
|
|
auto add_val =
|
|
builder.Build<paddle::dialect::AddOp>(variance_val, add_num).result(0);
|
|
auto rsqrt_val = builder.Build<paddle::dialect::RsqrtOp>(add_val).result(0);
|
|
auto out =
|
|
builder.Build<paddle::dialect::MultiplyOp>(rsqrt_val, sub_num).result(0);
|
|
|
|
builder.Build<paddle::dialect::FetchOp>(out, "out", 0);
|
|
return program;
|
|
}
|
|
|
|
// softmax
|
|
std::shared_ptr<::pir::Program> BuildSoftmaxProgram(int spatial_size,
|
|
int reduce_size) {
|
|
::pir::IrContext *ctx = ::pir::IrContext::Instance();
|
|
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
|
|
|
|
auto program = std::make_shared<::pir::Program>(ctx);
|
|
::pir::Builder builder = ::pir::Builder(ctx, program->block());
|
|
|
|
const std::vector<int64_t> shape = {spatial_size, reduce_size};
|
|
auto x = builder
|
|
.Build<paddle::dialect::DataOp>(
|
|
"x", shape, phi::DataType::FLOAT32, phi::GPUPlace())
|
|
.result(0);
|
|
auto max_num =
|
|
builder.Build<paddle::dialect::MaxOp>(x, std::vector<int64_t>{-1}, true)
|
|
.result(0);
|
|
auto sub_num =
|
|
builder.Build<paddle::dialect::SubtractOp>(x, max_num).result(0);
|
|
auto exp_num = builder.Build<paddle::dialect::ExpOp>(sub_num).result(0);
|
|
auto exp_sum =
|
|
builder
|
|
.Build<paddle::dialect::SumOp>(
|
|
exp_num, std::vector<int64_t>{-1}, phi::DataType::FLOAT32, true)
|
|
.result(0);
|
|
auto out =
|
|
builder.Build<paddle::dialect::DivideOp>(exp_num, exp_sum).result(0);
|
|
builder.Build<paddle::dialect::FetchOp>(out, "out", 0);
|
|
return program;
|
|
}
|
|
|
|
// RMSNorm
|
|
std::shared_ptr<::pir::Program> BuildRMSNormProgram(int spatial_size,
|
|
int reduce_size) {
|
|
::pir::IrContext *ctx = ::pir::IrContext::Instance();
|
|
ctx->GetOrRegisterDialect<paddle::dialect::OperatorDialect>();
|
|
|
|
auto program = std::make_shared<::pir::Program>(ctx);
|
|
::pir::Builder builder = ::pir::Builder(ctx, program->block());
|
|
|
|
const std::vector<int64_t> shape = {spatial_size, reduce_size};
|
|
auto x = builder
|
|
.Build<paddle::dialect::DataOp>(
|
|
"x", shape, phi::DataType::FLOAT32, phi::GPUPlace())
|
|
.result(0);
|
|
auto pow_val = builder.Build<paddle::dialect::PowOp>(x, 2.0).result(0);
|
|
auto sum_val =
|
|
builder
|
|
.Build<paddle::dialect::SumOp>(
|
|
pow_val, std::vector<int64_t>{-1}, phi::DataType::FLOAT32, true)
|
|
.result(0);
|
|
auto divide_num =
|
|
builder
|
|
.Build<paddle::dialect::FullOp>(
|
|
std::vector<int64_t>({1}), reduce_size, phi::DataType::FLOAT32)
|
|
.out();
|
|
auto div_val =
|
|
builder.Build<paddle::dialect::DivideOp>(sum_val, divide_num).result(0);
|
|
auto add_num =
|
|
builder
|
|
.Build<paddle::dialect::FullOp>(
|
|
std::vector<int64_t>({1}), 1e-6, phi::DataType::FLOAT32)
|
|
.out();
|
|
auto add_val =
|
|
builder.Build<paddle::dialect::AddOp>(div_val, add_num).result(0);
|
|
auto rsqrt_val = builder.Build<paddle::dialect::RsqrtOp>(add_val).result(0);
|
|
auto out = builder.Build<paddle::dialect::MultiplyOp>(rsqrt_val, x).result(0);
|
|
|
|
builder.Build<paddle::dialect::FetchOp>(out, "out", 0);
|
|
return program;
|
|
}
|
|
|
|
// Build test program for spatial reduce.
|
|
std::shared_ptr<::pir::Program> BuildSpatialReduceProgram(int spatial_size,
|
|
int reduce_size) {
|
|
std::shared_ptr<::pir::Program> program;
|
|
program = BuildSoftmaxProgram(spatial_size, reduce_size);
|
|
return program;
|
|
}
|
|
|
|
// Get the tile size configuration for the given dimension lower bound
|
|
// dynamically.
|
|
int get_tile_size_config_in_small_area(int dimension_lower) {
|
|
if (dimension_lower <= 2) {
|
|
return 126;
|
|
} else if (dimension_lower <= 128) {
|
|
return 384;
|
|
} else if (dimension_lower <= 512) {
|
|
return 512;
|
|
} else if (dimension_lower <= 1024) {
|
|
return 1024;
|
|
} else if (dimension_lower <= 2048) {
|
|
return 2048;
|
|
} else {
|
|
PADDLE_THROW(phi::errors::InvalidArgument(
|
|
"dimension_lower (%d) exceeds the supported range (<=2048).",
|
|
dimension_lower));
|
|
}
|
|
}
|
|
|
|
int get_tile_size_config_in_large_area(int dimension_lower) {
|
|
if (dimension_lower <= 2) {
|
|
return 510;
|
|
} else if (dimension_lower <= 512) {
|
|
return 512;
|
|
} else if (dimension_lower <= 4096) {
|
|
return 4096;
|
|
} else if (dimension_lower <= 8192) {
|
|
return 8192;
|
|
} else if (dimension_lower <= 16384) {
|
|
return 16384;
|
|
} else {
|
|
PADDLE_THROW(phi::errors::InvalidArgument(
|
|
"dimension_lower (%d) exceeds the supported range (<=16384).",
|
|
dimension_lower));
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<::pir::Program> BuildProgram(bool is_spatial_dynamic,
|
|
bool is_reduce_dynamic,
|
|
int s_dimension_lower,
|
|
int r_dimension_lower) {
|
|
std::shared_ptr<::pir::Program> program;
|
|
if (!is_spatial_dynamic && !is_reduce_dynamic) {
|
|
program = BuildSpatialReduceProgram(s_dimension_lower, r_dimension_lower);
|
|
} else if (is_spatial_dynamic && !is_reduce_dynamic) {
|
|
program = BuildSpatialReduceProgram(-1, r_dimension_lower);
|
|
} else if (!is_spatial_dynamic && is_reduce_dynamic) {
|
|
program = BuildSpatialReduceProgram(s_dimension_lower, -1);
|
|
} else {
|
|
program = BuildSpatialReduceProgram(-1, -1);
|
|
}
|
|
return program;
|
|
}
|
|
|
|
cinn::ir::BucketInfo CreateBucket(int s_dimension_lower,
|
|
int spatial_tile_width,
|
|
int r_dimension_lower,
|
|
int reduce_tile_width,
|
|
bool is_spatial_dynamic,
|
|
bool is_reduce_dynamic) {
|
|
cinn::ir::BucketInfo bucket_info;
|
|
bucket_info.space.push_back(cinn::ir::BucketInfo::Dimension{
|
|
s_dimension_lower,
|
|
s_dimension_lower + spatial_tile_width - 1,
|
|
"S",
|
|
/* is_dynamic = */ is_spatial_dynamic});
|
|
bucket_info.space.push_back(
|
|
cinn::ir::BucketInfo::Dimension{r_dimension_lower,
|
|
r_dimension_lower + reduce_tile_width - 1,
|
|
"R",
|
|
/* is_dynamic = */ is_reduce_dynamic});
|
|
return bucket_info;
|
|
}
|
|
|
|
cinn::ir::search::CandidateType GetCandidate(
|
|
const cinn::ir::TileConfigMap &best_tile_config_map,
|
|
int s_dimension_lower,
|
|
int spatial_tile_width,
|
|
int r_dimension_lower,
|
|
int reduce_tile_width) {
|
|
cinn::ir::search::CandidateType best_candidate;
|
|
for (auto &it : best_tile_config_map) {
|
|
auto s_flag = false, r_flag = false;
|
|
auto dims = it.first.space.size();
|
|
// SR type support only
|
|
if (dims == 2) {
|
|
if (it.first.space[0].lower_bound <= s_dimension_lower &&
|
|
it.first.space[0].upper_bound >=
|
|
s_dimension_lower + spatial_tile_width - 1) {
|
|
s_flag = true;
|
|
} else if (it.first.space[0].lower_bound == 4096 &&
|
|
s_dimension_lower == 4096) {
|
|
s_flag = true;
|
|
}
|
|
if (it.first.space[1].lower_bound <= r_dimension_lower &&
|
|
it.first.space[1].upper_bound >=
|
|
r_dimension_lower + reduce_tile_width - 1) {
|
|
r_flag = true;
|
|
} else if (it.first.space[1].lower_bound == 4096 &&
|
|
r_dimension_lower == 4096) {
|
|
r_flag = true;
|
|
}
|
|
} else {
|
|
PADDLE_THROW(::common::errors::Unavailable("Now just support SR type."));
|
|
}
|
|
if (s_flag == true && r_flag == true) {
|
|
best_candidate = {it.second.warp_num,
|
|
it.second.tree_reduce_num,
|
|
it.second.spatial_inner_num};
|
|
break;
|
|
}
|
|
}
|
|
if (best_candidate.empty()) {
|
|
PADDLE_THROW(
|
|
::common::errors::Unavailable("Not found the best candidate."));
|
|
}
|
|
return best_candidate;
|
|
}
|
|
|
|
void TestWindowPerformance(
|
|
std::ofstream &os,
|
|
const PerfTestConfig &perf_test_config,
|
|
const int graph_num,
|
|
const int s_dimension_lower,
|
|
const int spatial_tile_width,
|
|
const int r_dimension_lower,
|
|
const int reduce_tile_width,
|
|
const int is_spatial_dynamic,
|
|
const int is_reduce_dynamic,
|
|
const double s_weight,
|
|
const double r_weight,
|
|
const double sampling_prob,
|
|
const int kMaxSamplingTimes,
|
|
const int kRepeats,
|
|
const cinn::ir::TileConfigMap &best_tile_config_map,
|
|
const std::vector<std::pair<std::string, std::string>> &iter_space_type) {
|
|
std::vector<double> s_weights =
|
|
std::vector<double>(spatial_tile_width, s_weight);
|
|
std::vector<double> r_weights =
|
|
std::vector<double>(reduce_tile_width, r_weight);
|
|
|
|
LOG(INFO) << "spatial tile dimension lower bound = " << s_dimension_lower
|
|
<< ", reduce tile dimension lower bound = " << r_dimension_lower
|
|
<< std::endl;
|
|
|
|
// Construct pir::Program.
|
|
std::shared_ptr<::pir::Program> program;
|
|
program = BuildProgram(is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
s_dimension_lower,
|
|
r_dimension_lower);
|
|
|
|
// Construct iter space and objective function.
|
|
cinn::ir::BucketInfo bucket_info = CreateBucket(s_dimension_lower,
|
|
spatial_tile_width,
|
|
r_dimension_lower,
|
|
reduce_tile_width,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic);
|
|
std::unique_ptr<cinn::ir::search::BaseObjectiveFunc> obj_func =
|
|
std::make_unique<cinn::ir::search::WeightedSamplingTrailObjectiveFunc>(
|
|
program.get(),
|
|
bucket_info,
|
|
sampling_prob,
|
|
kMaxSamplingTimes,
|
|
kRepeats,
|
|
std::vector<std::vector<double>>{s_weights, r_weights});
|
|
cinn::ir::search::CandidateType best_candidate =
|
|
GetCandidate(best_tile_config_map,
|
|
s_dimension_lower,
|
|
spatial_tile_width,
|
|
r_dimension_lower,
|
|
reduce_tile_width);
|
|
|
|
// Write current bucket info to csv file.
|
|
WriteBucketInfo(os, iter_space_type, bucket_info);
|
|
|
|
int InnerTestNum = perf_test_config.InnerTestNum;
|
|
int OuterTestNum = perf_test_config.OuterTestNum;
|
|
int MaxTestNum = perf_test_config.MaxTestNum;
|
|
float EarlyStopThreshold = perf_test_config.EarlyStopThreshold;
|
|
cinn::ir::search::ScoreType record_baseline_score;
|
|
cinn::ir::search::ScoreType record_best_score;
|
|
double record_best_variance = 0;
|
|
// start test loop
|
|
for (int current_test_num = 0; current_test_num < MaxTestNum;
|
|
++current_test_num) {
|
|
std::vector<cinn::ir::search::ScoreType> vec_best;
|
|
std::vector<cinn::ir::search::ScoreType> vec_baseline;
|
|
// start outer measure loop
|
|
for (int i = 0; i < OuterTestNum; ++i) {
|
|
cinn::ir::search::CandidateType default_candidate;
|
|
std::vector<cinn::ir::search::ScoreType> vec_best_score;
|
|
std::vector<cinn::ir::search::ScoreType> vec_baseline_score;
|
|
// start inner measure loop
|
|
for (int i = 0; i < InnerTestNum; i++) {
|
|
FLAGS_tile_config_policy = "default";
|
|
cinn::ir::search::ScoreType temp_baseline_score =
|
|
(*obj_func)(default_candidate);
|
|
FLAGS_tile_config_policy = "search";
|
|
cinn::ir::search::ScoreType temp_best_score =
|
|
(*obj_func)(best_candidate);
|
|
vec_best_score.push_back(temp_best_score);
|
|
vec_baseline_score.push_back(temp_baseline_score);
|
|
}
|
|
float best_total_time =
|
|
std::accumulate(vec_best_score.begin(), vec_best_score.end(), 0.0);
|
|
float baseline_total_time = std::accumulate(
|
|
vec_baseline_score.begin(), vec_baseline_score.end(), 0.0);
|
|
float best_avg_time = best_total_time / InnerTestNum;
|
|
float baseline_avg_time = baseline_total_time / InnerTestNum;
|
|
vec_best.push_back(best_avg_time);
|
|
vec_baseline.push_back(baseline_avg_time);
|
|
}
|
|
cinn::ir::search::ScoreType best_mean =
|
|
std::accumulate(vec_best.begin(), vec_best.end(), 0.0) / OuterTestNum;
|
|
cinn::ir::search::ScoreType baseline_mean =
|
|
std::accumulate(vec_baseline.begin(), vec_baseline.end(), 0.0) /
|
|
OuterTestNum;
|
|
|
|
// Compute variance of OuterTestNum times of outer measure in each test
|
|
double best_variance = 0.0;
|
|
double baseline_variance = 0.0;
|
|
for (int i = 0; i < OuterTestNum; i++) {
|
|
best_variance = best_variance + pow(vec_best[i] - best_mean, 2);
|
|
baseline_variance =
|
|
baseline_variance + pow(vec_baseline[i] - baseline_mean, 2);
|
|
}
|
|
best_variance = pow(best_variance / OuterTestNum, 0.5);
|
|
baseline_variance = pow(baseline_variance / OuterTestNum, 0.5);
|
|
|
|
// Early stop when current best_variance smaller than EarlyStopThreshold
|
|
if ((best_variance < EarlyStopThreshold) &&
|
|
(baseline_variance < EarlyStopThreshold)) {
|
|
record_baseline_score = baseline_mean;
|
|
record_best_score = best_mean;
|
|
record_best_variance = best_variance + baseline_variance;
|
|
break;
|
|
} else {
|
|
if (record_best_variance == 0) {
|
|
record_best_variance = best_variance + baseline_variance;
|
|
record_baseline_score = baseline_mean;
|
|
record_best_score = best_mean;
|
|
} else if ((best_variance + baseline_variance) < record_best_variance) {
|
|
record_best_variance = best_variance + baseline_variance;
|
|
record_baseline_score = baseline_mean;
|
|
record_best_score = best_mean;
|
|
}
|
|
}
|
|
} // end of test_num loop
|
|
cinn::ir::search::ScoreType optim_percentage =
|
|
(1 / (record_best_score)-1 / record_baseline_score) *
|
|
record_baseline_score;
|
|
LOG(INFO) << "Best score: " << record_best_score / graph_num;
|
|
LOG(INFO) << "Baseline score: " << record_baseline_score / graph_num;
|
|
LOG(INFO) << "variance: " << (record_best_variance / 2);
|
|
LOG(INFO) << "optim percentage: " << optim_percentage;
|
|
LOG(INFO) << "Best candidate: " << best_candidate[0] << " "
|
|
<< best_candidate[1] << " " << best_candidate[2];
|
|
// Write measure results to csv file
|
|
os << std::setprecision(3) << " " << record_baseline_score / graph_num
|
|
<< " \t " << record_best_score / graph_num << " \t " << optim_percentage
|
|
<< "\n";
|
|
}
|
|
|
|
void TestPerformanceForTileConfig(int spatial_left_bound,
|
|
int spatial_right_bound,
|
|
int reduce_left_bound,
|
|
int reduce_right_bound,
|
|
bool is_spatial_dynamic,
|
|
bool is_reduce_dynamic,
|
|
bool test_single_large) {
|
|
FLAGS_enable_cinn_compile_cache = false;
|
|
FLAGS_cinn_measure_kernel_time = true;
|
|
// set tile_file path to test path when user use default setting
|
|
std::string root_path = FLAGS_cinn_tile_config_filename_label;
|
|
if (root_path == "") {
|
|
const std::string kTestFileDir = "./tile_file_test/";
|
|
FLAGS_cinn_tile_config_filename_label = kTestFileDir;
|
|
}
|
|
|
|
constexpr int kThreadsPerWarp = 32;
|
|
constexpr int kMaxThreadsPerBlock = 1024;
|
|
|
|
// now each has the same weight
|
|
constexpr double s_w = 0.05;
|
|
constexpr double r_w = 0.05;
|
|
constexpr double sampling_prob = 1.0;
|
|
constexpr int kMaxSamplingTimes = 360;
|
|
constexpr int kRepeats = 5;
|
|
constexpr int kInnerTestNum = 1;
|
|
constexpr int kOuterTestNum = 3;
|
|
constexpr int kMaxTestNum = 1;
|
|
constexpr float kEarlyStopThreshold = 1.2;
|
|
// number of nodes in cudaGraph for test, which is defined in
|
|
// performance_statistician.h as graph_nodes_num_. This parameter is set to
|
|
// make measure results corresponding to one launch for better readability
|
|
constexpr int kGraphNum = 25;
|
|
|
|
// Define the initial grid size for the spatial and reduction dimensions
|
|
int spatial_tile_config = 0, reduce_tile_config = 0;
|
|
int spatial_tile_width = 0, reduce_tile_width = 0;
|
|
// Define weight for each dimension
|
|
double s_weight = (is_spatial_dynamic ? s_w : 1.0);
|
|
double r_weight = (is_reduce_dynamic ? r_w : 1.0);
|
|
|
|
auto s_dimension_type = "S";
|
|
auto r_dimension_type = "R";
|
|
|
|
// Define the performance test configuration.
|
|
PerfTestConfig perf_test_config = {
|
|
kInnerTestNum, kOuterTestNum, kMaxTestNum, kEarlyStopThreshold};
|
|
|
|
// Get best configuration from json by file database.
|
|
std::vector<std::pair<std::string, std::string>> iter_space_type = {
|
|
std::make_pair(s_dimension_type,
|
|
is_spatial_dynamic == true ? "dynamic" : "static"),
|
|
std::make_pair(r_dimension_type,
|
|
is_reduce_dynamic == true ? "dynamic" : "static")};
|
|
cinn::ir::FileTileConfigDatabase file_database;
|
|
cinn::ir::TileConfigMap best_tile_config_map =
|
|
file_database.GetConfigs(cinn::common::DefaultTarget(), iter_space_type);
|
|
|
|
// build csv file
|
|
std::string dump_path =
|
|
GenCSVFilePath(cinn::common::DefaultTarget(), iter_space_type);
|
|
std::ofstream os(dump_path, std::ofstream::app);
|
|
PADDLE_ENFORCE_EQ(os.good(),
|
|
true,
|
|
::common::errors::InvalidArgument(
|
|
"Cannot open the file to write: %s", dump_path));
|
|
// run performance test for each data grid
|
|
for (int s_dimension_lower = spatial_left_bound;
|
|
s_dimension_lower < spatial_right_bound ||
|
|
s_dimension_lower == spatial_right_bound &&
|
|
spatial_left_bound == spatial_right_bound;
|
|
s_dimension_lower += spatial_tile_config) {
|
|
// adjust the tile size for the spatial dimension dymaically
|
|
spatial_tile_config = get_tile_size_config_in_small_area(s_dimension_lower);
|
|
spatial_tile_width = (is_spatial_dynamic ? spatial_tile_config : 1);
|
|
for (int r_dimension_lower = reduce_left_bound;
|
|
r_dimension_lower < reduce_right_bound ||
|
|
r_dimension_lower == reduce_right_bound &&
|
|
reduce_left_bound == reduce_right_bound;
|
|
r_dimension_lower += reduce_tile_config) {
|
|
// adjust the tile size for the reduce dimension dymaically
|
|
reduce_tile_config =
|
|
get_tile_size_config_in_small_area(r_dimension_lower);
|
|
reduce_tile_width = (is_reduce_dynamic ? reduce_tile_config : 1);
|
|
TestWindowPerformance(os,
|
|
perf_test_config,
|
|
kGraphNum,
|
|
s_dimension_lower,
|
|
spatial_tile_width,
|
|
r_dimension_lower,
|
|
reduce_tile_width,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
s_weight,
|
|
r_weight,
|
|
sampling_prob,
|
|
kMaxSamplingTimes,
|
|
kRepeats,
|
|
best_tile_config_map,
|
|
iter_space_type);
|
|
} // end of r_dimension_lower loop
|
|
} // end of s_dimension_lower loop
|
|
if (test_single_large) {
|
|
// (II) Test in the single large areas,
|
|
// i.e., S:[4096-32768]*R:[2-1024], S:[2-1024]*R:[4096-32768]
|
|
for (int s_dimension_lower = 2; s_dimension_lower < 1024;
|
|
s_dimension_lower += spatial_tile_config) {
|
|
// adjust the tile size for the spatial dimension dynamically
|
|
spatial_tile_config =
|
|
get_tile_size_config_in_large_area(s_dimension_lower);
|
|
spatial_tile_width = (is_spatial_dynamic ? spatial_tile_config : 1);
|
|
|
|
for (int r_dimension_lower = 4096; r_dimension_lower < 32768;
|
|
r_dimension_lower += reduce_tile_config) {
|
|
// adjust the tile size for the reduce dimension dymaically
|
|
reduce_tile_config =
|
|
get_tile_size_config_in_large_area(r_dimension_lower);
|
|
reduce_tile_width = (is_reduce_dynamic ? reduce_tile_config : 1);
|
|
|
|
TestWindowPerformance(os,
|
|
perf_test_config,
|
|
kGraphNum,
|
|
s_dimension_lower,
|
|
spatial_tile_width,
|
|
r_dimension_lower,
|
|
reduce_tile_width,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
s_weight,
|
|
r_weight,
|
|
sampling_prob,
|
|
kMaxSamplingTimes,
|
|
kRepeats,
|
|
best_tile_config_map,
|
|
iter_space_type);
|
|
}
|
|
}
|
|
|
|
for (int s_dimension_lower = 4096; s_dimension_lower < 32768;
|
|
s_dimension_lower += spatial_tile_config) {
|
|
// adjust the tile size for the spatial dimension dymaically
|
|
spatial_tile_config =
|
|
get_tile_size_config_in_large_area(s_dimension_lower);
|
|
spatial_tile_width = (is_spatial_dynamic ? spatial_tile_config : 1);
|
|
|
|
for (int r_dimension_lower = 2; r_dimension_lower < 1024;
|
|
r_dimension_lower += reduce_tile_config) {
|
|
// adjust the tile size for the reduce dimension dymaically
|
|
reduce_tile_config =
|
|
get_tile_size_config_in_large_area(r_dimension_lower);
|
|
reduce_tile_width = (is_reduce_dynamic ? reduce_tile_config : 1);
|
|
// Run performance test and write measure results to csv file.
|
|
|
|
TestWindowPerformance(os,
|
|
perf_test_config,
|
|
kGraphNum,
|
|
s_dimension_lower,
|
|
spatial_tile_width,
|
|
r_dimension_lower,
|
|
reduce_tile_width,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
s_weight,
|
|
r_weight,
|
|
sampling_prob,
|
|
kMaxSamplingTimes,
|
|
kRepeats,
|
|
best_tile_config_map,
|
|
iter_space_type);
|
|
}
|
|
}
|
|
}
|
|
os.close();
|
|
}
|
|
|
|
/**
|
|
* @brief Test case for the ConfigSearcher.
|
|
*
|
|
* This test case performs a perormance test for the best configuration derived
|
|
* from the ConfigSearcher. It iterates over different spatial and reduce tile
|
|
* sizes and constructs a pir::Program. The objective function used for the
|
|
* search is a WeightedSamplingTrailObjectiveFunc. The performance results are
|
|
* written into a CSV file, including the default score and the best candidate
|
|
* score.
|
|
*/
|
|
|
|
TEST(ConfigSearcher, TestPerfDynamicDynamic) {
|
|
constexpr int spatial_left_bound = 2; // for full test, set it to 2
|
|
constexpr int spatial_right_bound = 2; // for full test, set it to 4096
|
|
constexpr int reduce_left_bound = 2; // for full test, set it to 2
|
|
constexpr int reduce_right_bound = 2; // for full test, set it to 4096
|
|
constexpr bool is_spatial_dynamic = true;
|
|
constexpr bool is_reduce_dynamic = true;
|
|
bool test_single_large = false; // To test single large area, set it to true
|
|
TestPerformanceForTileConfig(spatial_left_bound,
|
|
spatial_right_bound,
|
|
reduce_left_bound,
|
|
reduce_right_bound,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
test_single_large);
|
|
}
|
|
|
|
TEST(ConfigSearcher, TestPerfStaticDynamic) {
|
|
constexpr int spatial_left_bound = 2; // for full test, set it to 2
|
|
constexpr int spatial_right_bound = 2; // for full test, set it to 4096
|
|
constexpr int reduce_left_bound = 2; // for full test, set it to 2
|
|
constexpr int reduce_right_bound = 2; // for full test, set it to 4096
|
|
constexpr bool is_spatial_dynamic = false;
|
|
constexpr bool is_reduce_dynamic = true;
|
|
bool test_single_large = false; // To test single large area, set it to true
|
|
TestPerformanceForTileConfig(spatial_left_bound,
|
|
spatial_right_bound,
|
|
reduce_left_bound,
|
|
reduce_right_bound,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
test_single_large);
|
|
}
|
|
|
|
TEST(ConfigSearcher, TestPerfDynamicStatic) {
|
|
constexpr int spatial_left_bound = 2; // for full test, set it to 2
|
|
constexpr int spatial_right_bound = 2; // for full test, set it to 4096
|
|
constexpr int reduce_left_bound = 2; // for full test, set it to 2
|
|
constexpr int reduce_right_bound = 2; // for full test, set it to 4096
|
|
constexpr bool is_spatial_dynamic = true;
|
|
constexpr bool is_reduce_dynamic = false;
|
|
bool test_single_large = false; // To test single large area, set it to true
|
|
TestPerformanceForTileConfig(spatial_left_bound,
|
|
spatial_right_bound,
|
|
reduce_left_bound,
|
|
reduce_right_bound,
|
|
is_spatial_dynamic,
|
|
is_reduce_dynamic,
|
|
test_single_large);
|
|
}
|