Commit 5bd05164 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-32537 Name threads to improve debugging experience and diagnostics.

Use SetThreadDescription/pthread_setname_np to give threads a name.
parent 584fc85e
......@@ -1624,6 +1624,12 @@ typedef void (*set_thread_os_id_v1_t)(struct PSI_thread *thread);
*/
typedef struct PSI_thread* (*get_thread_v1_t)(void);
/**
Get name of the thread, according to the thread class.
The name is returns without the thread/subsystem prefix.
*/
typedef const char* (*get_thread_class_name_v1_t)(void);
/**
Assign a user name to the instrumented thread.
@param user the user name
......@@ -2538,6 +2544,8 @@ struct PSI_v1
set_thread_os_id_v1_t set_thread_os_id;
/** @sa get_thread_v1_t. */
get_thread_v1_t get_thread;
/** @sa get_thread_name_v1_t. */
get_thread_class_name_v1_t get_thread_class_name;
/** @sa set_thread_user_v1_t. */
set_thread_user_v1_t set_thread_user;
/** @sa set_thread_account_v1_t. */
......
......@@ -449,6 +449,7 @@ typedef void (*set_thread_id_v1_t)(struct PSI_thread *thread,
ulonglong id);
typedef void (*set_thread_os_id_v1_t)(struct PSI_thread *thread);
typedef struct PSI_thread* (*get_thread_v1_t)(void);
typedef const char* (*get_thread_class_name_v1_t)(void);
typedef void (*set_thread_user_v1_t)(const char *user, int user_len);
typedef void (*set_thread_account_v1_t)(const char *user, int user_len,
const char *host, int host_len);
......@@ -725,6 +726,7 @@ struct PSI_v1
set_thread_THD_v1_t set_thread_THD;
set_thread_os_id_v1_t set_thread_os_id;
get_thread_v1_t get_thread;
get_thread_class_name_v1_t get_thread_class_name;
set_thread_user_v1_t set_thread_user;
set_thread_account_v1_t set_thread_account;
set_thread_db_v1_t set_thread_db;
......
......@@ -80,6 +80,8 @@ void pfs_set_thread_os_id_v1(PSI_thread *thread);
PSI_thread*
pfs_get_thread_v1(void);
const char *pfs_get_thread_class_name_v1(void);
void pfs_set_thread_user_v1(const char *user, int user_len);
void pfs_set_thread_account_v1(const char *user, int user_len,
......
......@@ -46,7 +46,7 @@ SET(MYSYS_SOURCES array.c charset-def.c charset.c my_default.c
my_rdtsc.c psi_noop.c
my_atomic_writes.c my_cpu.c my_likely.c my_largepage.c
file_logger.c my_dlerror.c crc32/crc32c.cc
my_timezone.cc)
my_timezone.cc my_thread_name.cc)
IF (WIN32)
SET (MYSYS_SOURCES ${MYSYS_SOURCES}
......
......@@ -172,35 +172,6 @@ my_bool my_thread_global_init(void)
return 0;
}
#ifdef _WIN32
#define MAX_THREAD_NAME 256
#elif defined(__linux__)
#define MAX_THREAD_NAME 16
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
#endif
void my_thread_set_name(const char *name)
{
#ifdef _WIN32
wchar_t wname[MAX_THREAD_NAME];
wname[0]= 0;
MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, MAX_THREAD_NAME);
SetThreadDescription(GetCurrentThread(), wname);
#elif defined __linux__
char shortname[MAX_THREAD_NAME];
snprintf(shortname, MAX_THREAD_NAME, "%s", name);
pthread_setname_np(pthread_self(), shortname);
#elif defined __NetBSD__
pthread_setname_np(pthread_self(), "%s", (void *) name);
#elif defined __FreeBSD__ || defined __OpenBSD__
pthread_set_name_np(pthread_self(), name);
#elif defined __APPLE__
pthread_setname_np(name);
#else
(void) name;
#endif
}
/**
End the mysys thread system. Called when ending the last thread
......
/* Copyright 2024, MariaDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA */
#include <my_global.h>
#include <my_pthread.h>
#include <my_sys.h>
#include "mysql/psi/psi.h"
#include <stdio.h>
#ifdef _WIN32
#define MAX_THREAD_NAME 256
typedef HRESULT (*func_SetThreadDescription)(HANDLE,PCWSTR);
#elif defined(__linux__)
#define MAX_THREAD_NAME 16
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h>
#endif
#if defined(HAVE_PSI_THREAD_INTERFACE) && !defined DBUG_OFF
/**
Check that the name is consistent with PSI.
Require that the name matches the last part of PSI's class name
(e.g. "thread/sql/main" -> "main").
We drop the namespace prefix, because these thread names are
truncated to 15 characters on Linux, and something like "innodb/" would
already take up about half of that.
*/
static void dbug_verify_thread_name(const char *name)
{
const char *psi_name= NULL;
const char *thread_class_name= PSI_THREAD_CALL(get_thread_class_name)();
if (thread_class_name)
{
/* Remove the path prefix */
const char *last_part= strrchr(thread_class_name, '/');
if (last_part)
psi_name= last_part + 1;
else
psi_name= thread_class_name;
}
if (psi_name && strcmp(psi_name, name))
{
fprintf(stderr, "my_thread_set_name() mismatch: PSI name '%s' != '%s'\n",
psi_name, name);
abort();
}
}
#else
#define dbug_verify_thread_name(name) do {} while (0)
#endif
/* Set current thread name for debugger/profiler and similar tools. */
extern "C" void my_thread_set_name(const char *name)
{
dbug_verify_thread_name(name);
#ifdef _WIN32
/*
SetThreadDescription might not be there on older Windows versions.
Load it dynamically.
*/
static func_SetThreadDescription my_SetThreadDescription=
(func_SetThreadDescription) GetProcAddress(GetModuleHandle("kernel32"),
"SetThreadDescription");
if (!my_SetThreadDescription)
return;
wchar_t wname[MAX_THREAD_NAME];
wname[0]= 0;
MultiByteToWideChar(CP_UTF8, 0, name, -1, wname, MAX_THREAD_NAME);
my_SetThreadDescription(GetCurrentThread(), wname);
#elif defined __linux__
char shortname[MAX_THREAD_NAME];
snprintf(shortname, MAX_THREAD_NAME, "%s", name);
pthread_setname_np(pthread_self(), shortname);
#elif defined __NetBSD__
pthread_setname_np(pthread_self(), "%s", (void *) name);
#elif defined __FreeBSD__ || defined __OpenBSD__
pthread_set_name_np(pthread_self(), name);
#elif defined __APPLE__
pthread_setname_np(name);
#else
(void) name;
#endif
}
......@@ -228,6 +228,11 @@ get_thread_noop(void NNN)
return NULL;
}
static const char* get_thread_class_name_noop(void)
{
return NULL;
}
static void set_thread_user_noop(const char *user NNN, int user_len NNN)
{
return;
......@@ -938,6 +943,7 @@ static PSI PSI_noop=
set_thread_THD_noop,
set_thread_os_id_noop,
get_thread_noop,
get_thread_class_name_noop,
set_thread_user_noop,
set_thread_user_host_noop,
set_thread_db_noop,
......
......@@ -3219,7 +3219,7 @@ pthread_handler_t signal_hand(void *)
sigset_t set;
int sig;
my_thread_init(); // Init new thread
my_thread_set_name("signal_hand");
my_thread_set_name("signal_handler");
signal_thread_in_use= 1;
if (test_flags & TEST_SIGINT)
......
......@@ -1226,7 +1226,7 @@ handle_rpl_parallel_thread(void *arg)
struct rpl_parallel_thread *rpt= (struct rpl_parallel_thread *)arg;
my_thread_init();
my_thread_set_name("rpl_parallel");
my_thread_set_name("rpl_parallel_thread");
thd = new THD(next_thread_id());
thd->thread_stack = (char*)&thd;
server_threads.insert(thd);
......
......@@ -33,7 +33,7 @@ pthread_handler_t ack_receive_handler(void *arg)
Ack_receiver *recv= reinterpret_cast<Ack_receiver *>(arg);
my_thread_init();
my_thread_set_name("ack_receive");
my_thread_set_name("Ack_receiver");
recv->run();
my_thread_end();
......
......@@ -75,7 +75,7 @@ pthread_handler_t handle_manager(void *arg __attribute__((unused)))
struct timespec abstime;
bool reset_flush_time = TRUE;
my_thread_init();
my_thread_set_name("handle_manager");
my_thread_set_name("manager");
DBUG_ENTER("handle_manager");
pthread_detach_this_thread();
......
......@@ -1534,7 +1534,7 @@ static void *worker_main(void *param)
worker_thread_t this_thread;
pthread_detach_this_thread();
my_thread_init();
my_thread_set_name("connection_worker");
my_thread_set_name("worker_thread");
DBUG_ENTER("worker_main");
......
......@@ -577,7 +577,7 @@ pthread_handler_t ma_checkpoint_background(void *arg)
PAGECACHE_FILE *UNINIT_VAR(kfile); /**< index file currently being flushed */
my_thread_init();
my_thread_set_name("ma_checkpoint_background");
my_thread_set_name("checkpoint_background");
DBUG_PRINT("info",("Maria background checkpoint thread starts"));
DBUG_ASSERT(interval > 0);
......
......@@ -2325,6 +2325,14 @@ pfs_get_thread_v1(void)
return reinterpret_cast<PSI_thread*> (pfs);
}
const char *pfs_get_thread_class_name_v1(void)
{
PFS_thread *pfs= my_thread_get_THR_PFS();
if (!pfs)
return NULL;
return pfs->m_class->m_name;
}
/**
Implementation of the thread instrumentation interface.
@sa PSI_v1::set_thread_user.
......@@ -7040,6 +7048,7 @@ PSI_v1 PFS_v1=
pfs_set_thread_THD_v1,
pfs_set_thread_os_id_v1,
pfs_get_thread_v1,
pfs_get_thread_class_name_v1,
pfs_set_thread_user_v1,
pfs_set_thread_account_v1,
pfs_set_thread_db_v1,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment