chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
paddle_test(op_tester SRCS op_tester.cc DEPS common phi)
|
||||
|
||||
if(WITH_ONNXRUNTIME AND WIN32)
|
||||
# Copy onnxruntime for some c++ test in Windows, since the test will
|
||||
# be build only in CI, so suppose the generator in Windows is Ninja.
|
||||
copy_onnx(op_tester)
|
||||
endif()
|
||||
@@ -0,0 +1,552 @@
|
||||
/* Copyright (c) 2016 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 "test/cpp/fluid/benchmark/op_tester.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "paddle/common/flags.h"
|
||||
#include "paddle/fluid/framework/op_info.h"
|
||||
#include "paddle/fluid/framework/op_registry.h"
|
||||
#include "paddle/fluid/framework/variable_helper.h"
|
||||
#include "paddle/fluid/platform/init.h"
|
||||
#include "paddle/phi/core/platform/profiler.h"
|
||||
#include "paddle/phi/core/platform/timer.h"
|
||||
|
||||
// phi
|
||||
#include "paddle/phi/kernels/declarations.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
namespace benchmark {
|
||||
|
||||
PD_DEFINE_string(op_config_list, "", "Path of op config file."); // NOLINT
|
||||
PD_DEFINE_int32(specified_config_id, -1, "Test the specified op config.");
|
||||
|
||||
void OpTester::Init(const std::string &filename) {
|
||||
Init(OpTesterConfig(filename));
|
||||
}
|
||||
|
||||
void OpTester::Init(const OpTesterConfig &config) {
|
||||
config_ = config;
|
||||
|
||||
auto &op_desc_info = framework::OpInfoMap::Instance();
|
||||
// Initialize the OpDesc
|
||||
if (op_desc_info.Has(config_.op_type)) {
|
||||
type_ = config_.op_type;
|
||||
|
||||
CreateOpDesc();
|
||||
CreateInputVarDesc();
|
||||
CreateOutputVarDesc();
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::NotFound(
|
||||
"Operator '%s' is not registered in OpTester.", config_.op_type));
|
||||
}
|
||||
|
||||
if (config_.device_id >= 0) {
|
||||
place_ = ::phi::GPUPlace(config_.device_id);
|
||||
} else {
|
||||
place_ = ::phi::CPUPlace();
|
||||
}
|
||||
|
||||
framework::InitDevices();
|
||||
scope_ = std::make_unique<::paddle::framework::Scope>();
|
||||
|
||||
op_ = framework::OpRegistry::CreateOp(op_desc_);
|
||||
CreateVariables(scope_.get());
|
||||
}
|
||||
|
||||
void OpTester::Run() {
|
||||
if (config_.print_debug_string) {
|
||||
LOG(INFO) << DebugString();
|
||||
}
|
||||
|
||||
// Warm up
|
||||
RunImpl();
|
||||
|
||||
platform::Timer timer;
|
||||
if (config_.profile) {
|
||||
if (phi::is_cpu_place(place_)) {
|
||||
platform::EnableProfiler(platform::ProfilerState::kCPU);
|
||||
} else {
|
||||
#if defined(PADDLE_WITH_CUDA) || defined(PADDLE_WITH_HIP)
|
||||
platform::EnableProfiler(platform::ProfilerState::kAll);
|
||||
platform::SetDeviceId(config_.device_id);
|
||||
#else
|
||||
PADDLE_THROW(common::errors::PermissionDenied(
|
||||
"'GPUPlace' is not supported in CPU only device."));
|
||||
#endif
|
||||
}
|
||||
|
||||
timer.Start();
|
||||
for (int i = config_.repeat; i > 0; --i) {
|
||||
RunImpl();
|
||||
}
|
||||
timer.Pause();
|
||||
platform::DisableProfiler(platform::EventSortingKey::kDefault,
|
||||
"op_tester_profiler");
|
||||
} else {
|
||||
timer.Start();
|
||||
for (int i = config_.repeat; i > 0; --i) {
|
||||
RunImpl();
|
||||
}
|
||||
timer.Pause();
|
||||
}
|
||||
config_.runtime = timer.ElapsedMS() / config_.repeat;
|
||||
LOG(INFO) << "=== Run " << config_.repeat
|
||||
<< " times, latency: " << config_.runtime << " ms ===";
|
||||
}
|
||||
|
||||
void OpTester::RunImpl() {
|
||||
op_->Run(*scope_, place_);
|
||||
phi::DeviceContextPool::Instance().Get(place_)->Wait();
|
||||
scope_->DropKids();
|
||||
}
|
||||
|
||||
std::vector<std::string> OpTester::GetOpProtoInputNames() {
|
||||
std::vector<std::string> input_names;
|
||||
const framework::proto::OpProto &proto =
|
||||
framework::OpInfoMap::Instance().Get(type_).Proto();
|
||||
for (int i = 0; i != proto.inputs_size(); ++i) {
|
||||
const auto &input = proto.inputs(i);
|
||||
input_names.push_back(input.name());
|
||||
}
|
||||
return input_names;
|
||||
}
|
||||
|
||||
std::vector<std::string> OpTester::GetOpProtoOutputNames() {
|
||||
std::vector<std::string> output_names;
|
||||
const framework::proto::OpProto &proto =
|
||||
framework::OpInfoMap::Instance().Get(type_).Proto();
|
||||
for (int i = 0; i != proto.outputs_size(); ++i) {
|
||||
const auto &output = proto.outputs(i);
|
||||
output_names.push_back(output.name());
|
||||
}
|
||||
return output_names;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, framework::proto::AttrType>
|
||||
OpTester::GetOpProtoAttrNames() {
|
||||
std::unordered_map<std::string, framework::proto::AttrType> attr_types;
|
||||
const framework::proto::OpProto &proto =
|
||||
framework::OpInfoMap::Instance().Get(type_).Proto();
|
||||
const std::vector<std::string> skipped_attrs = {
|
||||
framework::OpProtoAndCheckerMaker::OpRoleAttrName(),
|
||||
framework::OpProtoAndCheckerMaker::OpRoleVarAttrName(),
|
||||
framework::OpProtoAndCheckerMaker::OpNamescopeAttrName(),
|
||||
framework::OpProtoAndCheckerMaker::OpCreationCallstackAttrName(),
|
||||
framework::OpProtoAndCheckerMaker::OpWithQuantAttrName()};
|
||||
for (int i = 0; i != proto.attrs_size(); ++i) {
|
||||
const auto &attr = proto.attrs(i);
|
||||
if (!Has(skipped_attrs, attr.name())) {
|
||||
VLOG(4) << "attr: " << attr.name() << ", type: " << attr.type();
|
||||
attr_types[attr.name()] = attr.type();
|
||||
}
|
||||
}
|
||||
return attr_types;
|
||||
}
|
||||
|
||||
framework::proto::VarType::Type OpTester::TransToVarType(std::string str) {
|
||||
if (str == "int32") {
|
||||
return framework::proto::VarType::INT32;
|
||||
} else if (str == "int64") {
|
||||
return framework::proto::VarType::INT64;
|
||||
} else if (str == "fp32") {
|
||||
return framework::proto::VarType::FP32;
|
||||
} else if (str == "fp64") {
|
||||
return framework::proto::VarType::FP64;
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported dtype %s in OpTester.", str.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
void OpTester::CreateInputVarDesc() {
|
||||
std::vector<std::string> input_names = GetOpProtoInputNames();
|
||||
for (auto &name : input_names) {
|
||||
const OpInputConfig *input = config_.GetInput(name);
|
||||
PADDLE_ENFORCE_NOT_NULL(
|
||||
input,
|
||||
common::errors::NotFound(
|
||||
"The input %s of operator %s is not correctly provided.",
|
||||
name,
|
||||
config_.op_type));
|
||||
|
||||
std::string var_name = config_.op_type + "." + name;
|
||||
framework::VarDesc *var = Var(var_name);
|
||||
// Need to support more type
|
||||
var->SetType(framework::proto::VarType::DENSE_TENSOR);
|
||||
var->SetPersistable(false);
|
||||
var->SetDataType(TransToVarType(input->dtype));
|
||||
var->SetShape(input->dims);
|
||||
|
||||
op_desc_.SetInput(name, {var_name});
|
||||
inputs_[var_name] = *input;
|
||||
}
|
||||
}
|
||||
|
||||
void OpTester::CreateOutputVarDesc() {
|
||||
std::vector<std::string> output_names = GetOpProtoOutputNames();
|
||||
for (auto &name : output_names) {
|
||||
std::string var_name = config_.op_type + "." + name;
|
||||
framework::VarDesc *var = Var(var_name);
|
||||
// Need to support more type
|
||||
var->SetType(framework::proto::VarType::DENSE_TENSOR);
|
||||
var->SetPersistable(false);
|
||||
var->SetDataType(framework::proto::VarType::FP32);
|
||||
|
||||
op_desc_.SetOutput(name, {var_name});
|
||||
}
|
||||
}
|
||||
|
||||
void OpTester::CreateOpDesc() {
|
||||
op_desc_.SetType(config_.op_type);
|
||||
std::unordered_map<std::string, framework::proto::AttrType> attr_types =
|
||||
GetOpProtoAttrNames();
|
||||
for (auto item : config_.attrs) {
|
||||
const std::string &name = item.first;
|
||||
PADDLE_ENFORCE_NE(
|
||||
attr_types.find(name),
|
||||
attr_types.end(),
|
||||
common::errors::NotFound(
|
||||
"Operator %s does not have attribute %s.", type_, name));
|
||||
|
||||
const std::string &value_str = item.second;
|
||||
const framework::proto::AttrType &type = attr_types[name];
|
||||
switch (type) {
|
||||
case framework::proto::AttrType::BOOLEAN:
|
||||
break;
|
||||
case framework::proto::AttrType::INT: {
|
||||
int value = StringTo<int>(value_str);
|
||||
op_desc_.SetAttr(name, {value});
|
||||
} break;
|
||||
case framework::proto::AttrType::FLOAT: {
|
||||
float value = StringTo<float>(value_str);
|
||||
op_desc_.SetAttr(name, {value});
|
||||
} break;
|
||||
case framework::proto::AttrType::STRING: {
|
||||
op_desc_.SetAttr(name, {value_str});
|
||||
} break;
|
||||
case framework::proto::AttrType::BOOLEANS:
|
||||
case framework::proto::AttrType::INTS:
|
||||
case framework::proto::AttrType::FLOATS:
|
||||
case framework::proto::AttrType::STRINGS:
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported STRINGS type in OpTester yet."));
|
||||
break;
|
||||
case framework::proto::AttrType::LONG: {
|
||||
int64_t value = StringTo<int64_t>(value_str);
|
||||
op_desc_.SetAttr(name, value);
|
||||
} break;
|
||||
case framework::proto::AttrType::LONGS:
|
||||
default:
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported attr type %d in OpTester.", type));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
framework::VarDesc *OpTester::Var(const std::string &name) {
|
||||
auto it = vars_.find(name);
|
||||
if (it != vars_.end()) {
|
||||
return it->second.get();
|
||||
}
|
||||
auto *var = new framework::VarDesc(name);
|
||||
vars_[name].reset(var);
|
||||
return var;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void OpTester::SetupTensor(phi::DenseTensor *tensor,
|
||||
const std::vector<int64_t> &shape,
|
||||
T lower,
|
||||
T upper,
|
||||
const std::string &initializer,
|
||||
const std::string &filename) {
|
||||
static unsigned int seed = 100;
|
||||
std::mt19937 rng(seed++);
|
||||
std::uniform_real_distribution<double> uniform_dist(0, 1);
|
||||
|
||||
T *ptr = tensor->mutable_data<T>(common::make_ddim(shape), place_);
|
||||
|
||||
phi::DenseTensor cpu_tensor;
|
||||
T *cpu_ptr = nullptr;
|
||||
|
||||
if (!phi::is_cpu_place(place_)) {
|
||||
cpu_ptr =
|
||||
cpu_tensor.mutable_data<T>(common::make_ddim(shape), phi::CPUPlace());
|
||||
} else {
|
||||
cpu_ptr = ptr;
|
||||
}
|
||||
|
||||
if (initializer == "random") {
|
||||
for (int i = 0; i < cpu_tensor.numel(); ++i) {
|
||||
cpu_ptr[i] = static_cast<T>(uniform_dist(rng) * (upper - lower) + lower);
|
||||
}
|
||||
} else if (initializer == "natural") {
|
||||
for (int i = 0; i < cpu_tensor.numel(); ++i) {
|
||||
cpu_ptr[i] = static_cast<T>(lower + i);
|
||||
}
|
||||
} else if (initializer == "zeros") {
|
||||
for (int i = 0; i < cpu_tensor.numel(); ++i) {
|
||||
cpu_ptr[i] = static_cast<T>(0);
|
||||
}
|
||||
} else if (initializer == "file") {
|
||||
std::ifstream is(filename);
|
||||
for (int i = 0; i < cpu_tensor.numel(); ++i) {
|
||||
T value;
|
||||
is >> value;
|
||||
cpu_ptr[i] = static_cast<T>(value);
|
||||
}
|
||||
is.close();
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported initializer %s in OpTester.", initializer.c_str()));
|
||||
}
|
||||
|
||||
if (!phi::is_cpu_place(place_)) {
|
||||
::paddle::framework::TensorCopySync(cpu_tensor, place_, tensor);
|
||||
}
|
||||
}
|
||||
|
||||
void OpTester::CreateVariables(framework::Scope *scope) {
|
||||
for (auto &item : vars_) {
|
||||
auto &var = item.second;
|
||||
if (var->Name() == framework::kEmptyVarName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *ptr = scope->Var(var->Name());
|
||||
framework::InitializeVariable(ptr, var->GetType());
|
||||
if (var->Persistable()) {
|
||||
VLOG(3) << "Create Variable " << var->Name()
|
||||
<< " global, which pointer is " << ptr;
|
||||
} else {
|
||||
VLOG(3) << "Create Variable " << var->Name()
|
||||
<< " locally, which pointer is " << ptr;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &item : inputs_) {
|
||||
// Allocate memory for input tensor
|
||||
auto &var_name = item.first;
|
||||
VLOG(3) << "Allocate memory for tensor " << var_name;
|
||||
|
||||
auto &var_desc = vars_[var_name];
|
||||
std::vector<int64_t> shape = var_desc->GetShape();
|
||||
|
||||
auto *var = scope->Var(var_name);
|
||||
auto *tensor = var->GetMutable<phi::DenseTensor>();
|
||||
const auto &data_type = var_desc->GetDataType();
|
||||
if (data_type == framework::proto::VarType::INT32) {
|
||||
SetupTensor<int>(
|
||||
tensor, shape, 0, 1, item.second.initializer, item.second.filename);
|
||||
} else if (data_type == framework::proto::VarType::INT64) {
|
||||
SetupTensor<int64_t>(
|
||||
tensor, shape, 0, 1, item.second.initializer, item.second.filename);
|
||||
} else if (data_type == framework::proto::VarType::FP32) {
|
||||
SetupTensor<float>(tensor,
|
||||
shape,
|
||||
static_cast<float>(0.0),
|
||||
static_cast<float>(1.0),
|
||||
item.second.initializer,
|
||||
item.second.filename);
|
||||
} else if (data_type == framework::proto::VarType::FP64) {
|
||||
SetupTensor<double>(tensor,
|
||||
shape,
|
||||
static_cast<double>(0.0),
|
||||
static_cast<double>(1.0),
|
||||
item.second.initializer,
|
||||
item.second.filename);
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported dtype %d in OpTester.", data_type));
|
||||
}
|
||||
|
||||
VLOG(3) << "Set lod for tensor " << var_name;
|
||||
std::vector<std::vector<size_t>> &lod_vec = item.second.lod;
|
||||
phi::LegacyLoD lod;
|
||||
for (auto &item : lod_vec) {
|
||||
lod.push_back(item);
|
||||
}
|
||||
tensor->set_lod(lod);
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GenSpaces(int count) {
|
||||
std::stringstream ss;
|
||||
for (int i = 0; i < count; ++i) {
|
||||
ss << " ";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string OpTester::DebugString() {
|
||||
std::stringstream ss;
|
||||
int count = 0;
|
||||
for (auto &item : vars_) {
|
||||
auto &var = item.second;
|
||||
ss << GenSpaces(count++) << "vars {\n";
|
||||
ss << GenSpaces(count) << "name: \"" << var->Name() << "\"\n";
|
||||
ss << GenSpaces(count++) << "type: {\n";
|
||||
ss << GenSpaces(count) << "type: DENSE_TENSOR\n";
|
||||
ss << GenSpaces(count++) << "lod_tensor {\n";
|
||||
ss << GenSpaces(count++) << "tensor {\n";
|
||||
const auto &data_type = var->GetDataType();
|
||||
if (data_type == framework::proto::VarType::INT32) {
|
||||
ss << GenSpaces(count) << "data_type: INT32\n";
|
||||
} else if (data_type == framework::proto::VarType::INT64) {
|
||||
ss << GenSpaces(count) << "data_type: INT64\n";
|
||||
} else if (data_type == framework::proto::VarType::FP32) {
|
||||
ss << GenSpaces(count) << "data_type: FP32\n";
|
||||
} else if (data_type == framework::proto::VarType::FP64) {
|
||||
ss << GenSpaces(count) << "data_type: FP64\n";
|
||||
}
|
||||
std::vector<int64_t> shape = var->GetShape();
|
||||
for (auto d : shape) {
|
||||
ss << GenSpaces(count) << "dims: " << d << "\n";
|
||||
}
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
ss << GenSpaces(count) << "persistable: " << var->Persistable() << "\n";
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
}
|
||||
ss << GenSpaces(count++) << "ops {\n";
|
||||
for (auto &name : op_desc_.InputNames()) {
|
||||
ss << GenSpaces(count++) << "inputs {\n";
|
||||
ss << GenSpaces(count) << "parameters: \"" << name << "\"\n";
|
||||
ss << GenSpaces(count) << "arguments: \"" << op_desc_.Input(name)[0]
|
||||
<< "\"\n";
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
}
|
||||
for (auto &name : op_desc_.OutputNames()) {
|
||||
ss << GenSpaces(count++) << "outputs {\n";
|
||||
ss << GenSpaces(count) << "parameters: \"" << name << "\"\n";
|
||||
ss << GenSpaces(count) << "arguments: \"" << op_desc_.Output(name)[0]
|
||||
<< "\"\n";
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
}
|
||||
ss << GenSpaces(count) << "type: " << op_desc_.Type() << "\n";
|
||||
for (auto &name : op_desc_.AttrNames()) {
|
||||
ss << GenSpaces(count++) << "attrs {\n";
|
||||
const auto &attr_type = op_desc_.GetAttrType(name);
|
||||
const auto &attr = op_desc_.GetAttr(name);
|
||||
ss << GenSpaces(count) << "name: \"" << name << "\"\n";
|
||||
switch (attr_type) {
|
||||
case framework::proto::AttrType::BOOLEAN: {
|
||||
ss << GenSpaces(count) << "type: BOOLEAN\n";
|
||||
ss << GenSpaces(count) << "b: " << PADDLE_GET_CONST(bool, attr) << "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::INT: {
|
||||
ss << GenSpaces(count) << "type: INT\n";
|
||||
ss << GenSpaces(count) << "i: " << PADDLE_GET_CONST(int, attr) << "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::FLOAT: {
|
||||
ss << GenSpaces(count) << "type: FLOAT\n";
|
||||
ss << GenSpaces(count) << "f: " << PADDLE_GET_CONST(float, attr)
|
||||
<< "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::STRING: {
|
||||
ss << GenSpaces(count) << "type: STRING\n";
|
||||
ss << GenSpaces(count) << "s: \"" << PADDLE_GET_CONST(std::string, attr)
|
||||
<< "\"\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::BOOLEANS: {
|
||||
ss << GenSpaces(count) << "type: BOOLEANS\n";
|
||||
ss << GenSpaces(count) << "bools: "
|
||||
<< "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::INTS: {
|
||||
ss << GenSpaces(count) << "type: INTS\n";
|
||||
ss << GenSpaces(count) << "ints: "
|
||||
<< "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::FLOATS: {
|
||||
ss << GenSpaces(count) << "type: FLOATS\n";
|
||||
ss << GenSpaces(count) << "floats: "
|
||||
<< "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::STRINGS: {
|
||||
ss << GenSpaces(count) << "type: STRINGS\n";
|
||||
ss << GenSpaces(count) << "strings: "
|
||||
<< "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::LONG: {
|
||||
ss << GenSpaces(count) << "type: LONG\n";
|
||||
ss << GenSpaces(count) << "l: " << PADDLE_GET_CONST(int64_t, attr)
|
||||
<< "\n";
|
||||
} break;
|
||||
case framework::proto::AttrType::LONGS: {
|
||||
ss << GenSpaces(count) << "type: LONGS\n";
|
||||
ss << GenSpaces(count) << "longs: "
|
||||
<< "\n";
|
||||
} break;
|
||||
default:
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported attr type %d in OpTester.", attr_type));
|
||||
}
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
}
|
||||
ss << GenSpaces(--count) << "}\n";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
TEST(op_tester, base) {
|
||||
if (!FLAGS_op_config_list.empty()) {
|
||||
std::ifstream fin(FLAGS_op_config_list, std::ios::in | std::ios::binary);
|
||||
PADDLE_ENFORCE_EQ(
|
||||
static_cast<bool>(fin),
|
||||
true,
|
||||
common::errors::InvalidArgument("OpTester cannot open file %s",
|
||||
FLAGS_op_config_list.c_str()));
|
||||
std::vector<OpTesterConfig> op_configs;
|
||||
while (!fin.eof()) {
|
||||
VLOG(4) << "Reading config " << op_configs.size() << "...";
|
||||
OpTesterConfig config;
|
||||
bool result = config.Init(fin);
|
||||
if (result) {
|
||||
op_configs.push_back(config);
|
||||
}
|
||||
}
|
||||
if (FLAGS_specified_config_id >= 0 &&
|
||||
FLAGS_specified_config_id < static_cast<int>(op_configs.size())) {
|
||||
OpTester tester;
|
||||
tester.Init(op_configs[FLAGS_specified_config_id]);
|
||||
tester.Run();
|
||||
} else {
|
||||
for (auto &op_config : op_configs) {
|
||||
OpTester tester;
|
||||
tester.Init(op_config);
|
||||
tester.Run();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
OpTester tester;
|
||||
OpTesterConfig config;
|
||||
config.op_type = "elementwise_add";
|
||||
config.inputs.resize(2);
|
||||
config.inputs[0].name = "X";
|
||||
config.inputs[0].dims = {64, 64};
|
||||
config.inputs[1].name = "Y";
|
||||
config.inputs[1].dims = {64, 1};
|
||||
tester.Init(config);
|
||||
tester.Run();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace benchmark
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,79 @@
|
||||
/* Copyright (c) 2016 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. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "paddle/common/ddim.h"
|
||||
#include "paddle/fluid/framework/op_desc.h"
|
||||
#include "paddle/fluid/framework/operator.h"
|
||||
#include "test/cpp/fluid/benchmark/op_tester_config.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
namespace benchmark {
|
||||
|
||||
class OpTester {
|
||||
public:
|
||||
OpTester() {}
|
||||
|
||||
void Init(const std::string &filename);
|
||||
void Init(const OpTesterConfig &config);
|
||||
|
||||
void Run();
|
||||
|
||||
std::string DebugString();
|
||||
|
||||
private:
|
||||
std::vector<std::string> GetOpProtoInputNames();
|
||||
std::vector<std::string> GetOpProtoOutputNames();
|
||||
std::unordered_map<std::string, framework::proto::AttrType>
|
||||
GetOpProtoAttrNames();
|
||||
|
||||
framework::proto::VarType::Type TransToVarType(std::string str);
|
||||
void CreateInputVarDesc();
|
||||
void CreateOutputVarDesc();
|
||||
void CreateOpDesc();
|
||||
|
||||
framework::VarDesc *Var(const std::string &name);
|
||||
void CreateVariables(framework::Scope *scope);
|
||||
|
||||
template <typename T>
|
||||
void SetupTensor(phi::DenseTensor *input,
|
||||
const std::vector<int64_t> &shape,
|
||||
T lower,
|
||||
T upper,
|
||||
const std::string &initializer,
|
||||
const std::string &filename);
|
||||
|
||||
void RunImpl();
|
||||
|
||||
private:
|
||||
OpTesterConfig config_;
|
||||
std::string type_;
|
||||
framework::OpDesc op_desc_;
|
||||
std::unordered_map<std::string, std::unique_ptr<framework::VarDesc>> vars_;
|
||||
std::unordered_map<std::string, OpInputConfig> inputs_;
|
||||
std::unique_ptr<framework::OperatorBase> op_;
|
||||
phi::Place place_;
|
||||
std::unique_ptr<framework::Scope> scope_;
|
||||
};
|
||||
|
||||
} // namespace benchmark
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,25 @@
|
||||
/* Copyright (c) 2016 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 "test/cpp/fluid/benchmark/op_tester_config.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "paddle/fluid/platform/enforce.h"
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
namespace benchmark {} // namespace benchmark
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
@@ -0,0 +1,299 @@
|
||||
/* Copyright (c) 2016 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. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace paddle {
|
||||
namespace operators {
|
||||
namespace benchmark {
|
||||
|
||||
struct OpInputConfig {
|
||||
OpInputConfig() {}
|
||||
explicit OpInputConfig(std::istream& is);
|
||||
|
||||
void ParseDType(std::istream& is);
|
||||
void ParseInitializer(std::istream& is);
|
||||
void ParseDims(std::istream& is);
|
||||
void ParseLoD(std::istream& is);
|
||||
|
||||
std::string name;
|
||||
std::string dtype{"fp32"}; // int32/int, int64/long, fp32/float, fp64/double
|
||||
std::string initializer{"random"}; // random, natural, zeros, file
|
||||
std::string filename{""};
|
||||
std::vector<int64_t> dims;
|
||||
std::vector<std::vector<size_t>> lod;
|
||||
};
|
||||
|
||||
struct OpTesterConfig {
|
||||
OpTesterConfig() {}
|
||||
explicit OpTesterConfig(const std::string& filename);
|
||||
|
||||
bool Init(std::istream& is);
|
||||
|
||||
bool ParseAttrs(std::istream& is);
|
||||
|
||||
const OpInputConfig* GetInput(const std::string& name);
|
||||
|
||||
std::string op_type;
|
||||
std::vector<OpInputConfig> inputs;
|
||||
std::unordered_map<std::string, std::string> attrs;
|
||||
int device_id{-1}; // CPU: -1
|
||||
int repeat{1};
|
||||
int profile{0};
|
||||
int print_debug_string{0};
|
||||
double runtime{0.0};
|
||||
};
|
||||
|
||||
static bool Has(const std::vector<std::string>& vec, const std::string& item) {
|
||||
for (size_t i = 0; i < vec.size(); ++i) {
|
||||
if (vec[i] == item) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T StringTo(const std::string& str) {
|
||||
std::istringstream is(str);
|
||||
T value;
|
||||
is >> value;
|
||||
return value;
|
||||
}
|
||||
|
||||
static const char kStartSeparator[] = "{";
|
||||
static const char kEndSeparator[] = "}";
|
||||
static const char kSepBetweenItems[] = ";";
|
||||
|
||||
static bool StartWith(const std::string& str, const std::string& substr) {
|
||||
return str.find(substr) == 0;
|
||||
}
|
||||
|
||||
static bool EndWith(const std::string& str, const std::string& substr) {
|
||||
return str.rfind(substr) == (str.length() - substr.length());
|
||||
}
|
||||
|
||||
static void EraseEndSep(std::string* str,
|
||||
std::string substr = kSepBetweenItems) {
|
||||
if (EndWith(*str, substr)) {
|
||||
str->erase(str->length() - substr.length(), str->length());
|
||||
}
|
||||
}
|
||||
|
||||
OpInputConfig::OpInputConfig(std::istream& is) {
|
||||
std::string sep;
|
||||
is >> sep;
|
||||
if (sep == kStartSeparator) {
|
||||
while (sep != kEndSeparator) {
|
||||
is >> sep;
|
||||
if (sep == "name" || sep == "name:") {
|
||||
is >> name;
|
||||
EraseEndSep(&name);
|
||||
} else if (sep == "dtype" || sep == "dtype:") {
|
||||
ParseDType(is);
|
||||
} else if (sep == "initializer" || sep == "initializer:") {
|
||||
ParseInitializer(is);
|
||||
} else if (sep == "dims" || sep == "dims:") {
|
||||
ParseDims(is);
|
||||
} else if (sep == "lod" || sep == "lod:") {
|
||||
ParseLoD(is);
|
||||
} else if (sep == "filename") {
|
||||
is >> filename;
|
||||
EraseEndSep(&filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpInputConfig::ParseDType(std::istream& is) {
|
||||
std::string dtype_str;
|
||||
is >> dtype_str;
|
||||
EraseEndSep(&dtype_str);
|
||||
|
||||
if (dtype_str == "int32" || dtype_str == "int") {
|
||||
dtype = "int32";
|
||||
} else if (dtype_str == "int64" || dtype_str == "long") {
|
||||
dtype = "int64";
|
||||
} else if (dtype_str == "fp32" || dtype_str == "float") {
|
||||
dtype = "fp32";
|
||||
} else if (dtype_str == "fp64" || dtype_str == "double") {
|
||||
dtype = "fp64";
|
||||
} else {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported dtype %s in OpInputConfig.", dtype_str.c_str()));
|
||||
}
|
||||
VLOG(4) << "dtype of input " << name << " is: " << dtype;
|
||||
}
|
||||
|
||||
void OpInputConfig::ParseInitializer(std::istream& is) {
|
||||
std::string initializer_str;
|
||||
is >> initializer_str;
|
||||
EraseEndSep(&initializer_str);
|
||||
|
||||
const std::vector<std::string> supported_initializers = {
|
||||
"random", "natural", "zeros", "file"};
|
||||
if (!Has(supported_initializers, initializer_str)) {
|
||||
PADDLE_THROW(common::errors::Unimplemented(
|
||||
"Unsupported initializer %s in OpInputConfig.",
|
||||
initializer_str.c_str()));
|
||||
}
|
||||
|
||||
initializer = initializer_str;
|
||||
VLOG(4) << "initializer of input " << name << " is: " << initializer;
|
||||
}
|
||||
|
||||
void OpInputConfig::ParseDims(std::istream& is) {
|
||||
std::string dims_str;
|
||||
is >> dims_str;
|
||||
|
||||
dims.clear();
|
||||
std::string token;
|
||||
std::istringstream token_stream(dims_str);
|
||||
while (std::getline(token_stream, token, 'x')) {
|
||||
dims.push_back(std::stoi(token));
|
||||
}
|
||||
}
|
||||
|
||||
void OpInputConfig::ParseLoD(std::istream& is) {
|
||||
std::string lod_str;
|
||||
std::string start_sep =
|
||||
std::string(kStartSeparator) + std::string(kStartSeparator);
|
||||
std::string end_sep = std::string(kEndSeparator) + std::string(kEndSeparator);
|
||||
|
||||
std::string sep;
|
||||
is >> sep;
|
||||
if (StartWith(sep, start_sep)) {
|
||||
lod_str += sep;
|
||||
while (!EndWith(sep, end_sep)) {
|
||||
is >> sep;
|
||||
lod_str += sep;
|
||||
}
|
||||
}
|
||||
EraseEndSep(&lod_str);
|
||||
PADDLE_ENFORCE_GE(
|
||||
lod_str.length(),
|
||||
4U,
|
||||
common::errors::InvalidArgument(
|
||||
"The length of lod string should be "
|
||||
"equal to or larger than 4. But length of lod string is %zu.",
|
||||
lod_str.length()));
|
||||
VLOG(4) << "lod: " << lod_str << ", length: " << lod_str.length();
|
||||
|
||||
// Parse the lod_str
|
||||
lod.clear();
|
||||
for (size_t i = 1; i < lod_str.length() - 1;) {
|
||||
if (lod_str[i] == '{') {
|
||||
std::vector<size_t> level;
|
||||
while (lod_str[i] != '}') {
|
||||
++i;
|
||||
|
||||
std::string number;
|
||||
while (lod_str[i] >= '0' && lod_str[i] <= '9') {
|
||||
number += lod_str[i];
|
||||
++i;
|
||||
}
|
||||
level.push_back(StringTo<size_t>(number));
|
||||
}
|
||||
lod.push_back(level);
|
||||
} else if (lod_str[i] == '}') {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OpTesterConfig::OpTesterConfig(const std::string& filename) {
|
||||
std::ifstream fin(filename, std::ios::in | std::ios::binary);
|
||||
PADDLE_ENFORCE_EQ(
|
||||
static_cast<bool>(fin),
|
||||
true,
|
||||
common::errors::InvalidArgument("OpTesterConfig cannot open file %s.",
|
||||
filename.c_str()));
|
||||
|
||||
Init(fin);
|
||||
}
|
||||
|
||||
bool OpTesterConfig::Init(std::istream& is) {
|
||||
std::string sep;
|
||||
is >> sep;
|
||||
if (sep == kStartSeparator) {
|
||||
while (sep != kEndSeparator) {
|
||||
is >> sep;
|
||||
if (sep == "op_type" || sep == "op_type:") {
|
||||
is >> op_type;
|
||||
} else if (sep == "device_id" || sep == "device_id:") {
|
||||
is >> device_id;
|
||||
} else if (sep == "repeat" || sep == "repeat:") {
|
||||
is >> repeat;
|
||||
} else if (sep == "profile" || sep == "profile:") {
|
||||
is >> profile;
|
||||
} else if (sep == "print_debug_string" || sep == "print_debug_string:") {
|
||||
is >> print_debug_string;
|
||||
} else if (sep == "input" || sep == "input:") {
|
||||
OpInputConfig input_config(is);
|
||||
inputs.push_back(input_config);
|
||||
} else if (sep == "attrs" || sep == "attrs:") {
|
||||
ParseAttrs(is);
|
||||
} else {
|
||||
if (sep != kEndSeparator) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpTesterConfig::ParseAttrs(std::istream& is) {
|
||||
std::string sep;
|
||||
is >> sep;
|
||||
if (sep == kStartSeparator) {
|
||||
while (true) {
|
||||
std::string key;
|
||||
is >> key;
|
||||
if (key == kEndSeparator) {
|
||||
break;
|
||||
}
|
||||
|
||||
std::string value;
|
||||
is >> value;
|
||||
EraseEndSep(&key, ":");
|
||||
EraseEndSep(&value);
|
||||
VLOG(4) << "attrs: " << key << ", " << value;
|
||||
|
||||
attrs[key] = value;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const OpInputConfig* OpTesterConfig::GetInput(const std::string& name) {
|
||||
for (size_t i = 0; i < inputs.size(); ++i) {
|
||||
if (inputs[i].name == name) {
|
||||
return &inputs[i];
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace benchmark
|
||||
} // namespace operators
|
||||
} // namespace paddle
|
||||
Reference in New Issue
Block a user