Skip to content

Commit 53ff81d

Browse files
authored
Merge pull request #3066 from stan-dev/fix/profile-data-race
use tbb::concurrent_unordered_map instead of std::map
2 parents b47928d + 452ad8e commit 53ff81d

File tree

2 files changed

+30
-12
lines changed

2 files changed

+30
-12
lines changed

stan/math/rev/core/profiling.hpp

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <stan/math/rev/meta.hpp>
88
#include <stan/math/rev/fun/value_of.hpp>
99
#include <stan/math/prim/err.hpp>
10+
#include <tbb/concurrent_unordered_map.h>
1011
#include <iostream>
1112
#include <sstream>
1213
#include <thread>
@@ -115,7 +116,24 @@ class profile_info {
115116

116117
using profile_key = std::pair<std::string, std::thread::id>;
117118

118-
using profile_map = std::map<profile_key, profile_info>;
119+
namespace internal {
120+
struct hash_profile_key {
121+
std::size_t operator()(const profile_key& key) const {
122+
return std::hash<std::string>()(key.first)
123+
^ std::hash<std::thread::id>()(key.second);
124+
}
125+
};
126+
struct equal_profile_key {
127+
bool operator()(const profile_key& lhs, const profile_key& rhs) const {
128+
return lhs.first == rhs.first && lhs.second == rhs.second;
129+
}
130+
};
131+
132+
} // namespace internal
133+
134+
using profile_map = tbb::concurrent_unordered_map<profile_key, profile_info,
135+
internal::hash_profile_key,
136+
internal::equal_profile_key>;
119137

120138
/**
121139
* Profiles C++ lines where the object is in scope.

test/unit/math/rev/core/profiling_test.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,31 @@
66
TEST(Profiling, double_basic) {
77
using stan::math::profile;
88
using stan::math::var;
9-
stan::math::profile_map profiles;
9+
stan::math::profile_map prof_map;
1010
double a = 3.0, b = 2.0, c;
1111
{
12-
profile<double> p1("p1", profiles);
12+
profile<double> p1("p1", prof_map);
1313
c = log(exp(a)) * log(exp(b));
1414
std::chrono::milliseconds timespan(10);
1515
std::this_thread::sleep_for(timespan);
1616
}
1717
{
18-
profile<int> p1("p1", profiles);
18+
profile<int> p1("p1", prof_map);
1919
c = log(exp(a)) * log(exp(b));
2020
std::chrono::milliseconds timespan(10);
2121
std::this_thread::sleep_for(timespan);
2222
}
2323

2424
stan::math::profile_key key = {"p1", std::this_thread::get_id()};
2525
EXPECT_NEAR(c, 6.0, 1E-8);
26-
EXPECT_EQ(profiles[key].get_chain_stack_used(), 0);
27-
EXPECT_EQ(profiles[key].get_nochain_stack_used(), 0);
28-
EXPECT_FLOAT_EQ(profiles[key].get_rev_time(), 0.0);
29-
EXPECT_EQ(profiles[key].get_num_rev_passes(), 0);
30-
EXPECT_EQ(profiles[key].get_num_fwd_passes(), 2);
31-
EXPECT_EQ(profiles[key].get_num_no_AD_fwd_passes(), 2);
32-
EXPECT_EQ(profiles[key].get_num_AD_fwd_passes(), 0);
33-
EXPECT_TRUE(profiles[key].get_fwd_time() > 0.0);
26+
EXPECT_EQ(prof_map[key].get_chain_stack_used(), 0);
27+
EXPECT_EQ(prof_map[key].get_nochain_stack_used(), 0);
28+
EXPECT_FLOAT_EQ(prof_map[key].get_rev_time(), 0.0);
29+
EXPECT_EQ(prof_map[key].get_num_rev_passes(), 0);
30+
EXPECT_EQ(prof_map[key].get_num_fwd_passes(), 2);
31+
EXPECT_EQ(prof_map[key].get_num_no_AD_fwd_passes(), 2);
32+
EXPECT_EQ(prof_map[key].get_num_AD_fwd_passes(), 0);
33+
EXPECT_TRUE(prof_map[key].get_fwd_time() > 0.0);
3434
}
3535

3636
TEST(Profiling, var_basic) {

0 commit comments

Comments
 (0)