From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id GPIXH7YX0mAtYAAAWB0awg (envelope-from ) for ; Tue, 22 Jun 2021 13:02:46 -0400 Received: by simark.ca (Postfix, from userid 112) id 7B5C81F1F2; Tue, 22 Jun 2021 13:02:46 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.1 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,MAILING_LIST_MULTI,URIBL_BLOCKED autolearn=unavailable autolearn_force=no version=3.4.2 Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 1C4031E54D for ; Tue, 22 Jun 2021 13:02:46 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D0C8F393D033 for ; Tue, 22 Jun 2021 17:02:45 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D0C8F393D033 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1624381365; bh=2UVSh7D61aiXrZtt3taf6JLqnz2T6d3f6tytWpJqaFE=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=nYm7QipVBgdzUWgZYmB/Zo6IfQFYpCybmogr0LIxLfuasITz9OFej37Mf0j3xos3q szsESyoILtK1COWZ9gyI47ut4PVcw5nhZvOniZocUcdiVEA8MlWg5Zq63EYBs3h0iz O6AciaP8QoxauKYL3aOek5BBwtKk/3j7C1g62g0I= Received: from barracuda.ebox.ca (barracuda.ebox.ca [96.127.255.19]) by sourceware.org (Postfix) with ESMTPS id 392713857C40 for ; Tue, 22 Jun 2021 16:59:08 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 392713857C40 X-ASG-Debug-ID: 1624381147-0c856e67e2169e610001-fS2M51 Received: from smtp.ebox.ca (smtp.ebox.ca [96.127.255.82]) by barracuda.ebox.ca with ESMTP id GBAsWY9gYCzJ4iHl (version=TLSv1 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 22 Jun 2021 12:59:07 -0400 (EDT) X-Barracuda-Envelope-From: simon.marchi@polymtl.ca X-Barracuda-RBL-Trusted-Forwarder: 96.127.255.82 Received: from simark.localdomain (192-222-157-6.qc.cable.ebox.net [192.222.157.6]) by smtp.ebox.ca (Postfix) with ESMTP id 0D99D441D65; Tue, 22 Jun 2021 12:59:07 -0400 (EDT) X-Barracuda-RBL-IP: 192.222.157.6 X-Barracuda-Effective-Source-IP: 192-222-157-6.qc.cable.ebox.net[192.222.157.6] X-Barracuda-Apparent-Source-IP: 192.222.157.6 To: gdb-patches@sourceware.org Subject: [PATCH 10/11] gdb: maintain ptid -> thread map, optimize find_thread_ptid Date: Tue, 22 Jun 2021 12:57:03 -0400 X-ASG-Orig-Subj: [PATCH 10/11] gdb: maintain ptid -> thread map, optimize find_thread_ptid Message-Id: <20210622165704.2404007-11-simon.marchi@polymtl.ca> X-Mailer: git-send-email 2.32.0 In-Reply-To: <20210622165704.2404007-1-simon.marchi@polymtl.ca> References: <20210622165704.2404007-1-simon.marchi@polymtl.ca> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Barracuda-Connect: smtp.ebox.ca[96.127.255.82] X-Barracuda-Start-Time: 1624381147 X-Barracuda-Encrypted: DHE-RSA-AES256-SHA X-Barracuda-URL: https://96.127.255.19:443/cgi-mod/mark.cgi X-Barracuda-BRTS-Status: 1 X-Virus-Scanned: by bsmtpd at ebox.ca X-Barracuda-Scan-Msg-Size: 7164 X-Barracuda-Spam-Score: 0.50 X-Barracuda-Spam-Status: No, SCORE=0.50 using global scores of TAG_LEVEL=1000.0 QUARANTINE_LEVEL=1000.0 KILL_LEVEL=8.0 tests=BSF_RULE7568M X-Barracuda-Spam-Report: Code version 3.2, rules version 3.2.3.90826 Rule breakdown below pts rule name description ---- ---------------------- -------------------------------------------------- 0.50 BSF_RULE7568M Custom Rule 7568M X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , From: Simon Marchi via Gdb-patches Reply-To: Simon Marchi Errors-To: gdb-patches-bounces+public-inbox=simark.ca@sourceware.org Sender: "Gdb-patches" When debugging a large number of threads (thousands), looking up a thread by ptid_t using the inferior::thread_list linked list can add up. Add inferior::thread_map, an std::unordered_map indexed by ptid_t, and change the find_thread_ptid function to look up a thread using std::unordered_map::find, instead of iterating on all of the inferior's threads. This should make it faster to look up a thread from its ptid. gdb/ChangeLog: yyyy-mm-dd Simon Marchi Pedro Alves * gdbarch-selftests.c (register_to_value_test): Update the mock inferior's thread map as well. * inferior.c (inferior::clear_thread_list): Clear the thread map. * inferior.h: Include . (class inferior::thread_map): New field. * regcache.c (cooked_read_test): Update the mock inferior's thread map as well. * thread.c (set_thread_exited): Remove the thread from the thread map. (new_thread): Insert the thread in the ptid map. (find_thread_ptid): Lookup up the thread in the ptid map. (thread_change_ptid): Update ptid map entry. Change-Id: I3a8da0a839e18dee5bb98b8b7dbeb7f3dfa8ae1c --- gdb/inferior.c | 1 + gdb/inferior.h | 6 ++++++ gdb/infrun.c | 10 ++++++++++ gdb/regcache.c | 5 +++++ gdb/scoped-mock-context.h | 1 + gdb/thread.c | 29 ++++++++++++++++++++++++----- 6 files changed, 47 insertions(+), 5 deletions(-) diff --git a/gdb/inferior.c b/gdb/inferior.c index e07a8f88422a..8705c0f7f4b7 100644 --- a/gdb/inferior.c +++ b/gdb/inferior.c @@ -184,6 +184,7 @@ inferior::clear_thread_list (bool silent) if (thr->deletable ()) delete thr; }); + ptid_thread_map.clear (); } void diff --git a/gdb/inferior.h b/gdb/inferior.h index 2bfe29afed3f..6662a3bde463 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -63,6 +63,8 @@ struct thread_info; #include "process-stratum-target.h" #include "displaced-stepping.h" +#include + struct infcall_suspend_state; struct infcall_control_state; @@ -391,6 +393,10 @@ class inferior : public refcounted_object, /* This inferior's thread list, sorted by creation order. */ intrusive_list thread_list; + /* A map of ptid_t to thread_info*, for average O(1) ptid_t lookup. + Exited threads do not appear in the map. */ + std::unordered_map ptid_thread_map; + /* Returns a range adapter covering the inferior's threads, including exited threads. Used like this: diff --git a/gdb/infrun.c b/gdb/infrun.c index 80834fed1e3b..1f290b7fa7a6 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -9421,8 +9421,13 @@ infrun_thread_ptid_changed () target1.mock_inferior.pid = old_ptid.pid (); target1.mock_thread.ptid = old_ptid; + target1.mock_inferior.ptid_thread_map.clear (); + target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread; + target2.mock_inferior.pid = old_ptid.pid (); target2.mock_thread.ptid = old_ptid; + target2.mock_inferior.ptid_thread_map.clear (); + target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread; auto restore_inferior_ptid = make_scoped_restore (&inferior_ptid, old_ptid); set_current_inferior (&target1.mock_inferior); @@ -9445,8 +9450,13 @@ infrun_thread_ptid_changed () target1.mock_inferior.pid = old_ptid.pid (); target1.mock_thread.ptid = old_ptid; + target1.mock_inferior.ptid_thread_map.clear (); + target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread; + target2.mock_inferior.pid = old_ptid.pid (); target2.mock_thread.ptid = old_ptid; + target2.mock_inferior.ptid_thread_map.clear (); + target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread; auto restore_inferior_ptid = make_scoped_restore (&inferior_ptid, old_ptid); set_current_inferior (&target2.mock_inferior); diff --git a/gdb/regcache.c b/gdb/regcache.c index 21fa25d31553..ac44d714ddc1 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -2044,8 +2044,13 @@ regcache_thread_ptid_changed () target1.mock_inferior.pid = old_ptid.pid (); target1.mock_thread.ptid = old_ptid; + target1.mock_inferior.ptid_thread_map.clear (); + target1.mock_inferior.ptid_thread_map[old_ptid] = &target1.mock_thread; + target2.mock_inferior.pid = old_ptid.pid (); target2.mock_thread.ptid = old_ptid; + target2.mock_inferior.ptid_thread_map.clear (); + target2.mock_inferior.ptid_thread_map[old_ptid] = &target2.mock_thread; gdb_assert (regcaches.empty ()); diff --git a/gdb/scoped-mock-context.h b/gdb/scoped-mock-context.h index ba3b81ed12a5..48fdbacbb14f 100644 --- a/gdb/scoped-mock-context.h +++ b/gdb/scoped-mock-context.h @@ -51,6 +51,7 @@ struct scoped_mock_context inferior_list.push_back (mock_inferior); mock_inferior.thread_list.push_back (mock_thread); + mock_inferior.ptid_thread_map[mock_ptid] = &mock_thread; mock_inferior.gdbarch = gdbarch; mock_inferior.aspace = mock_pspace.aspace; mock_inferior.pspace = &mock_pspace; diff --git a/gdb/thread.c b/gdb/thread.c index 26974e1b8cbc..0d5ec48691a0 100644 --- a/gdb/thread.c +++ b/gdb/thread.c @@ -199,6 +199,14 @@ set_thread_exited (thread_info *tp, bool silent) /* Clear breakpoints, etc. associated with this thread. */ clear_thread_inferior_resources (tp); + + /* Remove from the ptid_t map. We don't want for + find_thread_ptid to find exited threads. Also, the target + may reuse the ptid for a new thread, and there can only be + one value per key; adding a new thread with the same ptid_t + would overwrite the exited thread's ptid entry. */ + size_t nr_deleted = tp->inf->ptid_thread_map.erase (tp->ptid); + gdb_assert (nr_deleted == 1); } } @@ -221,6 +229,11 @@ new_thread (struct inferior *inf, ptid_t ptid) inf->thread_list.push_back (*tp); + /* A thread with this ptid should not exist in the map yet. */ + gdb_assert (inf->ptid_thread_map.find (ptid) == inf->ptid_thread_map.end ()); + + inf->ptid_thread_map[ptid] = tp; + return tp; } @@ -477,11 +490,11 @@ find_thread_ptid (inferior *inf, ptid_t ptid) { gdb_assert (inf != nullptr); - for (thread_info *tp : inf->non_exited_threads ()) - if (tp->ptid == ptid) - return tp; - - return NULL; + auto it = inf->ptid_thread_map.find (ptid); + if (it != inf->ptid_thread_map.end ()) + return it->second; + else + return nullptr; } /* See gdbthread.h. */ @@ -751,7 +764,13 @@ thread_change_ptid (process_stratum_target *targ, inf->pid = new_ptid.pid (); tp = find_thread_ptid (inf, old_ptid); + gdb_assert (tp != nullptr); + + int num_erased = inf->ptid_thread_map.erase (old_ptid); + gdb_assert (num_erased == 1); + tp->ptid = new_ptid; + inf->ptid_thread_map[new_ptid] = tp; gdb::observers::thread_ptid_changed.notify (targ, old_ptid, new_ptid); } -- 2.32.0