From 15edd69ddf649ebf7ecab3fa72bc5dea263c0154 Mon Sep 17 00:00:00 2001
From: Vladislav Vaintroub <wlad@mariadb.com>
Date: Tue, 11 Oct 2022 00:07:38 +0200
Subject: [PATCH] MDEV-27943 Reduce overhead of attaching THD to OS thread, in
 threadpool

Avoid relatively expensive THD::store_globals() for every query in the
threadpool. Use a lighter version instead, that only resets some thread
local storage variables(THD, mysys, PSI), avoids some calculationms
and caches syscall gettid (Linux only) in a thread_local variable.

Also simplify Worker_context use, with RAII.
---
 sql/threadpool_common.cc | 54 ++++++++++++++++++++++++++++++++++------
 1 file changed, 46 insertions(+), 8 deletions(-)

diff --git a/sql/threadpool_common.cc b/sql/threadpool_common.cc
index 965432357be..78f9eaf8792 100644
--- a/sql/threadpool_common.cc
+++ b/sql/threadpool_common.cc
@@ -92,13 +92,13 @@ struct Worker_thread_context
   PSI_thread *psi_thread;
   st_my_thread_var* mysys_var;
 
-  void save()
+  Worker_thread_context()
   {
     psi_thread= PSI_CALL_get_thread();
     mysys_var= my_thread_var;
   }
 
-  void restore()
+  ~Worker_thread_context()
   {
     PSI_CALL_set_thread(psi_thread);
     set_mysys_var(mysys_var);
@@ -142,6 +142,44 @@ static inline void set_thd_idle(THD *thd)
 #endif
 }
 
+/*
+  Per OS thread info (ID and pthread_self)
+  stored as TLS, because of syscall overhead
+  (on Linux)
+*/
+struct OS_thread_info
+{
+  pthread_t self;
+  ssize_t stack_size;
+  uint32_t thread_id;
+
+  inline bool initialized() { return stack_size != 0; }
+
+  void init(ssize_t ssize)
+  {
+#if _WIN32
+   self= thread_id= GetCurrentThreadId();
+#else
+#ifdef __NR_gettid
+    thread_id= (uint32) syscall(__NR_gettid);
+#else
+    thread_id= 0;
+#endif
+    self= pthread_self();
+#endif
+    stack_size= ssize;
+  }
+};
+static thread_local OS_thread_info os_thread_info;
+
+static const OS_thread_info *get_os_thread_info()
+{
+  auto *res= &os_thread_info;
+  if (!res->initialized())
+    res->init((ssize_t) (my_thread_stack_size * STACK_DIRECTION));
+  return res;
+}
+
 /*
   Attach/associate the connection with the OS thread,
 */
@@ -154,7 +192,12 @@ static void thread_attach(THD* thd)
 #endif /* WITH_WSREP */
   set_mysys_var(thd->mysys_var);
   thd->thread_stack=(char*)&thd;
-  thd->store_globals();
+  set_current_thd(thd);
+  auto tinfo= get_os_thread_info();
+  thd->real_id= tinfo->self;
+  thd->os_thread_id= tinfo->thread_id;
+  DBUG_ASSERT(thd->mysys_var == my_thread_var);
+  thd->mysys_var->stack_ends_here= thd->thread_stack + tinfo->stack_size;
   PSI_CALL_set_thread(thd->get_psi());
   mysql_socket_set_thread_owner(thd->net.vio->mysql_socket);
 }
@@ -179,7 +222,6 @@ void tp_callback(TP_connection *c)
   DBUG_ASSERT(c);
 
   Worker_thread_context worker_context;
-  worker_context.save();
 
   THD *thd= c->thd;
 
@@ -212,7 +254,6 @@ retry:
           thd->async_state.m_state = thd_async_state::enum_async_state::RESUMED;
           goto retry;
         }
-        worker_context.restore();
         return;
       case DISPATCH_COMMAND_CLOSE_CONNECTION:
         /* QUIT or an error occurred. */
@@ -231,8 +272,6 @@ retry:
   c->state= TP_STATE_IDLE;
   if (c->start_io())
     goto error;
-
-  worker_context.restore();
   return;
 
 error:
@@ -242,7 +281,6 @@ error:
     threadpool_remove_connection(thd);
   }
   delete c;
-  worker_context.restore();
 }