common: cache pthread names

This provides common ceph entrypoints for the pthread_[gs]name functions which
will also cache a thread_local copy. This also removes the pthread_t parameter
which precipitated the bug i50743.

Obviously, the overall goal here is to avoid system calls.

See-also: https://tracker.ceph.com/issues/50743
Fixes: 0be8d01c9d
Fixes: https://tracker.ceph.com/issues/68691
Signed-off-by: Patrick Donnelly <pdonnell@ibm.com>
This commit is contained in:
Patrick Donnelly 2024-10-23 23:16:03 -04:00
parent 1f40d0c06c
commit 7de5af59c2
No known key found for this signature in database
GPG Key ID: FA47FD0B0367D313
25 changed files with 102 additions and 134 deletions

View File

@ -81,7 +81,7 @@ static void handle_mds_signal(int signum)
int main(int argc, const char **argv)
{
ceph_pthread_setname(pthread_self(), "ceph-mds");
ceph_pthread_setname("ceph-mds");
auto args = argv_to_vec(argc, argv);
if (args.empty()) {

View File

@ -41,7 +41,7 @@ static void usage()
*/
int main(int argc, const char **argv)
{
ceph_pthread_setname(pthread_self(), "ceph-mgr");
ceph_pthread_setname("ceph-mgr");
auto args = argv_to_vec(argc, argv);
if (args.empty()) {

View File

@ -250,7 +250,7 @@ int main(int argc, const char **argv)
{
// reset our process name, in case we did a respawn, so that it's not
// left as "exe".
ceph_pthread_setname(pthread_self(), "ceph-mon");
ceph_pthread_setname("ceph-mon");
int err;

View File

@ -45,7 +45,7 @@ static void usage()
*/
int main(int argc, const char **argv)
{
ceph_pthread_setname(pthread_self(), "ceph-nvmeof-monitor-client");
ceph_pthread_setname("ceph-nvmeof-monitor-client");
auto args = argv_to_vec(argc, argv);
if (args.empty()) {

View File

@ -290,6 +290,7 @@ SyntheticClient::SyntheticClient(StandaloneClient *client, int w)
void *synthetic_client_thread_entry(void *ptr)
{
ceph_pthread_setname("client");
SyntheticClient *sc = static_cast<SyntheticClient*>(ptr);
//int r =
sc->run();
@ -945,7 +946,6 @@ int SyntheticClient::start_thread()
pthread_create(&thread_id, NULL, synthetic_client_thread_entry, this);
ceph_assert(thread_id);
ceph_pthread_setname(thread_id, "client");
return 0;
}

View File

@ -83,7 +83,7 @@ void *Thread::entry_wrapper()
if (pid && cpuid >= 0)
_set_affinity(cpuid);
ceph_pthread_setname(pthread_self(), Thread::thread_name.c_str());
ceph_pthread_setname(thread_name.c_str());
return entry();
}
@ -154,7 +154,7 @@ int Thread::try_create(size_t stacksize)
void Thread::create(const char *name, size_t stacksize)
{
ceph_assert(strlen(name) < 16);
Thread::thread_name = name;
thread_name = name;
int ret = try_create(stacksize);
if (ret != 0) {
@ -203,24 +203,6 @@ int Thread::set_affinity(int id)
// Functions for std::thread
// =========================
void set_thread_name(std::thread& t, const std::string& s) {
int r = ceph_pthread_setname(t.native_handle(), s.c_str());
if (r != 0) {
throw std::system_error(r, std::generic_category());
}
}
std::string get_thread_name(const std::thread& t) {
std::string s(256, '\0');
int r = ceph_pthread_getname(const_cast<std::thread&>(t).native_handle(),
s.data(), s.length());
if (r != 0) {
throw std::system_error(r, std::generic_category());
}
s.resize(std::strlen(s.data()));
return s;
}
void kill(std::thread& t, int signal)
{
auto r = ceph_pthread_kill(t.native_handle(), signal);

View File

@ -27,7 +27,6 @@
#include "include/ceph_assert.h"
#include "include/compat.h"
#include "include/spinlock.h"
extern pid_t ceph_gettid();
@ -36,7 +35,7 @@ class Thread {
pthread_t thread_id;
pid_t pid;
int cpuid;
static inline thread_local std::string thread_name;
std::string thread_name;
void *entry_wrapper();
@ -64,15 +63,10 @@ class Thread {
int join(void **prval = 0);
int detach();
int set_affinity(int cpuid);
static const std::string get_thread_name() {
return Thread::thread_name;
}
};
// Functions for with std::thread
void set_thread_name(std::thread& t, const std::string& s);
std::string get_thread_name(const std::thread& t);
void kill(std::thread& t, int signal);
template<typename Fun, typename... Args>
@ -81,7 +75,7 @@ std::thread make_named_thread(std::string_view n,
Args&& ...args) {
return std::thread([n = std::string(n)](auto&& fun, auto&& ...args) {
ceph_pthread_setname(pthread_self(), n.data());
ceph_pthread_setname(n.data());
std::invoke(std::forward<Fun>(fun),
std::forward<Args>(args)...);
}, std::forward<Fun>(fun), std::forward<Args>(args)...);

View File

@ -44,8 +44,7 @@ namespace ceph {
g_assert_line = line;
g_assert_func = func;
g_assert_thread = (unsigned long long)pthread_self();
ceph_pthread_getname(pthread_self(), g_assert_thread_name,
sizeof(g_assert_thread_name));
ceph_pthread_getname(g_assert_thread_name, sizeof(g_assert_thread_name));
ostringstream tss;
tss << ceph_clock_now();
@ -122,8 +121,7 @@ namespace ceph {
g_assert_line = line;
g_assert_func = func;
g_assert_thread = (unsigned long long)pthread_self();
ceph_pthread_getname(pthread_self(), g_assert_thread_name,
sizeof(g_assert_thread_name));
ceph_pthread_getname(g_assert_thread_name, sizeof(g_assert_thread_name));
BufAppender ba(g_assert_msg, sizeof(g_assert_msg));
BackTrace *bt = new ClibBackTrace(1);
@ -168,8 +166,7 @@ namespace ceph {
g_assert_line = line;
g_assert_func = func;
g_assert_thread = (unsigned long long)pthread_self();
ceph_pthread_getname(pthread_self(), g_assert_thread_name,
sizeof(g_assert_thread_name));
ceph_pthread_getname(g_assert_thread_name, sizeof(g_assert_thread_name));
BackTrace *bt = new ClibBackTrace(1);
snprintf(g_assert_msg, sizeof(g_assert_msg),
@ -210,8 +207,7 @@ namespace ceph {
g_assert_line = line;
g_assert_func = func;
g_assert_thread = (unsigned long long)pthread_self();
ceph_pthread_getname(pthread_self(), g_assert_thread_name,
sizeof(g_assert_thread_name));
ceph_pthread_getname(g_assert_thread_name, sizeof(g_assert_thread_name));
BufAppender ba(g_assert_msg, sizeof(g_assert_msg));
BackTrace *bt = new ClibBackTrace(1);

View File

@ -98,6 +98,7 @@ class timer {
std::thread thread;
void timer_thread() {
ceph_pthread_setname("ceph_timer");
std::unique_lock l(lock);
while (!suspended) {
auto now = TC::now();
@ -155,7 +156,6 @@ class timer {
public:
timer() : suspended(false) {
thread = std::thread(&timer::timer_thread, this);
set_thread_name(thread, "ceph_timer");
}
// Create a suspended timer, jobs will be executed in order when

View File

@ -11,6 +11,7 @@
* Foundation. See file COPYING.
*
*/
#include "include/compat.h"
#include "common/code_environment.h"
@ -18,10 +19,6 @@
#include "acconfig.h"
#ifdef HAVE_PTHREAD_GETNAME_NP
#include <pthread.h>
#endif
#include <string.h>
code_environment_t g_code_env = CODE_ENVIRONMENT_UTILITY;
@ -57,7 +54,7 @@ int get_process_name(char *buf, int len)
}
// FIPS zeroization audit 20191115: this memset is not security related.
memset(buf, 0, len);
return pthread_getname_np(pthread_self(), buf, len);
return ceph_pthread_getname(buf, len);
}
#elif defined(HAVE_GETPROGNAME)

View File

@ -565,3 +565,66 @@ ssize_t get_self_exe_path(char* path, int buff_length) {
}
#endif /* _WIN32 */
static thread_local char cached_thread_name[256]{};
int ceph_pthread_setname(char const* name)
{
strncpy(cached_thread_name, name, sizeof cached_thread_name - 1);
#if defined(_WIN32) && defined(__clang__) && \
!defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
// In this case, llvm doesn't use the pthread api for std::thread.
// We cannot use native_handle() with the pthread api, nor can we pass
// it to Windows API functions.
return 0;
#elif defined(HAVE_PTHREAD_SETNAME_NP)
#if defined(__APPLE__)
return pthread_setname_np(name);
#else
return pthread_setname_np(pthread_self(), name);
#endif
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
pthread_set_name_np(pthread_self(), name); \
return 0;
#else
return 0;
#endif
}
int ceph_pthread_getname(char* name, size_t len)
{
if (cached_thread_name[0]) {
if (len > 0) {
strncpy(name, cached_thread_name, len);
name[len-1] = 0;
}
return 0;
} else {
#if defined(_WIN32) && defined(__clang__) && \
!defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
if (len > 0) {
strcpy(name, "");
}
return 0;
#elif defined(HAVE_PTHREAD_GETNAME_NP) || defined(HAVE_PTHREAD_GET_NAME_NP)
# if defined(HAVE_PTHREAD_GETNAME_NP)
int rc = pthread_getname_np(pthread_self(), cached_thread_name, sizeof cached_thread_name);
# else
int rc = pthread_get_name_np(pthread_self(), cached_thread_name, sizeof cached_thread_name);
# endif
if (rc == 0) {
strncpy(name, cached_thread_name, len);
name[len-1] = 0;
return 0;
} else {
return rc;
}
#else
if (len > 0) {
strcpy(name, "");
}
return 0;
#endif
}
}

View File

@ -99,6 +99,7 @@ ostream& ObjBencher::out(ostream& os)
}
void *ObjBencher::status_printer(void *_bencher) {
ceph_pthread_setname("OB::stat_print");
ObjBencher *bencher = static_cast<ObjBencher *>(_bencher);
bench_data& data = bencher->data;
Formatter *formatter = bencher->formatter;
@ -453,7 +454,6 @@ int ObjBencher::write_bench(int secondsToRun,
pthread_t print_thread;
pthread_create(&print_thread, NULL, ObjBencher::status_printer, (void *)this);
ceph_pthread_setname(print_thread, "write_stat");
std::unique_lock locker{lock};
data.finished = 0;
data.start_time = mono_clock::now();
@ -691,7 +691,6 @@ int ObjBencher::seq_read_bench(
pthread_t print_thread;
pthread_create(&print_thread, NULL, status_printer, (void *)this);
ceph_pthread_setname(print_thread, "seq_read_stat");
mono_time finish_time = data.start_time + time_to_run;
//start initial reads
@ -903,7 +902,6 @@ int ObjBencher::rand_read_bench(
pthread_t print_thread;
pthread_create(&print_thread, NULL, status_printer, (void *)this);
ceph_pthread_setname(print_thread, "rand_read_stat");
mono_time finish_time = data.start_time + time_to_run;
//start initial reads

View File

@ -27,7 +27,7 @@ ThreadPool::ThreadPool(size_t n_threads,
pin(*cpus);
}
block_sighup();
(void) pthread_setname_np(pthread_self(), "alien-store-tp");
(void) ceph_pthread_setname("alien-store-tp");
loop(queue_max_wait, i);
});
}

View File

@ -307,7 +307,7 @@ static void handle_oneshot_fatal_signal(int signum)
char buf[1024];
char pthread_name[16] = {0}; //limited by 16B include terminating null byte.
int r = ceph_pthread_getname(pthread_self(), pthread_name, sizeof(pthread_name));
int r = ceph_pthread_getname(pthread_name, sizeof(pthread_name));
(void)r;
#if defined(__sun)
char message[SIG2STR_MAX];

View File

@ -179,58 +179,10 @@ struct cpu_set_t;
#define MSG_DONTWAIT MSG_NONBLOCK
#endif
/* compiler warning free success noop */
#define pthread_setname_noop_helper(thread, name) ({ \
int __i = 0; \
__i; })
#define pthread_getname_noop_helper(thread, name, len) ({ \
if (name != NULL) \
*name = '\0'; \
0; })
#define pthread_kill_unsupported_helper(thread, signal) ({ \
int __i = -ENOTSUP; \
__i; })
#if defined(_WIN32) && defined(__clang__) && \
!defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
// In this case, llvm doesn't use the pthread api for std::thread.
// We cannot use native_handle() with the pthread api, nor can we pass
// it to Windows API functions.
#define ceph_pthread_setname pthread_setname_noop_helper
#elif defined(HAVE_PTHREAD_SETNAME_NP)
#if defined(__APPLE__)
#define ceph_pthread_setname(thread, name) ({ \
int __result = 0; \
if (thread == pthread_self()) \
__result = pthread_setname_np(name); \
__result; })
#else
#define ceph_pthread_setname pthread_setname_np
#endif
#elif defined(HAVE_PTHREAD_SET_NAME_NP)
/* Fix a small name diff and return 0 */
#define ceph_pthread_setname(thread, name) ({ \
pthread_set_name_np(thread, name); \
0; })
#else
#define ceph_pthread_setname pthread_setname_noop_helper
#endif
#if defined(_WIN32) && defined(__clang__) && \
!defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
#define ceph_pthread_getname pthread_getname_noop_helper
#elif defined(HAVE_PTHREAD_GETNAME_NP)
#define ceph_pthread_getname pthread_getname_np
#elif defined(HAVE_PTHREAD_GET_NAME_NP)
#define ceph_pthread_getname(thread, name, len) ({ \
pthread_get_name_np(thread, name, len); \
0; })
#else
#define ceph_pthread_getname pthread_getname_noop_helper
#endif
#if defined(_WIN32) && defined(__clang__) && \
!defined(_LIBCPP_HAS_THREAD_API_PTHREAD)
#define ceph_pthread_kill pthread_kill_unsupported_helper
@ -244,6 +196,9 @@ int ceph_posix_fallocate(int fd, off_t offset, off_t len);
extern "C" {
#endif
int ceph_pthread_getname(char* name, size_t size);
int ceph_pthread_setname(const char* name);
int pipe_cloexec(int pipefd[2], int flags);
char *ceph_strerror_r(int errnum, char *buf, size_t buflen);
unsigned get_page_size();

View File

@ -24,6 +24,7 @@ namespace logging {
class Entry {
public:
using time = log_time;
using thread_name_t = std::array<char, 16>;
Entry() = delete;
Entry(short pr, short sub) :
@ -32,8 +33,7 @@ public:
m_prio(pr),
m_subsys(sub)
{
strncpy(m_thread_name, Thread::get_thread_name().data(), 16);
m_thread_name[15] = '\0';
ceph_pthread_getname(m_thread_name.data(), m_thread_name.size());
}
Entry(const Entry &) = default;
Entry& operator=(const Entry &) = default;
@ -47,7 +47,7 @@ public:
time m_stamp;
pthread_t m_thread;
short m_prio, m_subsys;
char m_thread_name[16];
thread_name_t m_thread_name{};
static log_clock& clock() {
static log_clock clock;

View File

@ -501,7 +501,7 @@ void Log::dump_recent()
m_recent.clear();
for (const auto& e : t) {
auto& set = recent_pthread_ids[e.m_thread];
set.insert(e.m_thread_name);
set.insert(e.m_thread_name.data());
}
_flush(t, true);
}

View File

@ -74,7 +74,7 @@ void Beacon::init(const MDSMap &mdsmap)
_notify_mdsmap(mdsmap);
sender = std::thread([this]() {
ceph_pthread_setname(pthread_self(), "beacon");
ceph_pthread_setname("beacon");
std::unique_lock<std::mutex> lock(mutex);
bool sent;
while (!finished) {

View File

@ -352,7 +352,7 @@ class NetworkStack {
static constexpr int TASK_COMM_LEN = 16;
char tp_name[TASK_COMM_LEN];
sprintf(tp_name, "msgr-worker-%u", id);
ceph_pthread_setname(pthread_self(), tp_name);
ceph_pthread_setname(tp_name);
}
protected:

View File

@ -92,7 +92,6 @@ void RDMADispatcher::polling_start()
ceph_assert(rx_cq);
t = std::thread(&RDMADispatcher::polling, this);
ceph_pthread_setname(t.native_handle(), "rdma-polling");
}
void RDMADispatcher::polling_stop()
@ -263,6 +262,7 @@ int RDMADispatcher::post_chunks_to_rq(int num, QueuePair *qp)
void RDMADispatcher::polling()
{
ceph_pthread_setname("rdma-polling");
static int MAX_COMPLETIONS = 32;
ibv_wc wc[MAX_COMPLETIONS];

View File

@ -21,6 +21,7 @@
#include "common/dout.h"
#include "rgw_url.h"
#include <chrono>
#include <fmt/format.h>
#define dout_subsys ceph_subsys_rgw_notification
@ -769,9 +770,10 @@ public:
});
// start the worker threads to do the actual queue processing
const std::string WORKER_THREAD_NAME = "notif-worker";
for (auto worker_id = 0U; worker_id < worker_count; ++worker_id) {
workers.emplace_back([this]() {
workers.emplace_back([this,worker_id]() {
const auto thread_name = fmt::format("notif-worker-{}", worker_id);
ceph_pthread_setname(thread_name.c_str());
try {
io_context.run();
} catch (const std::exception& err) {
@ -779,11 +781,6 @@ public:
throw err;
}
});
const auto thread_name = WORKER_THREAD_NAME+std::to_string(worker_id);
if (const auto rc = ceph_pthread_setname(workers.back().native_handle(), thread_name.c_str()); rc != 0) {
ldpp_dout(this, 1) << "ERROR: failed to set notification manager thread name to: " << thread_name
<< ". error: " << rc << dendl;
}
}
ldpp_dout(this, 10) << "INfO: started notification manager with: " << worker_count << " workers" << dendl;
}

View File

@ -650,6 +650,9 @@ private:
// (4) TODO reconnect on connection errors
// (5) TODO cleanup timedout callbacks
void run() noexcept {
// give the runner thread a name for easier debugging
ceph_pthread_setname("amqp_manager");
amqp_frame_t frame;
while (!stopped) {
@ -838,12 +841,6 @@ public:
// This is to prevent rehashing so that iterators are not invalidated
// when a new connection is added.
connections.max_load_factor(10.0);
// give the runner thread a name for easier debugging
const char* thread_name = "amqp_manager";
if (const auto rc = ceph_pthread_setname(runner.native_handle(), thread_name); rc != 0) {
ldout(cct, 1) << "ERROR: failed to set amqp manager thread name to: " << thread_name
<< ". error: " << rc << dendl;
}
}
// non copyable

View File

@ -503,6 +503,7 @@ private:
}
void run() noexcept {
ceph_pthread_setname("kafka_manager");
while (!stopped) {
// publish all messages in the queue
@ -575,12 +576,6 @@ public:
// This is to prevent rehashing so that iterators are not invalidated
// when a new connection is added.
connections.max_load_factor(10.0);
// give the runner thread a name for easier debugging
const char* thread_name = "kafka_manager";
if (const auto rc = ceph_pthread_setname(runner.native_handle(), thread_name); rc != 0) {
ldout(cct, 1) << "ERROR: failed to set kafka manager thread name to: " << thread_name
<< ". error: " << rc << dendl;
}
}
// non copyable

View File

@ -83,11 +83,6 @@ void Background::start() {
}
started = true;
runner = std::thread(&Background::run, this);
const char* thread_name = "lua_background";
if (const auto rc = ceph_pthread_setname(runner.native_handle(), thread_name); rc != 0) {
ldout(cct, 1) << "ERROR: failed to set lua background thread name to: " << thread_name
<< ". error: " << rc << dendl;
}
}
void Background::pause() {
@ -127,6 +122,7 @@ const BackgroundMapValue& Background::get_table_value(const std::string& key) co
//(2) Executes the script
//(3) Sleep (configurable)
void Background::run() {
ceph_pthread_setname("lua_background");
const DoutPrefixProvider* const dpp = &dp;
lua_state_guard lguard(cct->_conf->rgw_lua_max_memory_per_state, dpp);
auto L = lguard.get();

View File

@ -239,6 +239,7 @@ class ActiveRateLimiter : public DoutPrefix {
std::atomic_uint8_t current_active = 0;
std::shared_ptr<RateLimiter> ratelimit[2];
void replace_active() {
ceph_pthread_setname("ratelimit_gc");
using namespace std::chrono_literals;
std::unique_lock<std::mutex> lk(cv_m);
while (!stopped) {
@ -286,8 +287,5 @@ class ActiveRateLimiter : public DoutPrefix {
void start() {
ldpp_dout(this, 20) << "starting ratelimit_gc thread" << dendl;
runner = std::thread(&ActiveRateLimiter::replace_active, this);
if (const auto rc = ceph_pthread_setname(runner.native_handle(), "ratelimit_gc"); rc != 0) {
ldpp_dout(this, 1) << "ERROR: failed to set ratelimit_gc thread name. error: " << rc << dendl;
}
}
};