Skip to content

Commit 3a29404

Browse files
authored
Merge pull request #11233 from tensor-tang/multithreads
Fix abort issue in cpu multi-threads
2 parents 4f95bc9 + 4b7b17a commit 3a29404

File tree

3 files changed

+46
-35
lines changed

3 files changed

+46
-35
lines changed

paddle/fluid/framework/scope.cc

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ Scope& Scope::NewScope() const {
4343
}
4444

4545
Variable* Scope::Var(const std::string& name) {
46+
// acquire the lock when new var under this scope
47+
std::unique_lock<std::mutex> lock(mutex_);
4648
auto* v = FindVarLocally(name);
4749
if (v != nullptr) return v;
4850

@@ -62,11 +64,17 @@ Variable* Scope::Var(std::string* name) {
6264
}
6365

6466
Variable* Scope::FindVar(const std::string& name) const {
67+
// acquire the lock when find var
68+
std::unique_lock<std::mutex> lock(mutex_);
69+
return FindVarInternal(name);
70+
}
71+
72+
Variable* Scope::FindVarInternal(const std::string& name) const {
6573
auto var = FindVarLocally(name);
6674
if (var != nullptr) {
6775
return var;
6876
}
69-
return (parent_ == nullptr) ? nullptr : parent_->FindVar(name);
77+
return (parent_ == nullptr) ? nullptr : parent_->FindVarInternal(name);
7078
}
7179

7280
const Scope* Scope::FindScope(const Variable* var) const {
@@ -78,6 +86,7 @@ const Scope* Scope::FindScope(const Variable* var) const {
7886
return (parent_ == nullptr) ? nullptr : parent_->FindScope(var);
7987
}
8088
void Scope::DropKids() {
89+
std::unique_lock<std::mutex> lock(mutex_);
8190
for (Scope* s : kids_) delete s;
8291
kids_.clear();
8392
}
@@ -105,6 +114,7 @@ void Scope::DeleteScope(Scope* scope) const {
105114
}
106115

107116
void Scope::EraseVars(const std::vector<std::string>& var_names) {
117+
std::unique_lock<std::mutex> lock(mutex_);
108118
std::set<std::string> var_set(var_names.begin(), var_names.end());
109119
for (auto it = vars_.begin(); it != vars_.end();) {
110120
if (var_set.find(it->first) != var_set.end()) {

paddle/fluid/framework/scope.h

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,20 @@ class Scope {
8181
// Rename variable to a new name and return the new name
8282
std::string Rename(const std::string& origin_name) const;
8383

84-
/// Caller doesn't own the returned Variable.
85-
Variable* FindVarLocally(const std::string& name) const;
86-
8784
private:
8885
// Call Scope::NewScope for a sub-scope.
8986
explicit Scope(Scope const* parent) : parent_(parent) {}
9087

88+
// Called by FindVar recursively.
89+
// Caller doesn't own the returned Variable.
90+
Variable* FindVarInternal(const std::string& name) const;
91+
92+
// Called by FindVarInternal and Var.
93+
// Caller doesn't own the returned Variable.
94+
Variable* FindVarLocally(const std::string& name) const;
95+
9196
mutable std::unordered_map<std::string, std::unique_ptr<Variable>> vars_;
97+
9298
// Scope in `kids_` are owned by this class.
9399
mutable std::list<Scope*> kids_;
94100
Scope const* parent_{nullptr};

paddle/fluid/inference/tests/book/test_inference_nlp.cc

Lines changed: 26 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -101,23 +101,22 @@ void SplitData(
101101
}
102102

103103
void ThreadRunInfer(
104-
const int tid, paddle::framework::Executor* executor,
105-
paddle::framework::Scope* scope,
106-
const std::unique_ptr<paddle::framework::ProgramDesc>& inference_program,
104+
const int tid, paddle::framework::Scope* scope,
107105
const std::vector<std::vector<const paddle::framework::LoDTensor*>>& jobs) {
108-
auto copy_program = std::unique_ptr<paddle::framework::ProgramDesc>(
109-
new paddle::framework::ProgramDesc(*inference_program));
106+
// maybe framework:ProgramDesc is not thread-safe
110107
auto& sub_scope = scope->NewScope();
108+
auto place = paddle::platform::CPUPlace();
109+
auto executor = paddle::framework::Executor(place);
110+
auto inference_program =
111+
paddle::inference::Load(&executor, scope, FLAGS_model_path);
111112

112-
std::string feed_holder_name = "feed_" + paddle::string::to_string(tid);
113-
std::string fetch_holder_name = "fetch_" + paddle::string::to_string(tid);
114-
copy_program->SetFeedHolderName(feed_holder_name);
115-
copy_program->SetFetchHolderName(fetch_holder_name);
113+
auto ctx = executor.Prepare(*inference_program, /*block_id*/ 0);
114+
executor.CreateVariables(*inference_program, &sub_scope, /*block_id*/ 0);
116115

117116
const std::vector<std::string>& feed_target_names =
118-
copy_program->GetFeedTargetNames();
117+
inference_program->GetFeedTargetNames();
119118
const std::vector<std::string>& fetch_target_names =
120-
copy_program->GetFetchTargetNames();
119+
inference_program->GetFetchTargetNames();
121120

122121
PADDLE_ENFORCE_EQ(fetch_target_names.size(), 1UL);
123122
std::map<std::string, paddle::framework::LoDTensor*> fetch_targets;
@@ -131,9 +130,8 @@ void ThreadRunInfer(
131130
auto start_ms = GetCurrentMs();
132131
for (size_t i = 0; i < inputs.size(); ++i) {
133132
feed_targets[feed_target_names[0]] = inputs[i];
134-
executor->Run(*copy_program, &sub_scope, &feed_targets, &fetch_targets,
135-
true /*create_local_scope*/, true /*create_vars*/,
136-
feed_holder_name, fetch_holder_name);
133+
executor.RunPreparedContext(ctx.get(), &sub_scope, &feed_targets,
134+
&fetch_targets, false /*create_local_scope*/);
137135
}
138136
auto stop_ms = GetCurrentMs();
139137
scope->DeleteScope(&sub_scope);
@@ -158,22 +156,10 @@ TEST(inference, nlp) {
158156
LOG(INFO) << "Number of samples (seq_len<1024): " << datasets.size();
159157
LOG(INFO) << "Total number of words: " << num_total_words;
160158

161-
const bool model_combined = false;
162159
// 0. Call `paddle::framework::InitDevices()` initialize all the devices
163-
// 1. Define place, executor, scope
164-
auto place = paddle::platform::CPUPlace();
165-
auto executor = paddle::framework::Executor(place);
166160
std::unique_ptr<paddle::framework::Scope> scope(
167161
new paddle::framework::Scope());
168162

169-
// 2. Initialize the inference_program and load parameters
170-
std::unique_ptr<paddle::framework::ProgramDesc> inference_program;
171-
inference_program =
172-
InitProgram(&executor, scope.get(), FLAGS_model_path, model_combined);
173-
if (FLAGS_use_mkldnn) {
174-
EnableMKLDNN(inference_program);
175-
}
176-
177163
#ifdef PADDLE_WITH_MKLML
178164
// only use 1 thread number per std::thread
179165
omp_set_dynamic(0);
@@ -189,21 +175,30 @@ TEST(inference, nlp) {
189175
start_ms = GetCurrentMs();
190176
for (int i = 0; i < FLAGS_num_threads; ++i) {
191177
threads.emplace_back(
192-
new std::thread(ThreadRunInfer, i, &executor, scope.get(),
193-
std::ref(inference_program), std::ref(jobs)));
178+
new std::thread(ThreadRunInfer, i, scope.get(), std::ref(jobs)));
194179
}
195180
for (int i = 0; i < FLAGS_num_threads; ++i) {
196181
threads[i]->join();
197182
}
198183
stop_ms = GetCurrentMs();
199184
} else {
200-
if (FLAGS_prepare_vars) {
201-
executor.CreateVariables(*inference_program, scope.get(), 0);
185+
// 1. Define place, executor, scope
186+
auto place = paddle::platform::CPUPlace();
187+
auto executor = paddle::framework::Executor(place);
188+
189+
// 2. Initialize the inference_program and load parameters
190+
std::unique_ptr<paddle::framework::ProgramDesc> inference_program;
191+
inference_program = InitProgram(&executor, scope.get(), FLAGS_model_path,
192+
/*model combined*/ false);
193+
if (FLAGS_use_mkldnn) {
194+
EnableMKLDNN(inference_program);
202195
}
203196
// always prepare context
204197
std::unique_ptr<paddle::framework::ExecutorPrepareContext> ctx;
205198
ctx = executor.Prepare(*inference_program, 0);
206-
199+
if (FLAGS_prepare_vars) {
200+
executor.CreateVariables(*inference_program, scope.get(), 0);
201+
}
207202
// preapre fetch
208203
const std::vector<std::string>& fetch_target_names =
209204
inference_program->GetFetchTargetNames();

0 commit comments

Comments
 (0)