diff options
author | Samy Lanka <samy.lanka@gmail.com> | 2018-04-06 15:25:22 -0400 |
---|---|---|
committer | Samy Lanka <samy.lanka@gmail.com> | 2018-04-11 16:17:26 -0400 |
commit | d91bc3cde8d453919fe00a6bd89357d41e79bb19 (patch) | |
tree | 66884d34e3ec715b5a9fe8fa1925add02abc3c95 /buildscripts/gdb | |
parent | fff261ac550155065fce4b7b1529061f18980599 (diff) | |
download | mongo-d91bc3cde8d453919fe00a6bd89357d41e79bb19.tar.gz |
SERVER-33987 add thread name to hang analyzer output
Diffstat (limited to 'buildscripts/gdb')
-rw-r--r-- | buildscripts/gdb/mongo.py | 27 | ||||
-rw-r--r-- | buildscripts/gdb/mongo_lock.py | 60 |
2 files changed, 44 insertions, 43 deletions
diff --git a/buildscripts/gdb/mongo.py b/buildscripts/gdb/mongo.py index 0d7bb626a40..ea3a6baf129 100644 --- a/buildscripts/gdb/mongo.py +++ b/buildscripts/gdb/mongo.py @@ -36,6 +36,19 @@ def get_thread_id(): raise ValueError("Failed to find thread id in {}".format(thread_info)) +def get_current_thread_name(): + """Returns the name of the current GDB thread""" + fallback_name = '"%s"' % (gdb.selected_thread().name or '') + try: + # This goes through the pretty printer for StringData which adds "" around the name. + name = str(gdb.parse_and_eval("mongo::for_debuggers::threadName")) + if name == '""': + return fallback_name + return name + except gdb.error: + return fallback_name + + ################################################################################################### # # Commands @@ -163,18 +176,6 @@ class MongoDBUniqueStack(gdb.Command): if current_thread and current_thread.is_valid(): current_thread.switch() - @staticmethod - def _get_current_thread_name(): - """Return the current thread name.""" - fallback_name = '"%s"' % (gdb.selected_thread().name or '') - try: - # This goes through the pretty printer for StringData which adds "" around the name. - name = str(gdb.parse_and_eval("mongo::for_debuggers::threadName")) - if name == '""': - return fallback_name - return name - except gdb.error: - return fallback_name def _process_thread_stack(self, arg, stacks, thread): """Process the thread stack.""" @@ -182,7 +183,7 @@ class MongoDBUniqueStack(gdb.Command): thread_info['pthread'] = get_thread_id() thread_info['gdb_thread_num'] = thread.num thread_info['lwpid'] = thread.ptid[1] - thread_info['name'] = self._get_current_thread_name() + thread_info['name'] = get_current_thread_name() if sys.platform.startswith("linux"): header_format = "Thread {gdb_thread_num}: {name} (Thread 0x{pthread:x} (LWP {lwpid}))" diff --git a/buildscripts/gdb/mongo_lock.py b/buildscripts/gdb/mongo_lock.py index c1d6e785fe0..a183f44809d 100644 --- a/buildscripts/gdb/mongo_lock.py +++ b/buildscripts/gdb/mongo_lock.py @@ -18,10 +18,11 @@ if sys.version_info[0] >= 3: class Thread(object): """Thread class.""" - def __init__(self, thread_id, lwpid): + def __init__(self, thread_id, lwpid, thread_name): """Initialize Thread.""" self.thread_id = thread_id self.lwpid = lwpid + self.name = thread_name def __eq__(self, other): if isinstance(other, Thread): @@ -32,7 +33,7 @@ class Thread(object): return not self == other def __str__(self): - return "Thread 0x{:012x} (LWP {})".format(self.thread_id, self.lwpid) + return "{} (Thread 0x{:012x} (LWP {}))".format(self.name, self.thread_id, self.lwpid) def key(self): """Return thread key.""" @@ -190,15 +191,15 @@ class Graph(object): if node not in nodes_visited: cycle_path = self.depth_first_search(node, nodes_visited) if cycle_path: - return cycle_path + return [str(self.nodes[node_key]['node']) for node_key in cycle_path] return None -def find_lwpid(thread_dict, search_thread_id): - """Find lwpid.""" - for (lwpid, thread_id) in thread_dict.items(): - if thread_id == search_thread_id: - return lwpid +def find_thread(thread_dict, search_thread_id): + """Find thread.""" + for (lwpid, thread) in thread_dict.items(): + if thread.thread_id == search_thread_id: + return thread return None @@ -245,27 +246,26 @@ def find_mutex_holder(graph, thread_dict, show): mutex_this, _ = gdb.lookup_symbol("this", frame.block()) mutex_value = mutex_this.value(frame) # The mutex holder is a LWPID - mutex_holder = int(mutex_value["_M_mutex"]["__data"]["__owner"]) + mutex_holder_lwpid = int(mutex_value["_M_mutex"]["__data"]["__owner"]) + # At time thread_dict was initialized, the mutex holder may not have been found. # Use the thread LWP as a substitute for showing output or generating the graph. - if mutex_holder not in thread_dict: + if mutex_holder_lwpid not in thread_dict: print("Warning: Mutex at {} held by thread with LWP {}" " not found in thread_dict. Using LWP to track thread.".format( - mutex_value, mutex_holder)) - mutex_holder_id = mutex_holder + mutex_value, mutex_holder_lwpid)) + mutex_holder = Thread(mutex_holder_lwpid, mutex_holder_lwpid, '"[unknown]"') else: - mutex_holder_id = thread_dict[mutex_holder] + mutex_holder = thread_dict[mutex_holder_lwpid] (_, mutex_waiter_lwpid, _) = gdb.selected_thread().ptid - mutex_waiter_id = thread_dict[mutex_waiter_lwpid] + mutex_waiter = thread_dict[mutex_waiter_lwpid] if show: - print("Mutex at {} held by thread 0x{:x} (LWP {})" - " waited on by thread 0x{:x} (LWP {})".format( - mutex_value, mutex_holder_id, mutex_holder, mutex_waiter_id, mutex_waiter_lwpid)) + print("Mutex at {} held by {} waited on by {}".format(mutex_value, mutex_holder, + mutex_waiter)) if graph: - graph.add_edge( - Thread(mutex_waiter_id, mutex_waiter_lwpid), Lock(long(mutex_value), "Mutex")) - graph.add_edge(Lock(long(mutex_value), "Mutex"), Thread(mutex_holder_id, mutex_holder)) + graph.add_edge(mutex_waiter, Lock(long(mutex_value), "Mutex")) + graph.add_edge(Lock(long(mutex_value), "Mutex"), mutex_holder) def find_lock_manager_holders(graph, thread_dict, show): @@ -276,7 +276,8 @@ def find_lock_manager_holders(graph, thread_dict, show): frame.select() - (_, lwpid, _) = gdb.selected_thread().ptid + (_, lock_waiter_lwpid, _) = gdb.selected_thread().ptid + lock_waiter = thread_dict[lock_waiter_lwpid] locker_ptr_type = gdb.lookup_type("mongo::LockerImpl<false>").pointer() lock_head = gdb.parse_and_eval( @@ -289,16 +290,14 @@ def find_lock_manager_holders(graph, thread_dict, show): locker_ptr = lock_request["locker"] locker_ptr = locker_ptr.cast(locker_ptr_type) locker = locker_ptr.dereference() - lock_thread_id = int(locker["_threadId"]["_M_thread"]) - lock_thread_lwpid = find_lwpid(thread_dict, lock_thread_id) + lock_holder_id = int(locker["_threadId"]["_M_thread"]) + lock_holder = find_thread(thread_dict, lock_holder_id) if show: - print("MongoDB Lock at {} ({}) held by thread id 0x{:x} (LWP {})".format( - lock_head, lock_request["mode"], lock_thread_id, lock_thread_lwpid) + - " waited on by thread 0x{:x} (LWP {})".format(thread_dict[lwpid], lwpid)) + print("MongoDB Lock at {} ({}) held by {} waited on by {}".format(lock_head, + lock_request["mode"], lock_holder, lock_waiter)) if graph: - graph.add_edge(Thread(thread_dict[lwpid], lwpid), Lock(long(lock_head), "MongoDB lock")) - graph.add_edge( - Lock(long(lock_head), "MongoDB lock"), Thread(lock_thread_id, lock_thread_lwpid)) + graph.add_edge(lock_waiter, Lock(long(lock_head), "MongoDB lock")) + graph.add_edge(Lock(long(lock_head), "MongoDB lock"), lock_holder) lock_request_ptr = lock_request["next"] @@ -326,11 +325,12 @@ def get_threads_info(): # PTID is a tuple: Process ID (PID), Lightweight Process ID (LWPID), Thread ID (TID) (_, lwpid, _) = thread.ptid thread_num = thread.num + thread_name = get_current_thread_name() # pylint: disable=undefined-variable thread_id = get_thread_id() # pylint: disable=undefined-variable if not thread_id: print("Unable to retrieve thread_info for thread %d" % thread_num) continue - thread_dict[lwpid] = thread_id + thread_dict[lwpid] = Thread(thread_id, lwpid, thread_name) except gdb.error as err: print("Ignoring GDB error '%s' in get_threads_info" % str(err)) |