Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
… remove_convert_tensor
  • Loading branch information
zyfncg committed Jan 15, 2022
2 parents 66e8e22 + a887914 commit 46efe37
Show file tree
Hide file tree
Showing 310 changed files with 5,806 additions and 3,456 deletions.
10 changes: 6 additions & 4 deletions cmake/configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ endif(NOT WITH_PROFILER)
if(WITH_AVX AND AVX_FOUND)
set(SIMD_FLAG ${AVX_FLAG})
add_definitions(-DPADDLE_WITH_AVX)
elseif(SSE3_FOUND)
if(NOT WIN32)
set(SIMD_FLAG ${SSE3_FLAG})
endif()
elseif(SSE3_FOUND AND NOT WIN32)
set(SIMD_FLAG ${SSE3_FLAG})
endif()

if (SSE3_FOUND)
# TODO: Runtime detection should be used here.
add_definitions(-DPADDLE_WITH_SSE3)
endif()

Expand Down
13 changes: 8 additions & 5 deletions cmake/external/llvm.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
include(FetchContent)

set(LLVM_DOWNLOAD_URL https://paddle-inference-dist.bj.bcebos.com/CINN/llvm11.tar.gz)
set(LLVM_MD5 39d32b6be466781dddf5869318dcba53)
set(LLVM_DOWNLOAD_URL https://paddle-inference-dist.bj.bcebos.com/infrt/llvm_b5149f4e66a49a98b67e8e2de4e24a4af8e2781b.tar.gz)
set(LLVM_MD5 022819bb5760817013cf4b8a37e97d5e)

set(FETCHCONTENT_BASE_DIR ${THIRD_PARTY_PATH}/llvm)
set(FETCHCONTENT_QUIET OFF)
Expand Down Expand Up @@ -51,16 +51,18 @@ message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
# To build with MLIR, the LLVM is build from source code using the following flags:

#[==[
cmake -G Ninja ../llvm \
cmake ../llvm -G "Unix Makefiles" \
-DLLVM_ENABLE_PROJECTS="mlir;clang" \
-DLLVM_BUILD_EXAMPLES=OFF \
-DLLVM_TARGETS_TO_BUILD="X86" \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_ASSERTIONS=ON \
-DLLVM_ENABLE_ZLIB=OFF \
-DLLVM_ENABLE_RTTI=ON \
-DLLVM_INSTALL_UTILS=ON \
-DCMAKE_INSTALL_PREFIX=./install
#]==]
# The matched llvm-project version is f9dc2b7079350d0fed3bb3775f496b90483c9e42 (currently a temporary commit)
# The matched llvm-project version is b5149f4e66a49a98b67e8e2de4e24a4af8e2781b (currently a temporary commit)

add_definitions(${LLVM_DEFINITIONS})

Expand All @@ -75,7 +77,7 @@ add_definitions(${LLVM_DEFINITIONS})


# The minimum needed libraries for MLIR IR parse and transform.
set(MLIR_IR_LIBS MLIRAnalysis MLIRStandardOps MLIRPass MLIRParser MLIRDialect MLIRIR MLIROptLib)
set(MLIR_IR_LIBS MLIRAnalysis MLIRPass MLIRParser MLIRDialect MLIRIR MLIROptLib)


# tb_base is the name of a xxx.td file (without the .td suffix)
Expand All @@ -89,6 +91,7 @@ function(mlir_tablegen_on td_base)
mlir_tablegen(${td_base}.cpp.inc -gen-op-defs)
if (mlir_tablegen_on_DIALECT)
mlir_tablegen(${td_base}_dialect.hpp.inc --gen-dialect-decls -dialect=${mlir_tablegen_on_DIALECT})
mlir_tablegen(${td_base}_dialect.cpp.inc --gen-dialect-defs -dialect=${mlir_tablegen_on_DIALECT})
endif()
add_public_tablegen_target(${td_base}_IncGen)
add_custom_target(${td_base}_inc DEPENDS ${td_base}_IncGen)
Expand Down
6 changes: 3 additions & 3 deletions cmake/pten_kernel.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
function(kernel_declare TARGET_LIST)
foreach(kernel_path ${TARGET_LIST})
file(READ ${kernel_path} kernel_impl)
# TODO(chenweihang): rename PT_REGISTER_CTX_KERNEL to PT_REGISTER_KERNEL
# TODO(chenweihang): rename PT_REGISTER_KERNEL to PT_REGISTER_KERNEL
# NOTE(chenweihang): now we don't recommend to use digit in kernel name
string(REGEX MATCH "(PT_REGISTER_CTX_KERNEL|PT_REGISTER_GENERAL_KERNEL)\\([ \t\r\n]*[a-z0-9_]*," first_registry "${kernel_impl}")
string(REGEX MATCH "(PT_REGISTER_KERNEL|PT_REGISTER_GENERAL_KERNEL)\\([ \t\r\n]*[a-z0-9_]*," first_registry "${kernel_impl}")
if (NOT first_registry STREQUAL "")
# parse the first kernel name
string(REPLACE "PT_REGISTER_CTX_KERNEL(" "" kernel_name "${first_registry}")
string(REPLACE "PT_REGISTER_KERNEL(" "" kernel_name "${first_registry}")
string(REPLACE "PT_REGISTER_GENERAL_KERNEL(" "" kernel_name "${kernel_name}")
string(REPLACE "," "" kernel_name "${kernel_name}")
string(REGEX REPLACE "[ \t\r\n]+" "" kernel_name "${kernel_name}")
Expand Down
4 changes: 2 additions & 2 deletions paddle/fluid/distributed/fleet_executor/carrier.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ class Carrier final {
std::mutex running_mutex_;
std::condition_variable cond_var_;
std::vector<framework::Scope*> microbatch_scopes_;
framework::Scope* root_scope_;
framework::Scope* minibatch_scope_;
framework::Scope* root_scope_{nullptr};
framework::Scope* minibatch_scope_{nullptr};
paddle::platform::Place place_;
paddle::platform::DeviceContext* dev_ctx_{nullptr};
int64_t rank_;
Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/eager/accumulation/accumulation_node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

#include "paddle/pten/api/all.h"
#include "paddle/pten/core/dense_tensor.h"
#include "paddle/pten/include/core.h"

#include "paddle/fluid/platform/device_context.h"
#include "paddle/fluid/platform/enforce.h"
Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/eager/accumulation/gradient_accumulation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "paddle/fluid/platform/float16.h"
#include "paddle/pten/api/all.h"
#include "paddle/pten/core/convert_utils.h"
#include "paddle/pten/include/core.h"
#include "unsupported/Eigen/CXX11/Tensor"
#ifdef PADDLE_WITH_XPU
#include "xpu/refactor/math.h"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
#include "paddle/fluid/eager/api/utils/global_utils.h"
#include "paddle/fluid/eager/eager_tensor.h"

#include "paddle/pten/api/all.h"
#include "paddle/pten/kernels/scale_kernel.h"

#include "paddle/fluid/platform/device_context.h"
#include "paddle/fluid/platform/enforce.h"
Expand All @@ -33,28 +33,28 @@ static void ScaleDeviceDispatch(const pten::DenseTensor& dense_tensor,
pten::DenseTensor* dense_out) {
switch (dense_tensor.dtype()) {
case pten::DataType::FLOAT64: {
pten::Scale<double, DeviceContext>(
pten::ScaleKernel<double, DeviceContext>(
dev_ctx, dense_tensor /* tensor */, scale /* scale */,
bias /* bias */, bias_after_scale /* bias_after_scale */,
dense_out /* out tensor */);
break;
}
case pten::DataType::FLOAT32: {
pten::Scale<float, DeviceContext>(dev_ctx, dense_tensor /* tensor */,
scale /* scale */, bias /* bias */,
bias_after_scale /* bias_after_scale */,
dense_out /* out tensor */);
pten::ScaleKernel<float, DeviceContext>(
dev_ctx, dense_tensor /* tensor */, scale /* scale */,
bias /* bias */, bias_after_scale /* bias_after_scale */,
dense_out /* out tensor */);
break;
}
case pten::DataType::INT64: {
pten::Scale<int64_t, DeviceContext>(
pten::ScaleKernel<int64_t, DeviceContext>(
dev_ctx, dense_tensor /* tensor */, scale /* scale */,
bias /* bias */, bias_after_scale /* bias_after_scale */,
dense_out /* out tensor */);
break;
}
case pten::DataType::INT32: {
pten::Scale<int32_t, DeviceContext>(
pten::ScaleKernel<int32_t, DeviceContext>(
dev_ctx, dense_tensor /* tensor */, scale /* scale */,
bias /* bias */, bias_after_scale /* bias_after_scale */,
dense_out /* out tensor */);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
#include "paddle/fluid/eager/utils.h"

#include "paddle/pten/api/all.h"
#include "paddle/pten/include/core.h"

namespace egr {

Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/eager/eager_tensor.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
#include "paddle/fluid/framework/tensor.h"
#include "paddle/fluid/framework/variable.h"
// pten deps
#include "paddle/pten/all.h"
#include "paddle/pten/api/all.h"
#include "paddle/pten/api/lib/api_declare.h"
#include "paddle/pten/api/lib/utils/tensor_utils.h"
Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/eager/grad_node_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/pten/api/all.h"
#include "paddle/pten/include/core.h"

namespace egr {
/**
Expand Down
19 changes: 14 additions & 5 deletions paddle/fluid/eager/legacy/infer_shape_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,18 @@ class EagerInferShapeContext : public paddle::framework::InferShapeContext {
using DDim = paddle::framework::DDim;

public:
EagerInferShapeContext(const NameTensorMap* in, const NameTensorMap* out,
const paddle::framework::AttributeMap* attr,
const paddle::framework::AttributeMap* default_attr,
const std::string op_type)
EagerInferShapeContext(
const NameTensorMap* in, const NameTensorMap* out,
const paddle::framework::AttributeMap* attr,
const paddle::framework::AttributeMap* default_attr,
const std::string op_type,
const paddle::framework::OpKernelType* op_kernel_type = nullptr)
: tensor_in_(in),
tensor_out_(out),
attrs_(attr),
default_attrs_(default_attr),
op_type_(op_type) {}
op_type_(op_type),
op_kernel_type_(op_kernel_type) {}

bool HasInput(const std::string& name) const override {
// has only one input
Expand Down Expand Up @@ -214,6 +217,11 @@ class EagerInferShapeContext : public paddle::framework::InferShapeContext {

bool IsRuntime() const override { return true; }

bool IsRunMKLDNNKernel() const override {
return (op_kernel_type_ && (op_kernel_type_->data_layout_ ==
paddle::framework::DataLayout::kMKLDNN));
}

// TODO(paddle-dev): Can this be template?
std::vector<paddle::framework::InferShapeVarPtr> GetInputVarPtrs(
const std::string& name) const override {
Expand Down Expand Up @@ -400,6 +408,7 @@ class EagerInferShapeContext : public paddle::framework::InferShapeContext {
const paddle::framework::AttributeMap* attrs_;
const paddle::framework::AttributeMap* default_attrs_;
const std::string op_type_;
const paddle::framework::OpKernelType* op_kernel_type_;
};

} // namespace legacy
Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/eager/legacy/infer_var_type_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
#include "paddle/fluid/framework/var_type_inference.h"
#include "paddle/fluid/framework/var_type_traits.h"
#include "paddle/pten/api/all.h"
#include "paddle/pten/include/core.h"

namespace egr {
namespace legacy {
Expand Down
2 changes: 1 addition & 1 deletion paddle/fluid/eager/legacy/prepared_operator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ static void PreparedOpRunImpl(
paddle::framework::Scope scope;

EagerInferShapeContext infer_shape_ctx(&ins, &outs, &attrs, &default_attrs,
op.Type());
op.Type(), &kernel_type);
op.Info().infer_shape_(&infer_shape_ctx);

func(EagerExecutionContext(op, scope, *dev_ctx, ctx, ins, outs, attrs,
Expand Down
2 changes: 0 additions & 2 deletions paddle/fluid/eager/legacy/prepared_operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@
#include "paddle/fluid/framework/operator.h"
#include "paddle/fluid/framework/type_defs.h"

#include "paddle/pten/include/core.h"

DECLARE_bool(use_mkldnn);

namespace paddle {
Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/eager/legacy/tensor_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <vector>
#include "paddle/fluid/eager/eager_tensor.h"
#include "paddle/pten/api/all.h"
#include "paddle/pten/include/core.h"
namespace egr {
namespace legacy {

Expand Down
1 change: 0 additions & 1 deletion paddle/fluid/framework/data_device_transform_test.cu
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ limitations under the License. */
#include "paddle/fluid/platform/init.h"

#include "paddle/fluid/framework/pten_utils.h"
#include "paddle/pten/include/core.h"

namespace paddle {
namespace framework {
Expand Down
11 changes: 11 additions & 0 deletions paddle/fluid/framework/new_executor/new_executor_defs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,17 @@ void InterpretercoreInferShapeContext::SetLoDLevel(const std::string& out,

bool InterpretercoreInferShapeContext::IsRuntime() const { return true; }

bool InterpretercoreInferShapeContext::IsRunMKLDNNKernel() const {
try {
auto& op_with_kernel = dynamic_cast<const OperatorWithKernel&>(op_);
return ((op_with_kernel.kernel_type()) &&
(op_with_kernel.kernel_type()->data_layout_ ==
framework::DataLayout::kMKLDNN));
} catch (std::bad_cast exp) {
return false;
}
}

// TODO(paddle-dev): Can this be template?
std::vector<InferShapeVarPtr> InterpretercoreInferShapeContext::GetInputVarPtrs(
const std::string& name) const {
Expand Down
2 changes: 2 additions & 0 deletions paddle/fluid/framework/new_executor/new_executor_defs.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class InterpretercoreInferShapeContext : public InferShapeContext {

bool IsRuntime() const override;

bool IsRunMKLDNNKernel() const override;

// TODO(paddle-dev): Can this be template?
std::vector<InferShapeVarPtr> GetInputVarPtrs(
const std::string& name) const override;
Expand Down
4 changes: 4 additions & 0 deletions paddle/fluid/framework/op_desc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,8 @@ class CompileTimeInferShapeContext : public InferShapeContext {

bool IsRuntime() const override;

bool IsRunMKLDNNKernel() const override;

std::vector<proto::VarType::Type> GetInputsVarType(
const std::string &name) const override {
return GetVarTypes(Inputs(name));
Expand Down Expand Up @@ -930,6 +932,8 @@ void CompileTimeInferShapeContext::SetRepeatedDims(

bool CompileTimeInferShapeContext::IsRuntime() const { return false; }

bool CompileTimeInferShapeContext::IsRunMKLDNNKernel() const { return false; }

proto::VarType::Type CompileTimeInferShapeContext::GetVarType(
const std::string &name) const {
return block_.FindVarRecursive(name)->GetType();
Expand Down
15 changes: 12 additions & 3 deletions paddle/fluid/framework/operator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,17 @@ class RuntimeInferShapeContext : public InferShapeContext {

bool IsRuntime() const override { return true; }

bool IsRunMKLDNNKernel() const override {
try {
auto& op_with_kernel = dynamic_cast<const OperatorWithKernel&>(op_);
return ((op_with_kernel.kernel_type()) &&
(op_with_kernel.kernel_type()->data_layout_ ==
framework::DataLayout::kMKLDNN));
} catch (std::bad_cast exp) {
return false;
}
}

// TODO(paddle-dev): Can this be template?
std::vector<InferShapeVarPtr> GetInputVarPtrs(
const std::string& name) const override {
Expand Down Expand Up @@ -1178,9 +1189,7 @@ void OperatorWithKernel::RunImpl(const Scope& scope,
platform::RecordEvent record_event("infer_shape",
platform::EventRole::kInnerOp);
RuntimeInferShapeContext infer_shape_ctx(*this, *runtime_ctx);
// TODO(chenweihang): replace this after removing `this->IsMKLDNNType()`
// in some mkldnn infershape functions, such conv2d infershape
this->InferShape(&infer_shape_ctx);
this->Info().infer_shape_(&infer_shape_ctx);
}

if (FLAGS_enable_unused_var_check) {
Expand Down
14 changes: 6 additions & 8 deletions paddle/fluid/framework/operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ limitations under the License. */
#include "paddle/utils/flat_hash_map.h"

#include "paddle/pten/core/arg_map_context.h"
#include "paddle/pten/include/core.h"
#include "paddle/pten/core/kernel_context.h"
#include "paddle/pten/core/kernel_factory.h"

namespace paddle {
namespace framework {
Expand Down Expand Up @@ -410,8 +411,8 @@ class ExecutionContext {
auto tmp_allocation_ptr = memory::Alloc(dev_ctx, product(dim) * sizeof(T));
auto& deleter = tmp_allocation_ptr.get_deleter();
auto* allocation_ptr = tmp_allocation_ptr.release();
auto shared_allocation = std::shared_ptr<memory::allocation::Allocation>(
allocation_ptr, deleter);
auto shared_allocation =
std::shared_ptr<pten::Allocation>(allocation_ptr, deleter);

PADDLE_ENFORCE_GE(
allocation_ptr->size(), framework::product(dim) * sizeof(T),
Expand Down Expand Up @@ -528,11 +529,6 @@ class OperatorWithKernel : public OperatorBase {
return g_all_op_kernels;
}

bool IsMKLDNNType() const {
return ((this->kernel_type_) && (this->kernel_type_->data_layout_ ==
framework::DataLayout::kMKLDNN));
}

bool SupportGPU() const override {
auto& op_kernels = OperatorWithKernel::AllOpKernels().at(type_);
return std::any_of(op_kernels.begin(), op_kernels.end(),
Expand Down Expand Up @@ -609,6 +605,8 @@ class OperatorWithKernel : public OperatorBase {
return pt_kernel_context_.get();
}

const OpKernelType* kernel_type() const { return kernel_type_.get(); }

private:
void RunImpl(const Scope& scope, const platform::Place& place) const final;
void RunImpl(const Scope& scope, const platform::Place& place,
Expand Down
2 changes: 2 additions & 0 deletions paddle/fluid/framework/shape_inference.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ class InferShapeContext {

virtual bool IsRuntime() const = 0;

virtual bool IsRunMKLDNNKernel() const = 0;

virtual std::vector<InferShapeVarPtr> GetInputVarPtrs(
const std::string &name) const = 0;
virtual std::vector<InferShapeVarPtr> GetOutputVarPtrs(
Expand Down
Loading

1 comment on commit 46efe37

@paddle-bot-old
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕵️ CI failures summary

🔍 PR: #38910 Commit ID: 46efe37 contains failed CI.

🔹 Failed: PR-CI-OP-benchmark

Unknown Failed
2022-01-15 20:04:48 [check_op_benchmark_result.py:153] [ERROR] Check speed result with case "min_2 (forward)" failed.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:238] [INFO] run function check_CHANGE_OP_MAP
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "lu_unpack"(paddle/fluid/operators/lu_unpack_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "reduce_amax"(paddle/fluid/operators/reduce_ops/reduce_amax_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "margin_cross_entropy"(paddle/fluid/operators/margin_cross_entropy_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "triangular_solve"(paddle/fluid/operators/triangular_solve_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "dot"(paddle/fluid/operators/dot_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "spectral"(paddle/fluid/operators/spectral_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "solve"(paddle/fluid/operators/solve_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "reduce_amin"(paddle/fluid/operators/reduce_ops/reduce_amin_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "fill_any_like"(paddle/fluid/operators/fill_any_like_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "conj"(paddle/fluid/operators/conj_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "lstsq"(paddle/fluid/operators/lstsq_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "lu"(paddle/fluid/operators/lu_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "dirichlet"(paddle/fluid/operators/dirichlet_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:245] [WARNING] Missing test script of "cholesky_solve"(paddle/fluid/operators/cholesky_solve_op.cu) in benchmark.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:249] [INFO] See https://github.com/PaddlePaddle/Paddle/wiki/PR-CI-OP-benchmark-Manual for details.
2022-01-15 20:04:48 [tools/ci_op_benchmark.sh:250] [INFO] Or you can apply for one RD (Avin0323(Recommend), Xreki, luotao1) approval to pass this PR.
2022-01-15 20:04:48 {build code state=8}

Please sign in to comment.