Created
May 1, 2018 18:36
-
-
Save jamesob/88f7cf082ee0bf97a2411bf8bd120594 to your computer and use it in GitHub Desktop.
diff -uw <(git diff master..threadnames.1) <(git diff master..threadnames.3)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
--- /proc/self/fd/15 2018-05-01 14:36:17.343988635 -0400 | |
+++ /proc/self/fd/16 2018-05-01 14:36:17.343988635 -0400 | |
@@ -196,10 +196,14 @@ | |
qt/test/wallettests.cpp \ | |
wallet/test/wallet_test_fixture.cpp | |
diff --git a/src/Makefile.test.include b/src/Makefile.test.include | |
-index 91d3a3d..f7eb712 100644 | |
+index 91d3a3d..40bc478 100644 | |
--- a/src/Makefile.test.include | |
+++ b/src/Makefile.test.include | |
-@@ -83,7 +83,6 @@ BITCOIN_TESTS =\ | |
+@@ -80,10 +80,10 @@ BITCOIN_TESTS =\ | |
+ test/sigopcount_tests.cpp \ | |
+ test/skiplist_tests.cpp \ | |
+ test/streams_tests.cpp \ | |
++ test/threadnames_tests.cpp \ | |
test/timedata_tests.cpp \ | |
test/torcontrol_tests.cpp \ | |
test/transaction_tests.cpp \ | |
@@ -1990,6 +1994,128 @@ | |
BOOST_CHECK(!isInvalid); | |
} | |
+diff --git a/src/test/threadnames_tests.cpp b/src/test/threadnames_tests.cpp | |
+new file mode 100644 | |
+index 0000000..a97cd08 | |
+--- /dev/null | |
++++ b/src/test/threadnames_tests.cpp | |
+@@ -0,0 +1,116 @@ | |
++// Copyright (c) 2018 The Bitcoin Core developers | |
++// Distributed under the MIT software license, see the accompanying | |
++// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
++ | |
++#include <threadnames.h> | |
++#include <test/test_bitcoin.h> | |
++ | |
++#include <thread> | |
++#include <vector> | |
++#include <set> | |
++#include <mutex> | |
++ | |
++#include <boost/test/unit_test.hpp> | |
++ | |
++BOOST_FIXTURE_TEST_SUITE(threadnames_tests, BasicTestingSetup) | |
++ | |
++BOOST_AUTO_TEST_CASE(threadnames_test_process_rename_serial) | |
++{ | |
++ ThreadNameRegistry reg; | |
++ | |
++ std::string original_process_name = reg.GetProcessName(); | |
++ | |
++ reg.RenameProcess("bazzz"); | |
++ BOOST_CHECK_EQUAL(reg.GetProcessName(), "bazzz"); | |
++ reg.RenameProcess("barrr"); | |
++ BOOST_CHECK_EQUAL(reg.GetProcessName(), "barrr"); | |
++ | |
++ reg.RenameProcess(original_process_name.c_str()); | |
++ BOOST_CHECK_EQUAL(reg.GetProcessName(), original_process_name); | |
++} | |
++ | |
++/** | |
++ * Ensure that expect_multiple prevents collisions by appending a numeric suffix. | |
++ */ | |
++BOOST_AUTO_TEST_CASE(threadnames_test_rename_multiple_serial) | |
++{ | |
++ ThreadNameRegistry reg; | |
++ | |
++ std::string original_process_name = reg.GetProcessName(); | |
++ | |
++ BOOST_CHECK(reg.Rename("foo", /*expect_multiple=*/ true)); | |
++ BOOST_CHECK_EQUAL(reg.GetName(), "foo.0"); | |
++ | |
++ // Can't rename to "foo" as that would be a collision. | |
++ BOOST_CHECK_EQUAL(reg.Rename("foo", /*expect_multiple=*/ false), false); | |
++ BOOST_CHECK_EQUAL(reg.GetName(), "foo.0"); | |
++ | |
++ BOOST_CHECK(reg.Rename("foo", /*expect_multiple=*/ true)); | |
++ BOOST_CHECK_EQUAL(reg.GetName(), "foo.1"); | |
++ | |
++ BOOST_CHECK(reg.Rename("foo", /*expect_multiple=*/ true)); | |
++ BOOST_CHECK_EQUAL(reg.GetName(), "foo.2"); | |
++ | |
++ reg.RenameProcess(original_process_name.c_str()); | |
++ BOOST_CHECK_EQUAL(reg.GetProcessName(), original_process_name); | |
++} | |
++ | |
++/** | |
++ * Run a bunch of threads to all call Rename with some parameters. | |
++ * | |
++ * @return the set of name each thread has after attempted renaming. | |
++ */ | |
++std::set<std::string> RenameEnMasse(int num_threads, bool expect_multiple) | |
++{ | |
++ ThreadNameRegistry reg; | |
++ std::vector<std::thread> threads; | |
++ std::set<std::string> names; | |
++ std::mutex lock; | |
++ | |
++ auto RenameThisThread = [&]() { | |
++ reg.Rename("test_thread", /*expect_multiple=*/ expect_multiple); | |
++ std::lock_guard<std::mutex> guard(lock); | |
++ names.insert(reg.GetName()); | |
++ }; | |
++ | |
++ for (int i = 0; i < num_threads; ++i) { | |
++ threads.push_back(std::thread(RenameThisThread)); | |
++ } | |
++ | |
++ for (std::thread& thread : threads) thread.join(); | |
++ | |
++ return names; | |
++} | |
++ | |
++/** | |
++ * Rename a bunch of threads with the same basename (expect_multiple=true), ensuring suffixes are | |
++ * applied properly. | |
++ */ | |
++BOOST_AUTO_TEST_CASE(threadnames_test_rename_multiple_threaded) | |
++{ | |
++ std::set<std::string> names = RenameEnMasse(100, true); | |
++ | |
++ BOOST_CHECK_EQUAL(names.size(), 100); | |
++ | |
++ // Names "test_thread.[n]" should exist for n = [0, 99] | |
++ for (int i = 0; i < 100; ++i) { | |
++ BOOST_CHECK(names.find("test_thread." + std::to_string(i)) != names.end()); | |
++ } | |
++ | |
++} | |
++ | |
++/** | |
++ * Rename a bunch of threads with the same basename (expect_multiple=false), ensuring only one | |
++ * rename succeeds. | |
++ */ | |
++BOOST_AUTO_TEST_CASE(threadnames_test_rename_threaded) | |
++{ | |
++ std::set<std::string> names = RenameEnMasse(100, false); | |
++ | |
++ // Only one thread's Rename should have succeeded for the same name. | |
++ BOOST_CHECK_EQUAL(names.count("test_thread"), 1); | |
++ BOOST_CHECK_EQUAL(names.size(), 2); // test_thread and test_bitcoin (name of parent thread) | |
++ | |
++} | |
++ | |
++BOOST_AUTO_TEST_SUITE_END() | |
diff --git a/src/test/txindex_tests.cpp b/src/test/txindex_tests.cpp | |
deleted file mode 100644 | |
index 14158f2..0000000 | |
@@ -2089,10 +2215,10 @@ | |
void reset(); | |
diff --git a/src/threadnames.cpp b/src/threadnames.cpp | |
new file mode 100644 | |
-index 0000000..d044825 | |
+index 0000000..305c3b4 | |
--- /dev/null | |
+++ b/src/threadnames.cpp | |
-@@ -0,0 +1,147 @@ | |
+@@ -0,0 +1,135 @@ | |
+// Copyright (c) 2018 The Bitcoin Core developers | |
+// Distributed under the MIT software license, see the accompanying | |
+// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
@@ -2100,7 +2226,13 @@ | |
+#include <threadnames.h> | |
+#include <tinyformat.h> | |
+ | |
++#include <atomic> | |
++#include <cstdint> | |
++#include <string> | |
++ | |
++#if !defined(HAVE_THREAD_LOCAL) | |
+#include <boost/thread.hpp> | |
++#endif | |
+ | |
+#if defined(HAVE_CONFIG_H) | |
+#include <config/bitcoin-config.h> // For HAVE_SYS_PRCTL_H | |
@@ -2120,75 +2252,57 @@ | |
+ | |
+std::unique_ptr<ThreadNameRegistry> g_thread_names(new ThreadNameRegistry()); | |
+ | |
-+namespace { | |
-+ | |
-+/** | |
-+ * @return true if `to_check` is prefixed with `prefix`. | |
-+ */ | |
-+bool HasPrefix(const std::string& to_check, const std::string& prefix) { | |
-+ return to_check.compare(0, prefix.size(), prefix) == 0; | |
-+} | |
-+ | |
-+/** | |
-+ * Count the number of entries in a map with a given prefix. | |
-+ * | |
-+ * @return The number of occurrences of keys with the given prefix. | |
-+ */ | |
-+template <class T> | |
-+int CountMapPrefixes(T map, const std::string& prefix) { | |
-+ auto it = map.lower_bound(prefix); | |
-+ int count = 0; | |
-+ | |
-+ while (it != map.end() && HasPrefix(it->first, prefix)) { | |
-+ ++it; ++count; | |
-+ } | |
+ | |
-+ return count; | |
++std::string ThreadNameRegistry::GetId() | |
++{ | |
++#if !defined(HAVE_THREAD_LOCAL) | |
++ // Fall back to boost when we don't have thread_local available. | |
++ // | |
++ // See: https://github.com/bitcoin/bitcoin/pull/11722#pullrequestreview-79322658 | |
++ // | |
++ std::stringstream temp; // stringstream use necessary to get thread_id into a string. | |
++ temp << boost::this_thread::get_id(); | |
++ return temp.str(); | |
++#else | |
++ // Otherwise, an ID is computed once and cached per thread. | |
++ // | |
++ static std::atomic<std::uint32_t> uid{0}; | |
++ static thread_local std::string this_id = std::to_string(uid++); | |
++ return this_id; | |
++#endif | |
+} | |
+ | |
-+} // namespace | |
-+ | |
+bool ThreadNameRegistry::Rename(std::string name, bool expect_multiple) | |
+{ | |
+ std::lock_guard<std::mutex> guard(m_map_lock); | |
++ std::string name_without_suffix = name; | |
+ | |
+ if (expect_multiple) { | |
-+ name = tfm::format("%s.%d", name, CountMapPrefixes(m_name_to_id, name)); | |
++ name = tfm::format("%s.%d", name_without_suffix, m_name_to_count[name_without_suffix]); | |
+ } | |
+ | |
-+ std::string process_name(name); | |
-+ | |
-+ /* | |
-+ * Uncomment if we want to retain the `bitcoin-` system thread name prefix. | |
-+ * | |
-+ const std::string process_prefix("bitcoin-"); | |
-+ if (!HasPrefix(process_name, process_prefix)) { | |
-+ process_name = process_prefix + process_name; | |
-+ } | |
-+ */ | |
-+ | |
-+ RenameProcess(process_name.c_str()); | |
++ std::string thread_id = GetId(); | |
++ std::string process_name = name; | |
+ | |
-+ auto thread_id = boost::this_thread::get_id(); | |
-+ auto it_name = m_name_to_id.find(name); | |
++ auto it_name = m_name_to_count.find(name); | |
+ auto it_id = m_id_to_name.find(thread_id); | |
+ | |
+ // Don't allow name collisions. | |
-+ if (it_name != m_name_to_id.end() && it_name->second != thread_id) { | |
-+ std::stringstream errmsg; // stringstream use necessary to get thread_id into a string. | |
-+ errmsg << "Thread name '" << name << "' already registered (id: " << it_name->second << ")\n"; | |
-+ LogPrintStr(errmsg.str()); | |
++ if (it_name != m_name_to_count.end()) { | |
++ LogPrintStr(tfm::format("Thread name '%s' already registered", name)); | |
+ return false; | |
+ } | |
+ // Warn on reregistration. | |
+ else if (it_id != m_id_to_name.end()) { | |
-+ std::stringstream warnmsg; | |
-+ warnmsg << "Reregistering thread " << thread_id << " with name '%s'; previously was '%s'\n"; | |
-+ LogPrintStr(tfm::format(warnmsg.str().c_str(), name, it_id->second)); | |
++ LogPrintStr(tfm::format( | |
++ "Reregistering thread %s with name '%s'; previously was '%s'\n", | |
++ thread_id, name, it_id->second)); | |
+ } | |
+ | |
++ RenameProcess(process_name.c_str()); | |
+ m_id_to_name[thread_id] = name; | |
-+ m_name_to_id[name] = thread_id; | |
++ m_name_to_count[name_without_suffix]++; | |
++ | |
+ return true; | |
+} | |
+ | |
@@ -2196,7 +2310,7 @@ | |
+{ | |
+ std::lock_guard<std::mutex> guard(m_map_lock); | |
+ | |
-+ auto thread_id = boost::this_thread::get_id(); | |
++ auto thread_id = GetId(); | |
+ auto found = m_id_to_name.find(thread_id); | |
+ | |
+ if (found != m_id_to_name.end()) { | |
@@ -2204,7 +2318,7 @@ | |
+ } | |
+ | |
+ std::string pname = GetProcessName(); | |
-+ m_name_to_id[pname] = thread_id; | |
++ ++m_name_to_count[pname]; | |
+ m_id_to_name[thread_id] = pname; | |
+ return pname; | |
+} | |
@@ -2242,10 +2356,10 @@ | |
+} | |
diff --git a/src/threadnames.h b/src/threadnames.h | |
new file mode 100644 | |
-index 0000000..4073490 | |
+index 0000000..10b2ca2 | |
--- /dev/null | |
+++ b/src/threadnames.h | |
-@@ -0,0 +1,55 @@ | |
+@@ -0,0 +1,64 @@ | |
+// Copyright (c) 2018 The Bitcoin Core developers | |
+// Distributed under the MIT software license, see the accompanying | |
+// file COPYING or http://www.opensource.org/licenses/mit-license.php. | |
@@ -2254,10 +2368,9 @@ | |
+#define BITCOIN_THREADNAMES_H | |
+ | |
+#include <map> | |
++#include <memory> | |
+#include <mutex> | |
+ | |
-+#include <boost/thread.hpp> | |
-+ | |
+ | |
+/** | |
+ * Keeps a map of thread IDs to string names and handles system-level thread naming. | |
@@ -2292,10 +2405,20 @@ | |
+ */ | |
+ std::string GetProcessName(); | |
+ | |
++ /** | |
++ * @return a unique identifier for the calling thread. | |
++ */ | |
++ std::string GetId(); | |
++ | |
+private: | |
+ std::mutex m_map_lock; | |
-+ std::map<boost::thread::id, std::string> m_id_to_name; | |
-+ std::map<std::string, boost::thread::id> m_name_to_id; | |
++ std::map<std::string, std::string> m_id_to_name; | |
++ /** | |
++ * The number of times this name has been used to identify a thread; | |
++ * used to generate numeric suffix. | |
++ */ | |
++ std::map<std::string, size_t> m_name_to_count; | |
++ | |
+}; | |
+ | |
+extern std::unique_ptr<ThreadNameRegistry> g_thread_names; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment