| #include <mutex> | |
| #include <thread> | |
| #include "caffe2/core/context.h" | |
| #include "caffe2/core/operator.h" | |
| #ifdef USE_MKLDNN | |
| #include <caffe2/ideep/operators/operator_fallback_ideep.h> | |
| #include <caffe2/ideep/utils/ideep_operator.h> | |
| #endif | |
| namespace caffe2 { | |
| namespace fb { | |
| namespace { | |
| class CreateMutexOp final : public Operator<CPUContext> { | |
| public: | |
| template <class... Args> | |
| explicit CreateMutexOp(Args&&... args) | |
| : Operator<CPUContext>(std::forward<Args>(args)...) {} | |
| bool RunOnDevice() override { | |
| *OperatorBase::Output<std::unique_ptr<std::mutex>>(0) = | |
| // NOLINTNEXTLINE(modernize-make-unique) | |
| std::unique_ptr<std::mutex>(new std::mutex); | |
| return true; | |
| } | |
| }; | |
| template <typename IntType> | |
| class AtomicFetchAddOp final : public Operator<CPUContext> { | |
| public: | |
| template <class... Args> | |
| explicit AtomicFetchAddOp(Args&&... args) | |
| : Operator<CPUContext>(std::forward<Args>(args)...) {} | |
| bool RunOnDevice() override { | |
| auto& mutex = OperatorBase::Input<std::unique_ptr<std::mutex>>(0); | |
| std::lock_guard<std::mutex> lg(*mutex); | |
| auto& a = Input(1); | |
| auto& b = Input(2); | |
| auto* c = Output(0); | |
| auto* d = Output(1); | |
| c->Resize(); | |
| d->Resize(); | |
| auto* aPtr = a.template data<IntType>(); | |
| auto* bPtr = b.template data<IntType>(); | |
| auto* cPtr = c->template mutable_data<IntType>(); | |
| auto* dPtr = d->template mutable_data<IntType>(); | |
| *dPtr = *aPtr; | |
| *cPtr = *aPtr + *bPtr; | |
| return true; | |
| } | |
| }; | |
| class CreateAtomicBoolOp final : public Operator<CPUContext> { | |
| public: | |
| using Operator::Operator; | |
| bool RunOnDevice() override { | |
| *OperatorBase::Output<std::unique_ptr<std::atomic<bool>>>(0) = | |
| // NOLINTNEXTLINE(modernize-make-unique) | |
| std::unique_ptr<std::atomic<bool>>(new std::atomic<bool>(false)); | |
| return true; | |
| } | |
| }; | |
| class ConditionalSetAtomicBoolOp final : public Operator<CPUContext> { | |
| public: | |
| using Operator::Operator; | |
| bool RunOnDevice() override { | |
| auto& ptr = | |
| OperatorBase::Input<std::unique_ptr<std::atomic<bool>>>(ATOMIC_BOOL); | |
| if (Input(CONDITION).data<bool>()[0]) { | |
| ptr->store(true); | |
| } | |
| return true; | |
| } | |
| private: | |
| INPUT_TAGS(ATOMIC_BOOL, CONDITION); | |
| }; | |
| class CheckAtomicBoolOp final : public Operator<CPUContext> { | |
| public: | |
| using Operator::Operator; | |
| bool RunOnDevice() override { | |
| auto& ptr = OperatorBase::Input<std::unique_ptr<std::atomic<bool>>>(0); | |
| Output(0)->Resize(1); | |
| *Output(0)->template mutable_data<bool>() = ptr->load(); | |
| return true; | |
| } | |
| }; | |
| REGISTER_CPU_OPERATOR(CreateMutex, CreateMutexOp); | |
| REGISTER_CPU_OPERATOR(AtomicFetchAdd, AtomicFetchAddOp<int32_t>); | |
| REGISTER_CPU_OPERATOR(AtomicFetchAdd64, AtomicFetchAddOp<int64_t>); | |
| #ifdef USE_MKLDNN | |
| REGISTER_IDEEP_OPERATOR( | |
| CreateMutex, | |
| IDEEPFallbackOp<CreateMutexOp, SkipIndices<0>>); | |
| #endif | |
| REGISTER_CPU_OPERATOR(CreateAtomicBool, CreateAtomicBoolOp); | |
| REGISTER_CPU_OPERATOR(ConditionalSetAtomicBool, ConditionalSetAtomicBoolOp); | |
| REGISTER_CPU_OPERATOR(CheckAtomicBool, CheckAtomicBoolOp); | |
| OPERATOR_SCHEMA(CreateMutex) | |
| .NumInputs(0) | |
| .NumOutputs(1) | |
| .SetDoc("Creates an unlocked mutex and returns it in a unique_ptr blob.") | |
| .Output(0, "mutex_ptr", "Blob containing a std::unique_ptr<mutex>.") | |
| .ScalarType(TensorProto_DataType_UNDEFINED); | |
| OPERATOR_SCHEMA(AtomicFetchAdd) | |
| .NumInputs(3) | |
| .NumOutputs(2) | |
| .SetDoc(R"DOC( | |
| Given a mutex and two int32 scalar tensors, performs an atomic fetch add | |
| by mutating the first argument and adding it to the second input | |
| argument. Returns the updated integer and the value prior to the update. | |
| )DOC") | |
| .Input(0, "mutex_ptr", "Blob containing to a unique_ptr<mutex>") | |
| .Input(1, "mut_value", "Value to be mutated after the sum.") | |
| .Input(2, "increment", "Value to add to the first operand.") | |
| .Output(0, "mut_value", "Mutated value after sum. Usually same as input 1.") | |
| .Output(1, "fetched_value", "Value of the first operand before sum.") | |
| .AllowInplace({{1, 0}}); | |
| OPERATOR_SCHEMA(AtomicFetchAdd64) | |
| .NumInputs(3) | |
| .NumOutputs(2) | |
| .SetDoc(R"DOC( | |
| Like, AtomicFetchAdd but with int64_t scalar tensors, | |
| performs an atomic fetch add | |
| by mutating the first argument and adding it to the second input | |
| argument. Returns the updated integer and the value prior to the update. | |
| )DOC") | |
| .Input(0, "mutex_ptr", "Blob containing to a unique_ptr<mutex>") | |
| .Input(1, "mut_value", "Value to be mutated after the sum.") | |
| .Input(2, "increment", "Value to add to the first operand.") | |
| .Output(0, "mut_value", "Mutated value after sum. Usually same as input 1.") | |
| .Output(1, "fetched_value", "Value of the first operand before sum.") | |
| .AllowInplace({{1, 0}}); | |
| OPERATOR_SCHEMA(CreateAtomicBool) | |
| .NumInputs(0) | |
| .NumOutputs(1) | |
| .SetDoc("Create an unique_ptr blob to hold an atomic<bool>") | |
| .Output(0, "atomic_bool", "Blob containing a unique_ptr<atomic<bool>>"); | |
| OPERATOR_SCHEMA(ConditionalSetAtomicBool) | |
| .NumInputs(2) | |
| .NumOutputs(0) | |
| .SetDoc(R"DOC( | |
| Set an atomic<bool> to true if the given condition bool variable is true | |
| )DOC") | |
| .Input(0, "atomic_bool", "Blob containing a unique_ptr<atomic<bool>>") | |
| .Input(1, "condition", "Blob containing a bool"); | |
| OPERATOR_SCHEMA(CheckAtomicBool) | |
| .NumInputs(1) | |
| .NumOutputs(1) | |
| .SetDoc("Copy the value of an atomic<bool> to a bool") | |
| .Input(0, "atomic_bool", "Blob containing a unique_ptr<atomic<bool>>") | |
| .Output(0, "value", "Copy of the value for the atomic<bool>"); | |
| SHOULD_NOT_DO_GRADIENT(CreateMutex); | |
| SHOULD_NOT_DO_GRADIENT(AtomicFetchAdd); | |
| SHOULD_NOT_DO_GRADIENT(CreateAtomicBool); | |
| SHOULD_NOT_DO_GRADIENT(ConditionalSetAtomicBool); | |
| SHOULD_NOT_DO_GRADIENT(CheckAtomicBool); | |
| } // namespace | |
| } // namespace fb | |
| } // namespace caffe2 |